From 415c0aef9bf25b79f126d1fd87e9bc764220398d Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Mon, 14 Feb 2011 17:26:38 +0000 Subject: [PATCH] ST_UnaryUnion and test git-svn-id: http://svn.osgeo.org/postgis/trunk@6816 b70326c6-7e19-0410-871a-916f4a2858ee --- postgis/lwgeom_geos.c | 93 ++++++++++++++++++++++++++++++++++++- postgis/postgis.sql.in.c | 7 +++ regress/Makefile.in | 5 ++ regress/unaryunion.sql | 10 ++++ regress/unaryunion_expected | 3 ++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 regress/unaryunion.sql create mode 100644 regress/unaryunion_expected diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c index 1b71b74ab..a208e770b 100644 --- a/postgis/lwgeom_geos.c +++ b/postgis/lwgeom_geos.c @@ -4,7 +4,7 @@ * PostGIS - Spatial Types for PostgreSQL * http://postgis.refractions.net * - * Copyright 2009-2010 Sandro Santilli + * Copyright 2009-2011 Sandro Santilli * Copyright 2008 Paul Ramsey * Copyright 2001-2003 Refractions Research Inc. * @@ -52,6 +52,7 @@ Datum difference(PG_FUNCTION_ARGS); Datum boundary(PG_FUNCTION_ARGS); Datum symdifference(PG_FUNCTION_ARGS); Datum geomunion(PG_FUNCTION_ARGS); +Datum ST_UnaryUnion(PG_FUNCTION_ARGS); Datum issimple(PG_FUNCTION_ARGS); Datum isring(PG_FUNCTION_ARGS); Datum geomequals(PG_FUNCTION_ARGS); @@ -671,6 +672,96 @@ Datum pgis_union_geometry_array(PG_FUNCTION_ARGS) } +/** + * @example ST_UnaryUnion {@link #geomunion} SELECT ST_UnaryUnion( + * 'POLYGON((0 0, 10 0, 0 10, 10 10, 0 0))' + * ); + * + */ +PG_FUNCTION_INFO_V1(ST_UnaryUnion); +Datum ST_UnaryUnion(PG_FUNCTION_ARGS) +{ +#if POSTGIS_GEOS_VERSION < 33 + PG_RETURN_NULL(); + lwerror("The GEOS version this postgis binary " + "was compiled against (%d) doesn't support " + "'GEOSUnaryUnion' function (3.3.0+ required)", + POSTGIS_GEOS_VERSION); + PG_RETURN_NULL(); +#else /* POSTGIS_GEOS_VERSION >= 33 */ + PG_LWGEOM *geom1; + int is3d; + int srid; + GEOSGeometry *g1, *g3; + PG_LWGEOM *result; + + POSTGIS_DEBUG(2, "in ST_UnaryUnion"); + + PROFSTART(PROF_QRUN); + + geom1 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + /* UnaryUnion(empty) == (empty) */ + if ( pglwgeom_is_empty(geom1) ) + PG_RETURN_POINTER(geom1); + + is3d = ( pglwgeom_has_z(geom1) ); + + srid = pglwgeom_get_srid(geom1); + + initGEOS(lwnotice, lwgeom_geos_error); + + PROFSTART(PROF_P2G1); + g1 = (GEOSGeometry *)POSTGIS2GEOS(geom1); + PROFSTOP(PROF_P2G1); + if ( 0 == g1 ) /* exception thrown at construction */ + { + lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); + PG_RETURN_NULL(); + } + + POSTGIS_DEBUGF(3, "g1=%s", GEOSGeomToWKT(g1)); + + PROFSTART(PROF_GRUN); + g3 = GEOSUnaryUnion(g1); + PROFSTOP(PROF_GRUN); + + POSTGIS_DEBUGF(3, "g3=%s", GEOSGeomToWKT(g3)); + + GEOSGeom_destroy(g1); + + if (g3 == NULL) + { + lwerror("GEOSUnion: %s", lwgeom_geos_errmsg); + PG_RETURN_NULL(); /* never get here */ + } + + + GEOSSetSRID(g3, srid); + + PROFSTART(PROF_G2P); + result = GEOS2POSTGIS(g3, is3d); + PROFSTOP(PROF_G2P); + + GEOSGeom_destroy(g3); + + if (result == NULL) + { + elog(ERROR, "ST_UnaryUnion failed converting GEOS result Geometry to PostGIS format"); + PG_RETURN_NULL(); /*never get here */ + } + + /* compressType(result); */ + + PROFSTOP(PROF_QRUN); + PROFREPORT("geos",geom1, NULL, result); + + PG_FREE_IF_COPY(geom1, 0); + + PG_RETURN_POINTER(result); +#endif /* POSTGIS_GEOS_VERSION >= 33 */ +} + /** * @example geomunion {@link #geomunion} SELECT geomunion( diff --git a/postgis/postgis.sql.in.c b/postgis/postgis.sql.in.c index 56e4cdae9..83624dd15 100644 --- a/postgis/postgis.sql.in.c +++ b/postgis/postgis.sql.in.c @@ -2987,6 +2987,13 @@ CREATE OR REPLACE FUNCTION ST_Union(geometry,geometry) AS 'MODULE_PATHNAME','geomunion' LANGUAGE 'C' IMMUTABLE STRICT; +-- Availability: 2.0.0 +-- Requires: GEOS-3.3.0 +CREATE OR REPLACE FUNCTION ST_UnaryUnion(geometry) + RETURNS geometry + AS 'MODULE_PATHNAME','ST_UnaryUnion' + LANGUAGE 'C' IMMUTABLE STRICT; + -- ST_RemoveRepeatedPoints(in geometry) -- -- Removes duplicate vertices in input. diff --git a/regress/Makefile.in b/regress/Makefile.in index 9ff2afec0..3d293a4ee 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -106,6 +106,11 @@ ifeq ($(shell expr $(POSTGIS_GEOS_VERSION) ">=" 33),1) TESTS += snap endif +# ST_UnaryUnion if GEOS >= 3.3 +ifeq ($(shell expr $(POSTGIS_GEOS_VERSION) ">=" 33),1) + TESTS += unaryunion +endif + all install uninstall distclean: postgis.sql: ../postgis/postgis.sql diff --git a/regress/unaryunion.sql b/regress/unaryunion.sql new file mode 100644 index 000000000..78826731c --- /dev/null +++ b/regress/unaryunion.sql @@ -0,0 +1,10 @@ + +-- Noding a multilinestring +SELECT 1, ST_AsText(ST_UnaryUnion('MULTILINESTRING((0 0, 10 0), (5 -5, 5 5))')); + +-- Unioning a set of polygons (CascadedUnion) +SELECT 2, ST_AsText(ST_UnaryUnion('GEOMETRYCOLLECTION(POLYGON((0 0, 10 0, 10 10, 0 10, 0 0)),POLYGON((5 5, 15 5, 15 15, 5 15, 5 5)))')); + +-- Unioning an heterogeneous collection of geometries +SELECT 3, ST_AsText(ST_UnaryUnion('GEOMETRYCOLLECTION(POLYGON((0 0, 10 0, 10 10, 0 10, 0 0)),POLYGON((5 5, 15 5, 15 15, 5 15, 5 5)), MULTIPOINT(5 4, -5 4),LINESTRING(2 -10, 2 20))')); + diff --git a/regress/unaryunion_expected b/regress/unaryunion_expected new file mode 100644 index 000000000..074bc6c84 --- /dev/null +++ b/regress/unaryunion_expected @@ -0,0 +1,3 @@ +1|MULTILINESTRING((0 0,5 0),(5 0,10 0),(5 -5,5 0),(5 0,5 5)) +2|POLYGON((10 5,10 0,0 0,0 10,5 10,5 15,15 15,15 5,10 5)) +3|GEOMETRYCOLLECTION(POINT(-5 4),LINESTRING(2 -10,2 0),LINESTRING(2 10,2 20),POLYGON((10 5,10 0,2 0,0 0,0 10,2 10,5 10,5 15,15 15,15 5,10 5))) -- 2.50.1