/* 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; }
void object::test<2>() { geom1_ = GEOSGeomFromWKT("POINT (6 3)"); ensure( 0 != geom1_ ); geom2_ = GEOSUnaryUnion(geom1_); ensure( 0 != geom2_ ); ensure_equals(toWKT(geom2_), std::string("POINT (6 3)")); }
void object::test<1>() { geom1_ = GEOSGeomFromWKT("POINT EMPTY"); ensure( 0 != geom1_ ); geom2_ = GEOSUnaryUnion(geom1_); ensure( 0 != geom2_ ); ensure_equals(toWKT(geom2_), std::string("GEOMETRYCOLLECTION EMPTY")); }
void object::test<5>() { geom1_ = GEOSGeomFromWKT("GEOMETRYCOLLECTION (POINT(4 5), MULTIPOINT(6 7, 6 5, 6 7), LINESTRING(0 5, 10 5), LINESTRING(4 -10, 4 10))"); ensure( 0 != geom1_ ); geom2_ = GEOSUnaryUnion(geom1_); ensure( 0 != geom2_ ); ensure_equals(toWKT(geom2_), std::string("GEOMETRYCOLLECTION (POINT (6 7), LINESTRING (4 -10, 4 5), LINESTRING (4 5, 4 10), LINESTRING (0 5, 4 5), LINESTRING (4 5, 10 5))")); }
void object::test<4>() { geom1_ = GEOSGeomFromWKT("MULTIPOINT (4 5, 6 7, 4 5, 6 5, 6 7)"); ensure( 0 != geom1_ ); geom2_ = GEOSUnaryUnion(geom1_); ensure( 0 != geom2_ ); ensure_equals(toWKT(geom2_), std::string("MULTIPOINT (4 5, 6 5, 6 7)")); }
void object::test<8>() { geom1_ = GEOSGeomFromWKT("GEOMETRYCOLLECTION (MULTILINESTRING((5 7, 12 7), (4 5, 6 5), (5.5 7.5, 6.5 7.5)), POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(5 6, 7 6, 7 8, 5 8, 5 6)), MULTIPOINT(6 6.5, 6 1, 12 2, 6 1))"); ensure( 0 != geom1_ ); geom2_ = GEOSUnaryUnion(geom1_); ensure( 0 != geom2_ ); ensure_equals(toWKT(geom2_), std::string( "GEOMETRYCOLLECTION (POINT (6 6.5), POINT (12 2), LINESTRING (5 7, 7 7), LINESTRING (10 7, 12 7), LINESTRING (5.5 7.5, 6.5 7.5), POLYGON ((10 7, 10 0, 0 0, 0 10, 10 10, 10 7), (5 6, 7 6, 7 7, 7 8, 5 8, 5 7, 5 6)))" )); }
void object::test<6>() { geom1_ = GEOSGeomFromWKT("GEOMETRYCOLLECTION (POINT(4 5), MULTIPOINT(6 7, 6 5, 6 7), POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(5 6, 7 6, 7 8, 5 8, 5 6)))"); ensure( 0 != geom1_ ); geom2_ = GEOSUnaryUnion(geom1_); ensure( 0 != geom2_ ); ensure_equals(toWKT(geom2_), std::string( "GEOMETRYCOLLECTION (POINT (6 7), POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 6, 7 6, 7 8, 5 8, 5 6)))" )); }
/* 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_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 */ }