From: Sandro Santilli Date: Sat, 6 Aug 2011 09:46:33 +0000 (+0000) Subject: Add lwgeom_buildarea to liblwgeom [RT-SIGTA] X-Git-Tag: 2.0.0alpha1~1150 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5f7f4fefbe783190bedb52103dcc50a755a5f2e6;p=postgis Add lwgeom_buildarea to liblwgeom [RT-SIGTA] git-svn-id: http://svn.osgeo.org/postgis/trunk@7697 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/lwgeom_geos.c b/liblwgeom/lwgeom_geos.c index 7a35f93a0..11d24f72a 100644 --- a/liblwgeom/lwgeom_geos.c +++ b/liblwgeom/lwgeom_geos.c @@ -1,3 +1,15 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Copyright 2011 Sandro Santilli + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + #include "lwgeom_geos.h" #include "liblwgeom.h" #include "profile.h" @@ -231,7 +243,7 @@ LWGEOM2GEOS(LWGEOM *lwgeom) */ uint32 ngeoms, i; int geostype; -#if POSTGIS_DEBUG_LEVEL >= 4 +#if LWDEBUG_LEVEL >= 4 char *wkt; #endif @@ -375,7 +387,7 @@ LWGEOM2GEOS(LWGEOM *lwgeom) GEOSSetSRID(g, lwgeom->srid); -#if POSTGIS_DEBUG_LEVEL >= 4 +#if LWDEBUG_LEVEL >= 4 wkt = GEOSGeomToWKT(g); LWDEBUGF(4, "LWGEOM2GEOS: GEOSGeom: %s", wkt); free(wkt); @@ -738,3 +750,189 @@ LWGEOM* lwgeom_union(LWGEOM *geom1, LWGEOM *geom2) } +GEOSGeometry* +LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in) +{ + GEOSGeometry *tmp; + GEOSGeometry *geos_result, *shp; + GEOSGeometry const *vgeoms[1]; + uint32 i, ngeoms; + int srid = GEOSGetSRID(geom_in); + + vgeoms[0] = geom_in; + geos_result = GEOSPolygonize(vgeoms, 1); + + LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result); + + /* Null return from GEOSpolygonize (an exception) */ + if ( ! geos_result ) return 0; + + /* + * We should now have a collection + */ +#if PARANOIA_LEVEL > 0 + if ( GEOSGeometryTypeId(geos_result) != COLLECTIONTYPE ) + { + GEOSGeom_destroy(geos_result); + lwerror("Unexpected return from GEOSpolygonize"); + return 0; + } +#endif + + ngeoms = GEOSGetNumGeometries(geos_result); + + LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms); + LWDEBUGF(3, "GEOSpolygonize: polygonized:%s", + lwgeom_to_ewkt(GEOS2LWGEOM(geos_result, 0), PARSER_CHECK_NONE)); + + /* + * No geometries in collection, early out + */ + if ( ngeoms == 0 ) + { + GEOSSetSRID(geos_result, srid); + return geos_result; + } + + /* + * Return first geometry if we only have one in collection, + * to avoid the unnecessary Geometry clone below. + */ + if ( ngeoms == 1 ) + { + tmp = (GEOSGeometry *)GEOSGetGeometryN(geos_result, 0); + if ( ! tmp ) + { + GEOSGeom_destroy(geos_result); + return 0; /* exception */ + } + shp = GEOSGeom_clone(tmp); + GEOSGeom_destroy(geos_result); /* only safe after the clone above */ + GEOSSetSRID(shp, srid); + return shp; + } + + /* + * Iteratively invoke symdifference on outer rings + * as suggested by Carl Anderson: + * postgis-devel/2005-December/001805.html + */ + shp = NULL; + for (i=0; isrid); + 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, "LWGEOM_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; +} diff --git a/liblwgeom/lwgeom_geos.h b/liblwgeom/lwgeom_geos.h index 94c29c382..eaa820464 100644 --- a/liblwgeom/lwgeom_geos.h +++ b/liblwgeom/lwgeom_geos.h @@ -1,3 +1,15 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * + * Copyright 2011 Sandro Santilli + * + * This is free software; you can redistribute and/or modify it under + * the terms of the GNU General Public Licence. See the COPYING file. + * + **********************************************************************/ + /* Workaround for GEOS 2.2 compatibility: old geos_c.h does not contain header guards to protect from multiple inclusion */ #ifndef GEOS_C_INCLUDED @@ -12,6 +24,7 @@ LWGEOM *lwgeom_intersection(LWGEOM *geom1, LWGEOM *geom2) ; LWGEOM *lwgeom_difference(LWGEOM *geom1, LWGEOM *geom2) ; LWGEOM *lwgeom_symdifference(LWGEOM* geom1, LWGEOM* geom2) ; LWGEOM* lwgeom_union(LWGEOM *geom1, LWGEOM *geom2) ; +LWGEOM* lwgeom_buildarea(LWGEOM *geom) ; @@ -20,6 +33,8 @@ LWGEOM* lwgeom_union(LWGEOM *geom1, LWGEOM *geom2) ; */ LWGEOM *GEOS2LWGEOM(const GEOSGeometry *geom, char want3d); GEOSGeometry * LWGEOM2GEOS(LWGEOM *g); +GEOSGeometry * LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in); + POINTARRAY *ptarray_from_GEOSCoordSeq(const GEOSCoordSequence *cs, char want3d); diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c index 52589ebf3..e95544593 100644 --- a/postgis/lwgeom_geos.c +++ b/postgis/lwgeom_geos.c @@ -1,5 +1,4 @@ /********************************************************************** - * $Id$ * * PostGIS - Spatial Types for PostgreSQL * http://postgis.refractions.net @@ -79,122 +78,6 @@ Datum pgis_union_geometry_array(PG_FUNCTION_ARGS); */ -GEOSGeometry* -LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in) -{ - GEOSGeometry *tmp; - GEOSGeometry *geos_result, *shp; - GEOSGeometry const *vgeoms[1]; - uint32 i, ngeoms; - - vgeoms[0] = geom_in; - geos_result = GEOSPolygonize(vgeoms, 1); - - POSTGIS_DEBUGF(3, "GEOSpolygonize returned @ %p", geos_result); - - /* Null return from GEOSpolygonize (an exception) */ - if ( ! geos_result ) return 0; - - /* - * We should now have a collection - */ -#if PARANOIA_LEVEL > 0 - if ( GEOSGeometryTypeId(geos_result) != COLLECTIONTYPE ) - { - GEOSGeom_destroy(geos_result); - lwerror("Unexpected return from GEOSpolygonize"); - return 0; - } -#endif - - ngeoms = GEOSGetNumGeometries(geos_result); - - POSTGIS_DEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms); - POSTGIS_DEBUGF(3, "GEOSpolygonize: polygonized:%s", - lwgeom_to_ewkt(GEOS2LWGEOM(geos_result, 0), PARSER_CHECK_NONE)); - - /* - * No geometries in collection, early out - */ - if ( ngeoms == 0 ) - { - return geos_result; - } - - /* - * Return first geometry if we only have one in collection, - * to avoid the unnecessary Geometry clone below. - */ - if ( ngeoms == 1 ) - { - tmp = (GEOSGeometry *)GEOSGetGeometryN(geos_result, 0); - if ( ! tmp ) - { - GEOSGeom_destroy(geos_result); - return 0; /* exception */ - } - shp = GEOSGeom_clone(tmp); - GEOSGeom_destroy(geos_result); /* only safe after the clone above */ - return shp; - } - - /* - * Iteratively invoke symdifference on outer rings - * as suggested by Carl Anderson: - * postgis-devel/2005-December/001805.html - */ - shp = NULL; - for (i=0; i= 3 - static int call=1; -#endif + LWGEOM *lwgeom_in, *lwgeom_out; geom = (PG_LWGEOM*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - lwgeom = pglwgeom_deserialize(geom); - - /* Can't build an area from an empty! */ - if ( lwgeom_is_empty(lwgeom) ) - { - lwgeom_free(lwgeom); - PG_RETURN_POINTER(geom); - } - -#if POSTGIS_DEBUG_LEVEL >= 3 - call++; - lwnotice("buildarea called (call %d)", call); -#endif - - srid = pglwgeom_get_srid(geom); - is3d = pglwgeom_has_z(geom); - - POSTGIS_DEBUGF(3, "LWGEOM_buildarea got geom @ %p", geom); + lwgeom_in = pglwgeom_deserialize(geom); - initGEOS(lwnotice, lwgeom_geos_error); - - geos_in = LWGEOM2GEOS(lwgeom); - lwgeom_free(lwgeom); - - if ( 0 == geos_in ) /* exception thrown at construction */ - { - lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); + lwgeom_out = lwgeom_buildarea(lwgeom_in); + if ( ! lwgeom_out ) { + lwgeom_free(lwgeom_in) ; + PG_FREE_IF_COPY(geom, 0); PG_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); - PG_RETURN_NULL(); - } + result = pglwgeom_serialize(lwgeom_out) ; - /* If no geometries are in result collection, return NULL */ - if ( GEOSGetNumGeometries(geos_out) == 0 ) - { - GEOSGeom_destroy(geos_out); - PG_RETURN_NULL(); - } - - GEOSSetSRID(geos_out, srid); - result = GEOS2POSTGIS(geos_out, is3d); - GEOSGeom_destroy(geos_out); - -#if PARANOIA_LEVEL > 0 - if ( result == NULL ) - { - lwerror("serialization error"); - PG_RETURN_NULL(); /*never get here */ - } - -#endif + lwgeom_free(lwgeom_out) ; + lwgeom_free(lwgeom_in) ; + PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); - } diff --git a/postgis/lwgeom_geos.h b/postgis/lwgeom_geos.h index c98748e81..f03b19f28 100644 --- a/postgis/lwgeom_geos.h +++ b/postgis/lwgeom_geos.h @@ -1,8 +1,8 @@ /********************************************************************** - * $Id$ * * PostGIS - Spatial Types for PostgreSQL * http://postgis.refractions.net + * * Copyright 2008 Paul Ramsey * * This is free software; you can redistribute and/or modify it under @@ -49,9 +49,3 @@ GEOSGeometry * POSTGIS2GEOS(PG_LWGEOM *g); void errorIfGeometryCollection(PG_LWGEOM *g1, PG_LWGEOM *g2); -/* - * This function would better be moved to the GEOS C-API - */ -GEOSGeometry* LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in); - -