LWGEOM* lwgeom_sharedpaths(const LWGEOM* geom1, const LWGEOM* geom2) { #if POSTGIS_GEOS_VERSION < 33 lwerror("The GEOS version this postgis binary " "was compiled against (%d) doesn't support " "'SharedPaths' function (3.3.0+ required)", POSTGIS_GEOS_VERSION); return NULL; #else /* POSTGIS_GEOS_VERSION >= 33 */ GEOSGeometry *g1, *g2, *g3; LWGEOM *out; int is3d, srid; srid = geom1->srid; error_if_srid_mismatch(srid, (int)(geom2->srid)); is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ; initGEOS(lwnotice, lwgeom_geos_error); g1 = (GEOSGeometry *)LWGEOM2GEOS(geom1); if ( 0 == g1 ) /* exception thrown at construction */ { lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = (GEOSGeometry *)LWGEOM2GEOS(geom2); if ( 0 == g2 ) /* exception thrown at construction */ { lwerror("Second argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); GEOSGeom_destroy(g1); return NULL; } g3 = GEOSSharedPaths(g1,g2); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); if (g3 == NULL) { lwerror("GEOSSharedPaths: %s", lwgeom_geos_errmsg); return NULL; } GEOSSetSRID(g3, srid); out = GEOS2LWGEOM(g3, is3d); GEOSGeom_destroy(g3); if (out == NULL) { lwerror("GEOS2LWGEOM threw an error"); return NULL; } return out; #endif /* POSTGIS_GEOS_VERSION >= 33 */ }
/* May return LWPOINT or LWMPOINT */ static LWGEOM* lwgeom_extract_unique_endpoints(const LWGEOM* lwg) { LWGEOM* ret; GEOSGeometry *gepu; LWMPOINT *epall = lwgeom_extract_endpoints(lwg); GEOSGeometry *gepall = LWGEOM2GEOS((LWGEOM*)epall, 1); lwmpoint_free(epall); if ( ! gepall ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } /* UnaryUnion to remove duplicates */ /* TODO: do it all within pgis using indices */ gepu = GEOSUnaryUnion(gepall); if ( ! gepu ) { GEOSGeom_destroy(gepall); lwerror("GEOSUnaryUnion: %s", lwgeom_geos_errmsg); return NULL; } GEOSGeom_destroy(gepall); ret = GEOS2LWGEOM(gepu, FLAGS_GET_Z(lwg->flags)); GEOSGeom_destroy(gepu); if ( ! ret ) { lwerror("Error during GEOS2LWGEOM"); return NULL; } return ret; }
LWGEOM* lwgeom_buildarea(const LWGEOM *geom) { GEOSGeometry* geos_in; GEOSGeometry* geos_out; LWGEOM* geom_out; int SRID = (int)(geom->srid); int is3d = FLAGS_GET_Z(geom->flags); /* Can't build an area from an empty! */ if ( lwgeom_is_empty(geom) ) { return (LWGEOM*)lwpoly_construct_empty(SRID, is3d, 0); } LWDEBUG(3, "buildarea called"); LWDEBUGF(3, "ST_BuildArea got geom @ %p", geom); initGEOS(lwnotice, lwgeom_geos_error); geos_in = LWGEOM2GEOS(geom); if ( 0 == geos_in ) /* exception thrown at construction */ { lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } geos_out = LWGEOM_GEOS_buildArea(geos_in); GEOSGeom_destroy(geos_in); if ( ! geos_out ) /* exception thrown.. */ { lwerror("LWGEOM_GEOS_buildArea: %s", lwgeom_geos_errmsg); return NULL; } /* If no geometries are in result collection, return NULL */ if ( GEOSGetNumGeometries(geos_out) == 0 ) { GEOSGeom_destroy(geos_out); return NULL; } geom_out = GEOS2LWGEOM(geos_out, is3d); GEOSGeom_destroy(geos_out); #if PARANOIA_LEVEL > 0 if ( geom_out == NULL ) { lwerror("serialization error"); return NULL; } #endif return geom_out; }
LWGEOM* lwgeom_offsetcurve(const LWLINE *lwline, double size, int quadsegs, int joinStyle, double mitreLimit) { #if POSTGIS_GEOS_VERSION < 32 lwerror("lwgeom_offsetcurve: GEOS 3.2 or higher required"); #else GEOSGeometry *g1, *g3; LWGEOM *lwgeom_result; LWGEOM *lwgeom_in = lwline_as_lwgeom(lwline); initGEOS(lwnotice, lwgeom_geos_error); g1 = (GEOSGeometry *)LWGEOM2GEOS(lwgeom_in); if ( ! g1 ) { lwerror("lwgeom_offsetcurve: Geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } #if POSTGIS_GEOS_VERSION < 33 /* Size is always positive for GEOSSingleSidedBuffer, and a flag determines left/right */ g3 = GEOSSingleSidedBuffer(g1, size < 0 ? -size : size, quadsegs, joinStyle, mitreLimit, size < 0 ? 0 : 1); #else g3 = GEOSOffsetCurve(g1, size, quadsegs, joinStyle, mitreLimit); #endif /* Don't need input geometry anymore */ GEOSGeom_destroy(g1); if (g3 == NULL) { GEOSGeom_destroy(g1); lwerror("GEOSOffsetCurve: %s", lwgeom_geos_errmsg); return NULL; } LWDEBUGF(3, "result: %s", GEOSGeomToWKT(g3)); GEOSSetSRID(g3, lwgeom_get_srid(lwgeom_in)); lwgeom_result = GEOS2LWGEOM(g3, lwgeom_has_z(lwgeom_in)); GEOSGeom_destroy(g3); if (lwgeom_result == NULL) { lwerror("lwgeom_offsetcurve: GEOS2LWGEOM returned null"); return NULL; } return lwgeom_result; #endif /* POSTGIS_GEOS_VERSION < 32 */ }
/* May return LWPOINT or LWMPOINT */ static LWGEOM* lwgeom_extract_unique_endpoints(const LWGEOM* lwg) { #if POSTGIS_GEOS_VERSION < 33 lwerror("The GEOS version this postgis binary " "was compiled against (%d) doesn't support " "'GEOSUnaryUnion' function (3.3.0+ required)", POSTGIS_GEOS_VERSION); return NULL; #else /* POSTGIS_GEOS_VERSION >= 33 */ LWGEOM* ret; GEOSGeometry *gepu; LWMPOINT *epall = lwgeom_extract_endpoints(lwg); GEOSGeometry *gepall = LWGEOM2GEOS((LWGEOM*)epall); lwmpoint_free(epall); if ( ! gepall ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } /* UnaryUnion to remove duplicates */ /* TODO: do it all within pgis using indices */ gepu = GEOSUnaryUnion(gepall); if ( ! gepu ) { GEOSGeom_destroy(gepall); lwerror("GEOSUnaryUnion: %s", lwgeom_geos_errmsg); return NULL; } GEOSGeom_destroy(gepall); ret = GEOS2LWGEOM(gepu, FLAGS_GET_Z(lwg->flags)); GEOSGeom_destroy(gepu); if ( ! ret ) { lwerror("Error during GEOS2LWGEOM"); return NULL; } return ret; #endif /* POSTGIS_GEOS_VERSION >= 33 */ }
LWGEOM * lwgeom_normalize(const LWGEOM *geom1) { LWGEOM *result ; GEOSGeometry *g1; int is3d ; int srid ; srid = (int)(geom1->srid); is3d = FLAGS_GET_Z(geom1->flags); initGEOS(lwnotice, lwgeom_geos_error); g1 = LWGEOM2GEOS(geom1); if ( 0 == g1 ) /* exception thrown at construction */ { lwerror("First argument geometry could not be converted to GEOS."); return NULL ; } if ( -1 == GEOSNormalize(g1) ) { lwerror("Error in GEOSNormalize: %s", lwgeom_geos_errmsg); return NULL; /* never get here */ } GEOSSetSRID(g1, srid); /* needed ? */ result = GEOS2LWGEOM(g1, is3d); GEOSGeom_destroy(g1); if (result == NULL) { lwerror("Error performing intersection: GEOS2LWGEOM: %s", lwgeom_geos_errmsg); return NULL ; /* never get here */ } return result ; }
LWGEOM* lwgeom_geos_noop(const LWGEOM* geom_in) { GEOSGeometry *geosgeom; LWGEOM* geom_out; int is3d = FLAGS_GET_Z(geom_in->flags); initGEOS(lwnotice, lwgeom_geos_error); geosgeom = LWGEOM2GEOS(geom_in); if ( ! geosgeom ) { lwerror("Geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } geom_out = GEOS2LWGEOM(geosgeom, is3d); GEOSGeom_destroy(geosgeom); if ( ! geom_out ) { lwerror("GEOS Geometry could not be converted to LWGEOM: %s", lwgeom_geos_errmsg); } return geom_out; }
/* Initializes and uses GEOS internally */ static LWGEOM* lwline_split_by_line(const LWLINE* lwline_in, const LWGEOM* blade_in) { LWGEOM** components; LWGEOM* diff; LWCOLLECTION* out; GEOSGeometry* gdiff; /* difference */ GEOSGeometry* g1; GEOSGeometry* g2; int ret; /* ASSERT blade_in is LINE or MULTILINE */ assert (blade_in->type == LINETYPE || blade_in->type == MULTILINETYPE || blade_in->type == POLYGONTYPE || blade_in->type == MULTIPOLYGONTYPE ); /* Possible outcomes: * * 1. The lines do not cross or overlap * -> Return a collection with single element * 2. The lines cross * -> Return a collection of all elements resulting from the split */ initGEOS(lwgeom_geos_error, lwgeom_geos_error); g1 = LWGEOM2GEOS((LWGEOM*)lwline_in, 0); if ( ! g1 ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = LWGEOM2GEOS(blade_in, 0); if ( ! g2 ) { GEOSGeom_destroy(g1); lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } /* If blade is a polygon, pick its boundary */ if ( blade_in->type == POLYGONTYPE || blade_in->type == MULTIPOLYGONTYPE ) { gdiff = GEOSBoundary(g2); GEOSGeom_destroy(g2); if ( ! gdiff ) { GEOSGeom_destroy(g1); lwerror("GEOSBoundary: %s", lwgeom_geos_errmsg); return NULL; } g2 = gdiff; gdiff = NULL; } /* If interior intersecton is linear we can't split */ ret = GEOSRelatePattern(g1, g2, "1********"); if ( 2 == ret ) { lwerror("GEOSRelatePattern: %s", lwgeom_geos_errmsg); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); return NULL; } if ( ret ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); lwerror("Splitter line has linear intersection with input"); return NULL; } gdiff = GEOSDifference(g1,g2); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); if (gdiff == NULL) { lwerror("GEOSDifference: %s", lwgeom_geos_errmsg); return NULL; } diff = GEOS2LWGEOM(gdiff, FLAGS_GET_Z(lwline_in->flags)); GEOSGeom_destroy(gdiff); if (NULL == diff) { lwerror("GEOS2LWGEOM: %s", lwgeom_geos_errmsg); return NULL; } out = lwgeom_as_lwcollection(diff); if ( ! out ) { components = lwalloc(sizeof(LWGEOM*)*1); components[0] = diff; out = lwcollection_construct(COLLECTIONTYPE, lwline_in->srid, NULL, 1, components); } else { /* Set SRID */ lwgeom_set_srid((LWGEOM*)out, lwline_in->srid); /* Force collection type */ out->type = COLLECTIONTYPE; } return (LWGEOM*)out; }
/* 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; }
LWGEOM* lwgeom_node(const LWGEOM* lwgeom_in) { #if POSTGIS_GEOS_VERSION < 33 lwerror("The GEOS version this postgis binary " "was compiled against (%d) doesn't support " "'GEOSUnaryUnion' function (3.3.0+ required)", POSTGIS_GEOS_VERSION); return NULL; #else /* POSTGIS_GEOS_VERSION >= 33 */ GEOSGeometry *g1, *gu, *gm; LWGEOM *ep, *lines; LWCOLLECTION *col, *tc; int pn, ln, np, nl; if ( lwgeom_dimension(lwgeom_in) != 1 ) { lwerror("Noding geometries of dimension != 1 is unsupported"); return NULL; } initGEOS(lwgeom_geos_error, lwgeom_geos_error); g1 = LWGEOM2GEOS(lwgeom_in); if ( ! g1 ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } ep = lwgeom_extract_unique_endpoints(lwgeom_in); if ( ! ep ) { GEOSGeom_destroy(g1); lwerror("Error extracting unique endpoints from input"); return NULL; } /* Unary union input to fully node */ gu = GEOSUnaryUnion(g1); GEOSGeom_destroy(g1); if ( ! gu ) { lwgeom_free(ep); lwerror("GEOSUnaryUnion: %s", lwgeom_geos_errmsg); return NULL; } /* Linemerge (in case of overlaps) */ gm = GEOSLineMerge(gu); GEOSGeom_destroy(gu); if ( ! gm ) { lwgeom_free(ep); lwerror("GEOSLineMerge: %s", lwgeom_geos_errmsg); return NULL; } lines = GEOS2LWGEOM(gm, FLAGS_GET_Z(lwgeom_in->flags)); GEOSGeom_destroy(gm); if ( ! lines ) { lwgeom_free(ep); lwerror("Error during GEOS2LWGEOM"); return NULL; } /* * Reintroduce endpoints from input, using split-line-by-point. * Note that by now we can be sure that each point splits at * most _one_ segment as any point shared by multiple segments * would already be a node. Also we can be sure that any of * the segments endpoints won't split any other segment. * We can use the above 2 assertions to early exit the loop. */ col = lwcollection_construct_empty(MULTILINETYPE, lwgeom_in->srid, FLAGS_GET_Z(lwgeom_in->flags), FLAGS_GET_M(lwgeom_in->flags)); np = lwgeom_ngeoms(ep); for (pn=0; pn<np; ++pn) { /* for each point */ const LWPOINT* p = (LWPOINT*)lwgeom_subgeom(ep, pn); nl = lwgeom_ngeoms(lines); for (ln=0; ln<nl; ++ln) { /* for each line */ const LWLINE* l = (LWLINE*)lwgeom_subgeom(lines, ln); int s = lwline_split_by_point_to(l, p, (LWMLINE*)col); if ( ! s ) continue; /* not on this line */ if ( s == 1 ) { /* found on this line, but not splitting it */ break; } /* splits this line */ /* replace this line with the two splits */ if ( lwgeom_is_collection(lines) ) { tc = (LWCOLLECTION*)lines; lwcollection_reserve(tc, nl + 1); while (nl > ln+1) { tc->geoms[nl] = tc->geoms[nl-1]; --nl; } lwgeom_free(tc->geoms[ln]); tc->geoms[ln] = col->geoms[0]; tc->geoms[ln+1] = col->geoms[1]; tc->ngeoms++; } else { lwgeom_free(lines); /* transfer ownership rather than cloning */ lines = (LWGEOM*)lwcollection_clone_deep(col); assert(col->ngeoms == 2); lwgeom_free(col->geoms[0]); lwgeom_free(col->geoms[1]); } /* reset the vector */ assert(col->ngeoms == 2); col->ngeoms = 0; break; } } lwgeom_free(ep); lwcollection_free(col); lines->srid = lwgeom_in->srid; return (LWGEOM*)lines; #endif /* POSTGIS_GEOS_VERSION >= 33 */ }
LWGEOM* lwgeom_snap(const LWGEOM* geom1, const LWGEOM* geom2, double tolerance) { #if POSTGIS_GEOS_VERSION < 33 lwerror("The GEOS version this lwgeom library " "was compiled against (%d) doesn't support " "'Snap' function (3.3.0+ required)", POSTGIS_GEOS_VERSION); return NULL; #else /* POSTGIS_GEOS_VERSION >= 33 */ int srid, is3d; GEOSGeometry *g1, *g2, *g3; LWGEOM* out; srid = geom1->srid; error_if_srid_mismatch(srid, (int)(geom2->srid)); is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ; initGEOS(lwnotice, lwgeom_geos_error); g1 = (GEOSGeometry *)LWGEOM2GEOS(geom1); if ( 0 == g1 ) /* exception thrown at construction */ { lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = (GEOSGeometry *)LWGEOM2GEOS(geom2); if ( 0 == g2 ) /* exception thrown at construction */ { lwerror("Second argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); GEOSGeom_destroy(g1); return NULL; } g3 = GEOSSnap(g1, g2, tolerance); if (g3 == NULL) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); lwerror("GEOSSnap: %s", lwgeom_geos_errmsg); return NULL; } GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSSetSRID(g3, srid); out = GEOS2LWGEOM(g3, is3d); if (out == NULL) { GEOSGeom_destroy(g3); lwerror("GEOSSnap() threw an error (result LWGEOM geometry formation)!"); return NULL; } GEOSGeom_destroy(g3); return out; #endif /* POSTGIS_GEOS_VERSION >= 33 */ }
LWGEOM* lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2) { int is3d; int srid; GEOSGeometry *g1, *g2, *g3; LWGEOM *result; LWDEBUG(2, "in geomunion"); /* A.Union(empty) == A */ if ( lwgeom_is_empty(geom1) ) return lwgeom_clone(geom2); /* B.Union(empty) == B */ if ( lwgeom_is_empty(geom2) ) return lwgeom_clone(geom1); /* ensure srids are identical */ srid = (int)(geom1->srid); error_if_srid_mismatch(srid, (int)(geom2->srid)); is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ; initGEOS(lwnotice, lwgeom_geos_error); g1 = LWGEOM2GEOS(geom1); if ( 0 == g1 ) /* exception thrown at construction */ { lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = LWGEOM2GEOS(geom2); if ( 0 == g2 ) /* exception thrown at construction */ { GEOSGeom_destroy(g1); lwerror("Second argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } LWDEBUGF(3, "g1=%s", GEOSGeomToWKT(g1)); LWDEBUGF(3, "g2=%s", GEOSGeomToWKT(g2)); g3 = GEOSUnion(g1,g2); LWDEBUGF(3, "g3=%s", GEOSGeomToWKT(g3)); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); if (g3 == NULL) { lwerror("GEOSUnion: %s", lwgeom_geos_errmsg); return NULL; /* never get here */ } GEOSSetSRID(g3, srid); result = GEOS2LWGEOM(g3, is3d); GEOSGeom_destroy(g3); if (result == NULL) { lwerror("Error performing union: GEOS2LWGEOM: %s", lwgeom_geos_errmsg); return NULL; /*never get here */ } return result; }
LWGEOM * lwgeom_symdifference(const LWGEOM* geom1, const LWGEOM* geom2) { GEOSGeometry *g1, *g2, *g3; LWGEOM *result; int is3d; int srid; /* A.SymDifference(Empty) == A */ if ( lwgeom_is_empty(geom2) ) return lwgeom_clone(geom1); /* Empty.DymDifference(B) == Empty */ if ( lwgeom_is_empty(geom1) ) return lwgeom_clone(geom1); /* ensure srids are identical */ srid = (int)(geom1->srid); error_if_srid_mismatch(srid, (int)(geom2->srid)); is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ; initGEOS(lwnotice, lwgeom_geos_error); g1 = LWGEOM2GEOS(geom1); if ( 0 == g1 ) /* exception thrown at construction */ { lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = LWGEOM2GEOS(geom2); if ( 0 == g2 ) /* exception thrown at construction */ { lwerror("Second argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); GEOSGeom_destroy(g1); return NULL; } g3 = GEOSSymDifference(g1,g2); if (g3 == NULL) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); lwerror("GEOSSymDifference: %s", lwgeom_geos_errmsg); return NULL; /*never get here */ } LWDEBUGF(3, "result: %s", GEOSGeomToWKT(g3)); GEOSSetSRID(g3, srid); result = GEOS2LWGEOM(g3, is3d); if (result == NULL) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g3); lwerror("GEOS symdifference() threw an error (result postgis geometry formation)!"); return NULL ; /*never get here */ } GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g3); return result; }
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2) { LWGEOM *result ; GEOSGeometry *g1, *g2, *g3 ; int is3d ; int srid ; /* A.Intersection(Empty) == Empty */ if ( lwgeom_is_empty(geom2) ) return lwgeom_clone(geom2); /* Empty.Intersection(A) == Empty */ if ( lwgeom_is_empty(geom1) ) return lwgeom_clone(geom1); /* ensure srids are identical */ srid = (int)(geom1->srid); error_if_srid_mismatch(srid, (int)(geom2->srid)); is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ; initGEOS(lwnotice, lwgeom_geos_error); LWDEBUG(3, "intersection() START"); g1 = LWGEOM2GEOS(geom1); if ( 0 == g1 ) /* exception thrown at construction */ { lwerror("First argument geometry could not be converted to GEOS."); return NULL ; } g2 = LWGEOM2GEOS(geom2); if ( 0 == g2 ) /* exception thrown at construction */ { lwerror("Second argument geometry could not be converted to GEOS."); GEOSGeom_destroy(g1); return NULL ; } LWDEBUG(3, " constructed geometrys - calling geos"); LWDEBUGF(3, " g1 = %s", GEOSGeomToWKT(g1)); LWDEBUGF(3, " g2 = %s", GEOSGeomToWKT(g2)); /*LWDEBUGF(3, "g2 is valid = %i",GEOSisvalid(g2)); */ /*LWDEBUGF(3, "g1 is valid = %i",GEOSisvalid(g1)); */ g3 = GEOSIntersection(g1,g2); LWDEBUG(3, " intersection finished"); if (g3 == NULL) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); lwerror("Error performing intersection: %s", lwgeom_geos_errmsg); return NULL; /* never get here */ } LWDEBUGF(3, "result: %s", GEOSGeomToWKT(g3) ) ; GEOSSetSRID(g3, srid); result = GEOS2LWGEOM(g3, is3d); if (result == NULL) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g3); lwerror("Error performing intersection: GEOS2LWGEOM: %s", lwgeom_geos_errmsg); return NULL ; /* never get here */ } GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); GEOSGeom_destroy(g3); return result ; }
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom) { GEOSCoordSeq sq; GEOSGeom g, shell; GEOSGeom *geoms = NULL; /* LWGEOM *tmp; */ uint32_t ngeoms, i; int geostype; #if LWDEBUG_LEVEL >= 4 char *wkt; #endif LWDEBUGF(4, "LWGEOM2GEOS got a %s", lwtype_name(lwgeom->type)); if (lwgeom_has_arc(lwgeom)) { LWDEBUG(3, "LWGEOM2GEOS: arced geometry found."); lwerror("Exception in LWGEOM2GEOS: curved geometry not supported."); return NULL; } switch (lwgeom->type) { LWPOINT *lwp = NULL; LWPOLY *lwpoly = NULL; LWLINE *lwl = NULL; LWCOLLECTION *lwc = NULL; #if POSTGIS_GEOS_VERSION < 33 POINTARRAY *pa = NULL; #endif case POINTTYPE: lwp = (LWPOINT *)lwgeom; if ( lwgeom_is_empty(lwgeom) ) { #if POSTGIS_GEOS_VERSION < 33 pa = ptarray_construct_empty(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), 2); sq = ptarray_to_GEOSCoordSeq(pa); shell = GEOSGeom_createLinearRing(sq); g = GEOSGeom_createPolygon(shell, NULL, 0); #else g = GEOSGeom_createEmptyPolygon(); #endif } else { sq = ptarray_to_GEOSCoordSeq(lwp->point); g = GEOSGeom_createPoint(sq); } if ( ! g ) { /* lwnotice("Exception in LWGEOM2GEOS"); */ return NULL; } break; case LINETYPE: lwl = (LWLINE *)lwgeom; if ( lwl->points->npoints == 1 ) { /* Duplicate point, to make geos-friendly */ lwl->points = ptarray_addPoint(lwl->points, getPoint_internal(lwl->points, 0), FLAGS_NDIMS(lwl->points->flags), lwl->points->npoints); } sq = ptarray_to_GEOSCoordSeq(lwl->points); g = GEOSGeom_createLineString(sq); if ( ! g ) { /* lwnotice("Exception in LWGEOM2GEOS"); */ return NULL; } break; case POLYGONTYPE: lwpoly = (LWPOLY *)lwgeom; if ( lwgeom_is_empty(lwgeom) ) { #if POSTGIS_GEOS_VERSION < 33 POINTARRAY *pa = ptarray_construct_empty(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), 2); sq = ptarray_to_GEOSCoordSeq(pa); shell = GEOSGeom_createLinearRing(sq); g = GEOSGeom_createPolygon(shell, NULL, 0); #else g = GEOSGeom_createEmptyPolygon(); #endif } else { sq = ptarray_to_GEOSCoordSeq(lwpoly->rings[0]); /* TODO: check ring for being closed and fix if not */ shell = GEOSGeom_createLinearRing(sq); if ( ! shell ) return NULL; /*lwerror("LWGEOM2GEOS: exception during polygon shell conversion"); */ ngeoms = lwpoly->nrings-1; if ( ngeoms > 0 ) geoms = malloc(sizeof(GEOSGeom)*ngeoms); for (i=1; i<lwpoly->nrings; ++i) { sq = ptarray_to_GEOSCoordSeq(lwpoly->rings[i]); geoms[i-1] = GEOSGeom_createLinearRing(sq); if ( ! geoms[i-1] ) { --i; while (i) GEOSGeom_destroy(geoms[--i]); free(geoms); GEOSGeom_destroy(shell); return NULL; } /*lwerror("LWGEOM2GEOS: exception during polygon hole conversion"); */ } g = GEOSGeom_createPolygon(shell, geoms, ngeoms); if (geoms) free(geoms); } if ( ! g ) return NULL; break; case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case COLLECTIONTYPE: if ( lwgeom->type == MULTIPOINTTYPE ) geostype = GEOS_MULTIPOINT; else if ( lwgeom->type == MULTILINETYPE ) geostype = GEOS_MULTILINESTRING; else if ( lwgeom->type == MULTIPOLYGONTYPE ) geostype = GEOS_MULTIPOLYGON; else geostype = GEOS_GEOMETRYCOLLECTION; lwc = (LWCOLLECTION *)lwgeom; ngeoms = lwc->ngeoms; if ( ngeoms > 0 ) geoms = malloc(sizeof(GEOSGeom)*ngeoms); for (i=0; i<ngeoms; ++i) { GEOSGeometry* g = LWGEOM2GEOS(lwc->geoms[i]); if ( ! g ) { while (i) GEOSGeom_destroy(geoms[--i]); free(geoms); return NULL; } geoms[i] = g; } g = GEOSGeom_createCollection(geostype, geoms, ngeoms); if ( geoms ) free(geoms); if ( ! g ) return NULL; break; default: lwerror("Unknown geometry type: %d - %s", lwgeom->type, lwtype_name(lwgeom->type)); return NULL; } GEOSSetSRID(g, lwgeom->srid); #if LWDEBUG_LEVEL >= 4 wkt = GEOSGeomToWKT(g); LWDEBUGF(4, "LWGEOM2GEOS: GEOSGeom: %s", wkt); free(wkt); #endif return g; }
/* Initializes and uses GEOS internally */ static LWGEOM* lwline_split_by_line(const LWLINE* lwline_in, const LWLINE* blade_in) { LWGEOM** components; LWGEOM* diff; LWCOLLECTION* out; GEOSGeometry* gdiff; /* difference */ GEOSGeometry* g1; GEOSGeometry* g2; int ret; /* Possible outcomes: * * 1. The lines do not cross or overlap * -> Return a collection with single element * 2. The lines cross * -> Return a collection of all elements resulting from the split */ initGEOS(lwgeom_geos_error, lwgeom_geos_error); g1 = LWGEOM2GEOS((LWGEOM*)lwline_in); if ( ! g1 ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } g2 = LWGEOM2GEOS((LWGEOM*)blade_in); if ( ! g2 ) { GEOSGeom_destroy(g1); lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } /* If interior intersecton is linear we can't split */ ret = GEOSRelatePattern(g1, g2, "1********"); if ( 2 == ret ) { lwerror("GEOSRelatePattern: %s", lwgeom_geos_errmsg); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); return NULL; } if ( ret ) { GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); lwerror("Splitter line has linear intersection with input"); return NULL; } gdiff = GEOSDifference(g1,g2); GEOSGeom_destroy(g1); GEOSGeom_destroy(g2); if (gdiff == NULL) { lwerror("GEOSDifference: %s", lwgeom_geos_errmsg); return NULL; } diff = GEOS2LWGEOM(gdiff, FLAGS_GET_Z(lwline_in->flags)); GEOSGeom_destroy(gdiff); if (NULL == diff) { lwerror("GEOS2LWGEOM: %s", lwgeom_geos_errmsg); return NULL; } if ( ! lwtype_is_collection(diff->type) ) { components = lwalloc(sizeof(LWGEOM*)*1); components[0] = diff; out = lwcollection_construct(COLLECTIONTYPE, lwline_in->srid, NULL, 1, components); } else { out = lwcollection_construct(COLLECTIONTYPE, lwline_in->srid, NULL, ((LWCOLLECTION*)diff)->ngeoms, ((LWCOLLECTION*)diff)->geoms); } return (LWGEOM*)out; }