char * lwcollection_summary(LWCOLLECTION *col, int offset) { size_t size = 128; char *result; char *tmp; int i; char *pad=""; LWDEBUG(2, "lwcollection_summary called"); result = (char *)lwalloc(size); sprintf(result, "%*.s%s[%s] with %d elements\n", offset, pad, lwgeom_typename(TYPE_GETTYPE(col->type)), lwgeom_typeflags(col->type), col->ngeoms); for (i=0; i<col->ngeoms; i++) { tmp = lwgeom_summary(col->geoms[i], offset+2); size += strlen(tmp)+1; result = lwrealloc(result, size); LWDEBUGF(4, "Reallocated %d bytes for result", size); strcat(result, tmp); lwfree(tmp); } LWDEBUG(3, "lwcollection_summary returning"); return result; }
/* * Add a point into a pointarray. Only adds as many dimensions as the * pointarray supports. */ int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, int where) { size_t point_size = ptarray_point_size(pa); LWDEBUGF(5,"pa = %p; p = %p; where = %d", pa, p, where); LWDEBUGF(5,"pa->npoints = %d; pa->maxpoints = %d", pa->npoints, pa->maxpoints); if ( FLAGS_GET_READONLY(pa->flags) ) { lwerror("ptarray_insert_point: called on read-only point array"); return LW_FAILURE; } /* Error on invalid offset value */ if ( where > pa->npoints || where < 0) { lwerror("ptarray_insert_point: offset out of range (%d)", where); return LW_FAILURE; } /* If we have no storage, let's allocate some */ if( pa->maxpoints == 0 || ! pa->serialized_pointlist ) { pa->maxpoints = 32; pa->npoints = 0; pa->serialized_pointlist = lwalloc(ptarray_point_size(pa) * pa->maxpoints); } /* Error out if we have a bad situation */ if ( pa->npoints > pa->maxpoints ) { lwerror("npoints (%d) is greated than maxpoints (%d)", pa->npoints, pa->maxpoints); return LW_FAILURE; } /* Check if we have enough storage, add more if necessary */ if( pa->npoints == pa->maxpoints ) { pa->maxpoints *= 2; pa->serialized_pointlist = lwrealloc(pa->serialized_pointlist, ptarray_point_size(pa) * pa->maxpoints); } /* Make space to insert the new point */ if( where < pa->npoints ) { size_t copy_size = point_size * (pa->npoints - where); memmove(getPoint_internal(pa, where+1), getPoint_internal(pa, where), copy_size); LWDEBUGF(5,"copying %d bytes to start vertex %d from start vertex %d", copy_size, where+1, where); } /* We have one more point */ ++pa->npoints; /* Copy the new point into the gap */ ptarray_set_point4d(pa, where, p); LWDEBUGF(5,"copying new point to start vertex %d", point_size, where); return LW_SUCCESS; }
/* * Add a LWTRIANGLE inside a tgeom * Copy geometries from LWTRIANGLE */ static TGEOM* tgeom_add_triangle(TGEOM *tgeom, LWTRIANGLE *triangle) { int i; assert(tgeom); assert(triangle); if ((tgeom->nfaces + 1) == INT_MAX) lwerror("tgeom_add_triangle: Unable to alloc more than %i faces", INT_MAX); /* Integrity checks on subgeom, dims and srid */ if (tgeom->type != TINTYPE) lwerror("tgeom_add_triangle: Unable to handle %s - %s type", tgeom->type, lwtype_name(tgeom->type)); if (FLAGS_NDIMS(tgeom->flags) != FLAGS_NDIMS(triangle->flags)) lwerror("tgeom_add_triangle: Mixed dimension"); if (tgeom->srid != triangle->srid && (tgeom->srid != 0 && triangle->srid != SRID_UNKNOWN)) lwerror("tgeom_add_triangle: Mixed srid. Tgeom: %i / Triangle: %i", tgeom->srid, triangle->srid); /* handle face array allocation */ if (tgeom->maxfaces == 0) { tgeom->faces = lwalloc(sizeof(TFACE*) * 2); tgeom->maxfaces = 2; } if ((tgeom->maxfaces - 1) == tgeom->nfaces) { tgeom->faces = lwrealloc(tgeom->faces, sizeof(TFACE*) * tgeom->maxfaces * 2); tgeom->maxfaces *= 2; } /* add an empty face */ tgeom->faces[tgeom->nfaces] = lwalloc(sizeof(TFACE)); tgeom->faces[tgeom->nfaces]->rings = NULL; tgeom->faces[tgeom->nfaces]->nrings = 0; tgeom->faces[tgeom->nfaces]->nedges = 0; tgeom->faces[tgeom->nfaces]->maxedges = 0; /* Compute edge on triangle */ for (i=1 ; i < triangle->points->npoints ; i++) { POINT4D p1, p2; getPoint4d_p(triangle->points, i-1, &p1); getPoint4d_p(triangle->points, i, &p2); tgeom_add_face_edge(tgeom, tgeom->nfaces, &p1, &p2); } tgeom->nfaces++; return tgeom; }
/** * Ensure the collection can hold up at least ngeoms */ void lwcollection_reserve(LWCOLLECTION *col, int ngeoms) { if ( ngeoms <= col->maxgeoms ) return; /* Allocate more space if we need it */ do { col->maxgeoms *= 2; } while ( col->maxgeoms < ngeoms ); col->geoms = lwrealloc(col->geoms, sizeof(LWGEOM*) * col->maxgeoms); }
static LWGEOM* lwcollection_split(const LWCOLLECTION* lwcoll_in, const LWGEOM* blade_in) { LWGEOM** split_vector=NULL; LWCOLLECTION* out; size_t split_vector_capacity; size_t split_vector_size=0; size_t i,j; split_vector_capacity=8; split_vector = lwalloc(split_vector_capacity * sizeof(LWGEOM*)); if ( ! split_vector ) { lwerror("Out of virtual memory"); return NULL; } for (i=0; i<lwcoll_in->ngeoms; ++i) { LWCOLLECTION* col; LWGEOM* split = lwgeom_split(lwcoll_in->geoms[i], blade_in); /* an exception should prevent this from ever returning NULL */ if ( ! split ) return NULL; col = lwgeom_as_lwcollection(split); /* Output, if any, will always be a collection */ assert(col); /* Reallocate split_vector if needed */ if ( split_vector_size + col->ngeoms > split_vector_capacity ) { /* NOTE: we could be smarter on reallocations here */ split_vector_capacity += col->ngeoms; split_vector = lwrealloc(split_vector, split_vector_capacity * sizeof(LWGEOM*)); if ( ! split_vector ) { lwerror("Out of virtual memory"); return NULL; } } for (j=0; j<col->ngeoms; ++j) { col->geoms[j]->srid = SRID_UNKNOWN; /* strip srid */ split_vector[split_vector_size++] = col->geoms[j]; } lwfree(col->geoms); lwfree(col); } /* Now split_vector has split_vector_size geometries */ out = lwcollection_construct(COLLECTIONTYPE, lwcoll_in->srid, NULL, split_vector_size, split_vector); return (LWGEOM*)out; }
int lwcurvepoly_add_ring(LWCURVEPOLY *poly, LWGEOM *ring) { int i; /* Can't do anything with NULLs */ if( ! poly || ! ring ) { LWDEBUG(4,"NULL inputs!!! quitting"); return LW_FAILURE; } /* Check that we're not working with garbage */ if ( poly->rings == NULL && (poly->nrings || poly->maxrings) ) { LWDEBUG(4,"mismatched nrings/maxrings"); lwerror("Curvepolygon is in inconsistent state. Null memory but non-zero collection counts."); } /* Check that we're adding an allowed ring type */ if ( ! ( ring->type == LINETYPE || ring->type == CIRCSTRINGTYPE || ring->type == COMPOUNDTYPE ) ) { LWDEBUGF(4,"got incorrect ring type: %s",lwtype_name(ring->type)); return LW_FAILURE; } /* In case this is a truly empty, make some initial space */ if ( poly->rings == NULL ) { poly->maxrings = 2; poly->nrings = 0; poly->rings = (LWGEOM **)lwalloc(poly->maxrings * sizeof(LWGEOM*)); } /* Allocate more space if we need it */ if ( poly->nrings == poly->maxrings ) { poly->maxrings *= 2; poly->rings = (LWGEOM **)lwrealloc(poly->rings, sizeof(LWGEOM*) * poly->maxrings); } /* Make sure we don't already have a reference to this geom */ for ( i = 0; i < poly->nrings; i++ ) { if ( poly->rings[i] == ring ) { LWDEBUGF(4, "Found duplicate geometry in collection %p == %p", poly->rings[i], ring); return LW_SUCCESS; } } /* Add the ring and increment the ring count */ poly->rings[poly->nrings] = (LWGEOM*)ring; poly->nrings++; return LW_SUCCESS; }
static LWGEOM* parse_geojson_polygon(json_object *geojson, bool *hasz, int *root_srid) { LWGEOM *geom; POINTARRAY **ppa; json_object* rings = NULL; int i = 0, j = 0; int ring = 0; rings = findMemberByName( geojson, "coordinates" ); if ( ! rings ) geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4); ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*)); if( json_type_array == json_object_get_type( rings ) ) { int nPoints; json_object* points = NULL; ppa[0] = ptarray_construct_empty(1, 0, 1); ring = json_object_array_length( rings ); points = json_object_array_get_idx( rings, 0 ); nPoints = json_object_array_length( points ); for (i=0; i < nPoints; i++ ) { json_object* coords = NULL; coords = json_object_array_get_idx( points, i ); parse_geojson_coord(coords, hasz, ppa[0]); } for(i = 1; i < ring; ++i) { int nPoints; ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa, sizeof(POINTARRAY*) * (i + 1)); ppa[i] = ptarray_construct_empty(1, 0, 1); points = json_object_array_get_idx( rings, i ); nPoints = json_object_array_length( points ); for (j=0; j < nPoints; j++ ) { json_object* coords = NULL; coords = json_object_array_get_idx( points, j ); parse_geojson_coord(coords, hasz, ppa[i]); } } } geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa); return geom; }
/** * If necessary, expand the stringbuffer_t internal buffer to accomodate the * specified additional size. */ static inline void stringbuffer_makeroom(stringbuffer_t *s, size_t size_to_add) { size_t current_size = (s->str_end - s->str_start); size_t capacity = s->capacity; size_t required_size = current_size + size_to_add; while (capacity < required_size) capacity *= 2; if ( capacity > s->capacity ) { s->str_start = lwrealloc(s->str_start, capacity); s->capacity = capacity; s->str_end = s->str_start + current_size; } }
/** * Add a ring to a polygon. Point array will be referenced, not copied. */ int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa) { if( ! poly || ! pa ) return LW_FAILURE; /* We have used up our storage, add some more. */ if( poly->nrings >= poly->maxrings ) { int new_maxrings = 2 * (poly->nrings + 1); poly->rings = lwrealloc(poly->rings, new_maxrings * sizeof(POINTARRAY*)); } /* Add the new ring entry. */ poly->rings[poly->nrings] = pa; poly->nrings++; return LW_SUCCESS; }
/** * If necessary, expand the bytebuffer_t internal buffer to accomodate the * specified additional size. */ static inline void bytebuffer_makeroom(bytebuffer_t *s, size_t size_to_add) { LWDEBUGF(2,"Entered bytebuffer_makeroom with space need of %d", size_to_add); size_t current_write_size = (s->writecursor - s->buf_start); size_t capacity = s->capacity; size_t required_size = current_write_size + size_to_add; LWDEBUGF(2,"capacity = %d and required size = %d",capacity ,required_size); while (capacity < required_size) capacity *= 2; if ( capacity > s->capacity ) { LWDEBUGF(4,"We need to realloc more memory. New capacity is %d", capacity); s->buf_start = lwrealloc(s->buf_start, capacity); s->capacity = capacity; s->writecursor = s->buf_start + current_write_size; s->readcursor = s->buf_start + (s->readcursor - s->buf_start); } return; }
static LWGEOM* parse_geojson_multipolygon(json_object *geojson, bool *hasz, int *root_srid) { LWGEOM *geom = NULL; int i, j, k; json_object* poObjPolys = NULL; if (!*root_srid) { geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0); } else { geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, -1, 1, 0); } poObjPolys = findMemberByName( geojson, "coordinates" ); if ( ! poObjPolys ) geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4); if( json_type_array == json_object_get_type( poObjPolys ) ) { const int nPolys = json_object_array_length( poObjPolys ); for(i = 0; i < nPolys; ++i) { POINTARRAY **ppa; json_object* poObjPoly = NULL; poObjPoly = json_object_array_get_idx( poObjPolys, i ); ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*)); if( json_type_array == json_object_get_type( poObjPoly ) ) { int nPoints; json_object* points = NULL; int ring = json_object_array_length( poObjPoly ); ppa[0] = ptarray_construct_empty(1, 0, 1); points = json_object_array_get_idx( poObjPoly, 0 ); nPoints = json_object_array_length( points ); for (j=0; j < nPoints; j++ ) { json_object* coords = NULL; coords = json_object_array_get_idx( points, j ); parse_geojson_coord(coords, hasz, ppa[0]); } for(j = 1; j < ring; ++j) { int nPoints; ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa, sizeof(POINTARRAY*) * (j + 1)); ppa[i] = ptarray_construct_empty(1, 0, 1); points = json_object_array_get_idx( poObjPoly, j ); nPoints = json_object_array_length( points ); for (k=0; k < nPoints; k++ ) { json_object* coords = NULL; coords = json_object_array_get_idx( points, k ); parse_geojson_coord(coords, hasz, ppa[i]); } } geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom, (LWPOLY*)lwpoly_construct(*root_srid, NULL, ring, ppa)); } } } return geom; }
/** * Takes a potentially heterogeneous collection and returns a homogeneous * collection consisting only of the specified type. */ LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type) { int i = 0; LWGEOM **geomlist; LWCOLLECTION *outcol; int geomlistsize = 16; int geomlistlen = 0; uint8_t outtype; if ( ! col ) return NULL; switch (type) { case POINTTYPE: outtype = MULTIPOINTTYPE; break; case LINETYPE: outtype = MULTILINETYPE; break; case POLYGONTYPE: outtype = MULTIPOLYGONTYPE; break; default: lwerror("Only POLYGON, LINESTRING and POINT are supported by lwcollection_extract. %s requested.", lwtype_name(type)); return NULL; } geomlist = lwalloc(sizeof(LWGEOM*) * geomlistsize); /* Process each sub-geometry */ for ( i = 0; i < col->ngeoms; i++ ) { int subtype = col->geoms[i]->type; /* Don't bother adding empty sub-geometries */ if ( lwgeom_is_empty(col->geoms[i]) ) { continue; } /* Copy our sub-types into the output list */ if ( subtype == type ) { /* We've over-run our buffer, double the memory segment */ if ( geomlistlen == geomlistsize ) { geomlistsize *= 2; geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize); } geomlist[geomlistlen] = lwgeom_clone(col->geoms[i]); geomlistlen++; } /* Recurse into sub-collections */ if ( lwtype_is_collection( subtype ) ) { int j = 0; LWCOLLECTION *tmpcol = lwcollection_extract((LWCOLLECTION*)col->geoms[i], type); for ( j = 0; j < tmpcol->ngeoms; j++ ) { /* We've over-run our buffer, double the memory segment */ if ( geomlistlen == geomlistsize ) { geomlistsize *= 2; geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize); } geomlist[geomlistlen] = tmpcol->geoms[j]; geomlistlen++; } lwfree(tmpcol); } } if ( geomlistlen > 0 ) { GBOX gbox; outcol = lwcollection_construct(outtype, col->srid, NULL, geomlistlen, geomlist); lwgeom_calculate_gbox((LWGEOM *) outcol, &gbox); outcol->bbox = gbox_copy(&gbox); } else { lwfree(geomlist); outcol = lwcollection_construct_empty(outtype, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags)); } return outcol; }
/* * Add a LWPOLY inside a tgeom * Copy geometries from LWPOLY */ static TGEOM* tgeom_add_polygon(TGEOM *tgeom, LWPOLY *poly) { int i; assert(tgeom); assert(poly); if ((tgeom->nfaces + 1) == INT_MAX) lwerror("tgeom_add_polygon: Unable to alloc more than %i faces", INT_MAX); /* Integrity checks on subgeom, dims and srid */ if (tgeom->type != POLYHEDRALSURFACETYPE) lwerror("tgeom_add_polygon: Unable to handle %s - %s type", tgeom->type, lwtype_name(tgeom->type)); if (FLAGS_NDIMS(tgeom->flags) != FLAGS_NDIMS(poly->flags)) lwerror("tgeom_add_polygon: Mixed dimension"); if (tgeom->srid != poly->srid && (tgeom->srid != 0 && poly->srid != SRID_UNKNOWN)) lwerror("tgeom_add_polygon: Mixed srid. Tgeom: %i / Polygon: %i", tgeom->srid, poly->srid); /* handle face array allocation */ if (tgeom->maxfaces == 0) { tgeom->faces = lwalloc(sizeof(TFACE*) * 2); tgeom->maxfaces = 2; } if ((tgeom->maxfaces - 1) == tgeom->nfaces) { tgeom->faces = lwrealloc(tgeom->faces, sizeof(TFACE*) * tgeom->maxfaces * 2); tgeom->maxfaces *= 2; } /* add an empty face */ tgeom->faces[tgeom->nfaces] = lwalloc(sizeof(TFACE)); tgeom->faces[tgeom->nfaces]->rings = NULL; tgeom->faces[tgeom->nfaces]->nrings = 0; tgeom->faces[tgeom->nfaces]->nedges = 0; tgeom->faces[tgeom->nfaces]->maxedges = 0; /* Compute edge on poly external ring */ for (i=1 ; i < poly->rings[0]->npoints ; i++) { POINT4D p1, p2; getPoint4d_p(poly->rings[0], i-1, &p1); getPoint4d_p(poly->rings[0], i, &p2); tgeom_add_face_edge(tgeom, tgeom->nfaces, &p1, &p2); } /* External ring is already handled by edges */ tgeom->faces[tgeom->nfaces]->nrings = poly->nrings - 1; /* handle rings array allocation */ if (tgeom->faces[tgeom->nfaces]->nrings >= 1) tgeom->faces[tgeom->nfaces]->rings = lwalloc(sizeof(POINTARRAY*) * tgeom->faces[tgeom->nfaces]->nrings); /* clone internal rings */ for (i=0 ; i < tgeom->faces[tgeom->nfaces]->nrings ; i++) tgeom->faces[tgeom->nfaces]->rings[i] = ptarray_clone_deep(poly->rings[i+1]); tgeom->nfaces++; return tgeom; }
/** * Parse KML Polygon */ static LWGEOM* parse_kml_polygon(xmlNodePtr xnode, bool *hasz) { int ring; xmlNodePtr xa, xb; POINTARRAY **ppa = NULL; for (xa = xnode->children ; xa != NULL ; xa = xa->next) { /* Polygon/outerBoundaryIs */ if (xa->type != XML_ELEMENT_NODE) continue; if (!is_kml_namespace(xa, false)) continue; if (strcmp((char *) xa->name, "outerBoundaryIs")) continue; for (xb = xa->children ; xb != NULL ; xb = xb->next) { if (xb->type != XML_ELEMENT_NODE) continue; if (!is_kml_namespace(xb, false)) continue; if (strcmp((char *) xb->name, "LinearRing")) continue; ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*)); ppa[0] = parse_kml_coordinates(xb->children, hasz); if (ppa[0]->npoints < 4 || (!*hasz && !ptarray_isclosed2d(ppa[0])) || (*hasz && !ptarray_isclosed3d(ppa[0]))) lwerror("invalid KML representation"); } } for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next) { /* Polygon/innerBoundaryIs */ if (xa->type != XML_ELEMENT_NODE) continue; if (!is_kml_namespace(xa, false)) continue; if (strcmp((char *) xa->name, "innerBoundaryIs")) continue; for (xb = xa->children ; xb != NULL ; xb = xb->next) { if (xb->type != XML_ELEMENT_NODE) continue; if (!is_kml_namespace(xb, false)) continue; if (strcmp((char *) xb->name, "LinearRing")) continue; ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa, sizeof(POINTARRAY*) * (ring + 1)); ppa[ring] = parse_kml_coordinates(xb->children, hasz); if (ppa[ring]->npoints < 4 || (!*hasz && !ptarray_isclosed2d(ppa[ring])) || (*hasz && !ptarray_isclosed3d(ppa[ring]))) lwerror("invalid KML representation"); ring++; } } /* Exterior Ring is mandatory */ if (ppa == NULL || ppa[0] == NULL) lwerror("invalid KML representation"); return (LWGEOM *) lwpoly_construct(4326, NULL, ring, ppa); }
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance) { unsigned int poff = 0; unsigned int npoints; unsigned int ncap; unsigned int ptsize; /* Check for pathology */ if( ! pa1 || ! pa2 ) { lwerror("ptarray_append_ptarray: null input"); return LW_FAILURE; } npoints = pa2->npoints; if ( ! npoints ) return LW_SUCCESS; /* nothing more to do */ if( FLAGS_GET_READONLY(pa1->flags) ) { lwerror("ptarray_append_ptarray: target pointarray is read-only"); return LW_FAILURE; } if( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) ) { lwerror("ptarray_append_ptarray: appending mixed dimensionality is not allowed"); return LW_FAILURE; } ptsize = ptarray_point_size(pa1); /* Check for duplicate end point */ if ( pa1->npoints ) { POINT2D tmp1, tmp2; getPoint2d_p(pa1, pa1->npoints-1, &tmp1); getPoint2d_p(pa2, 0, &tmp2); /* If the end point and start point are the same, then don't copy start point */ if (p2d_same(&tmp1, &tmp2)) { poff = 1; --npoints; } else if ( gap_tolerance == 0 || ( gap_tolerance > 0 && distance2d_pt_pt(&tmp1, &tmp2) > gap_tolerance ) ) { lwerror("Second line start point too far from first line end point"); return LW_FAILURE; } } /* Check if we need extra space */ ncap = pa1->npoints + npoints; if ( pa1->maxpoints < ncap ) { pa1->maxpoints = ncap > pa1->maxpoints*2 ? ncap : pa1->maxpoints*2; pa1->serialized_pointlist = (uint8_t *)lwrealloc(pa1->serialized_pointlist, ptsize * pa1->maxpoints); } memcpy(getPoint_internal(pa1, pa1->npoints), getPoint_internal(pa2, poff), ptsize * npoints); pa1->npoints = ncap; return LW_SUCCESS; }
/* Initializes and uses GEOS internally */ static LWGEOM* lwpoly_split_by_line(const LWPOLY* lwpoly_in, const LWLINE* blade_in) { LWCOLLECTION* out; GEOSGeometry* g1; GEOSGeometry* g2; GEOSGeometry* g1_bounds; GEOSGeometry* polygons; const GEOSGeometry *vgeoms[1]; int i,n; int hasZ = FLAGS_GET_Z(lwpoly_in->flags); /* Possible outcomes: * * 1. The line does not split the polygon * -> Return a collection with single element * 2. The line does split the polygon * -> Return a collection of all elements resulting from the split */ initGEOS(lwgeom_geos_error, lwgeom_geos_error); g1 = LWGEOM2GEOS((LWGEOM*)lwpoly_in, 0); if ( NULL == g1 ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } g1_bounds = GEOSBoundary(g1); if ( NULL == g1_bounds ) { GEOSGeom_destroy(g1); lwerror("GEOSBoundary: %s", lwgeom_geos_errmsg); return NULL; } g2 = LWGEOM2GEOS((LWGEOM*)blade_in, 0); if ( NULL == g2 ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g1_bounds); lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } vgeoms[0] = GEOSUnion(g1_bounds, g2); if ( NULL == vgeoms[0] ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g1_bounds); lwerror("GEOSUnion: %s", lwgeom_geos_errmsg); return NULL; } polygons = GEOSPolygonize(vgeoms, 1); if ( NULL == polygons ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g1_bounds); GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]); lwerror("GEOSPolygonize: %s", lwgeom_geos_errmsg); return NULL; } #if PARANOIA_LEVEL > 0 if ( GEOSGeomTypeId(polygons) != COLLECTIONTYPE ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g1_bounds); GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]); GEOSGeom_destroy(polygons); lwerror("%s [%s] Unexpected return from GEOSpolygonize", __FILE__, __LINE__); return 0; } #endif /* We should now have all polygons, just skip * the ones which are in holes of the original * geometries and return the rest in a collection */ n = GEOSGetNumGeometries(polygons); out = lwcollection_construct_empty(COLLECTIONTYPE, lwpoly_in->srid, hasZ, 0); /* Allocate space for all polys */ out->geoms = lwrealloc(out->geoms, sizeof(LWGEOM*)*n); assert(0 == out->ngeoms); for (i=0; i<n; ++i) { GEOSGeometry* pos; /* point on surface */ const GEOSGeometry* p = GEOSGetGeometryN(polygons, i); int contains; pos = GEOSPointOnSurface(p); if ( ! pos ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g1_bounds); GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]); GEOSGeom_destroy(polygons); lwerror("GEOSPointOnSurface: %s", lwgeom_geos_errmsg); return NULL; } contains = GEOSContains(g1, pos); if ( 2 == contains ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g1_bounds); GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]); GEOSGeom_destroy(polygons); GEOSGeom_destroy(pos); lwerror("GEOSContains: %s", lwgeom_geos_errmsg); return NULL; } GEOSGeom_destroy(pos); if ( 0 == contains ) { /* Original geometry doesn't contain * a point in this ring, must be an hole */ continue; } out->geoms[out->ngeoms++] = GEOS2LWGEOM(p, hasZ); } GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g1_bounds); GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]); GEOSGeom_destroy(polygons); return (LWGEOM*)out; }
/** * Clip an input MULTILINESTRING between two values, on any ordinate input. */ LWCOLLECTION* lwmline_clip_to_ordinate_range(const LWMLINE *mline, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; if ( ! mline ) { lwerror("Null input geometry."); return NULL; } if ( mline->ngeoms == 1) { lwgeom_out = lwline_clip_to_ordinate_range(mline->geoms[0], ordinate, from, to); } else { LWCOLLECTION *col; char hasz = lwgeom_has_z(lwmline_as_lwgeom(mline)); char hasm = lwgeom_has_m(lwmline_as_lwgeom(mline)); int i, j; char homogeneous = 1; size_t geoms_size = 0; lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, mline->srid, hasz, hasm); FLAGS_SET_Z(lwgeom_out->flags, hasz); FLAGS_SET_M(lwgeom_out->flags, hasm); for ( i = 0; i < mline->ngeoms; i ++ ) { col = lwline_clip_to_ordinate_range(mline->geoms[i], ordinate, from, to); if ( col ) { /* Something was left after the clip. */ if ( lwgeom_out->ngeoms + col->ngeoms > geoms_size ) { geoms_size += 16; if ( lwgeom_out->geoms ) { lwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, geoms_size * sizeof(LWGEOM*)); } else { lwgeom_out->geoms = lwalloc(geoms_size * sizeof(LWGEOM*)); } } for ( j = 0; j < col->ngeoms; j++ ) { lwgeom_out->geoms[lwgeom_out->ngeoms] = col->geoms[j]; lwgeom_out->ngeoms++; } if ( col->type != mline->type ) { homogeneous = 0; } /* Shallow free the struct, leaving the geoms behind. */ if ( col->bbox ) lwfree(col->bbox); lwfree(col->geoms); lwfree(col); } } lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); if ( ! homogeneous ) { lwgeom_out->type = COLLECTIONTYPE; } } if ( ! lwgeom_out || lwgeom_out->ngeoms == 0 ) /* Nothing left after clip. */ { return NULL; } return lwgeom_out; }
/* * Add an edge to a face in a tgeom * Edge is describded as a starting and an ending point * Points are really copied * Return the new tgeom pointer */ static TGEOM* tgeom_add_face_edge(TGEOM *tgeom, int face_id, POINT4D *s, POINT4D *e) { int nedges, edge_id; assert(tgeom); assert(s); assert(e); edge_id = tgeom_is_edge(tgeom, s, e); if (edge_id) { tgeom->edges[abs(edge_id)]->count++; LWDEBUGF(3, "face [%i] Founded Edge: %i\n", face_id, edge_id); } else { if ((tgeom->nedges + 1) == INT_MAX) lwerror("tgeom_add_face_edge: Unable to alloc more than %i edges", INT_MAX); /* alloc edges array */ if (tgeom->maxedges == 0) { tgeom->edges = (TEDGE**) lwalloc(sizeof(TEDGE*) * 4); tgeom->maxedges = 4; } if (tgeom->maxedges >= (tgeom->nedges + 1)) { tgeom->edges = (TEDGE **) lwrealloc(tgeom->edges, sizeof(TEDGE*) * tgeom->maxedges * 2); tgeom->maxedges *= 2; } edge_id = ++tgeom->nedges; /* edge_id is 1 based */ tgeom->edges[edge_id] = (TEDGE*) lwalloc(sizeof(TEDGE)); tgeom->edges[edge_id]->s = lwalloc(sizeof(POINT4D)); tgeom->edges[edge_id]->e = lwalloc(sizeof(POINT4D)); memcpy(tgeom->edges[edge_id]->s, s, sizeof(POINT4D)); memcpy(tgeom->edges[edge_id]->e, e, sizeof(POINT4D)); tgeom->edges[edge_id]->count = 1; LWDEBUGF(3, "face [%i] adding edge [%i] (%lf, %lf, %lf, %lf) -> (%lf, %lf, %lf, %lf)\n", face_id, edge_id, s->x, s->y, s->z, s->m, e->x, e->y, e->z, e->m); } nedges = tgeom->faces[face_id]->nedges; if (tgeom->faces[face_id]->maxedges == 0) { tgeom->faces[face_id]->edges = (int *) lwalloc(sizeof(int) * 4); tgeom->faces[face_id]->maxedges = 4; } if (tgeom->faces[face_id]->maxedges == nedges) { tgeom->faces[face_id]->edges = (int *) lwrealloc(tgeom->faces[face_id]->edges, sizeof(int) * tgeom->faces[face_id]->maxedges * 2); tgeom->faces[face_id]->maxedges *= 2; } LWDEBUGF(3, "face [%i] add %i in edge array in %i pos\n", face_id, edge_id, tgeom->faces[face_id]->nedges); tgeom->faces[face_id]->edges[nedges]= edge_id; tgeom->faces[face_id]->nedges++; return tgeom; }