]> granicus.if.org Git - postgis/commitdiff
Add lwgeom_buildarea to liblwgeom [RT-SIGTA]
authorSandro Santilli <strk@keybit.net>
Sat, 6 Aug 2011 09:46:33 +0000 (09:46 +0000)
committerSandro Santilli <strk@keybit.net>
Sat, 6 Aug 2011 09:46:33 +0000 (09:46 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@7697 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/lwgeom_geos.c
liblwgeom/lwgeom_geos.h
postgis/lwgeom_geos.c
postgis/lwgeom_geos.h

index 7a35f93a008859b08c0a892813614b98bbe31063..11d24f72a70b21dd2262b71aa0e89e0ab3951a80 100644 (file)
@@ -1,3 +1,15 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Copyright 2011 Sandro Santilli <strk@keybit.net>
+ *
+ * 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; i<ngeoms; ++i)
+       {
+               GEOSGeom extring;
+               GEOSCoordSeq sq;
+
+               /*
+                * Construct a Polygon from geometry i exterior ring
+                * We don't use GEOSGeom_clone on the ExteriorRing
+                * due to a bug in CAPI contained in GEOS 2.2 branch
+                * failing to properly return a LinearRing from
+                * a LinearRing clone.
+                */
+               sq=GEOSCoordSeq_clone(GEOSGeom_getCoordSeq(
+                                         GEOSGetExteriorRing(GEOSGetGeometryN( geos_result, i))
+                                     ));
+               extring = GEOSGeom_createPolygon(
+                             GEOSGeom_createLinearRing(sq),
+                             NULL, 0
+                         );
+
+               if ( extring == NULL ) /* exception */
+               {
+                       lwerror("GEOSCreatePolygon threw an exception");
+                       return 0;
+               }
+
+               if ( shp == NULL )
+               {
+                       shp = extring;
+                       LWDEBUGF(3, "GEOSpolygonize: shp:%s",
+                                      lwgeom_to_ewkt(GEOS2LWGEOM(shp, 0), PARSER_CHECK_NONE));
+               }
+               else
+               {
+                       tmp = GEOSSymDifference(shp, extring);
+                       LWDEBUGF(3, "GEOSpolygonize: SymDifference(%s, %s):%s",
+                                      lwgeom_to_ewkt(GEOS2LWGEOM(shp, 0), PARSER_CHECK_NONE),
+                                      lwgeom_to_ewkt(GEOS2LWGEOM(extring, 0), PARSER_CHECK_NONE),
+                                      lwgeom_to_ewkt(GEOS2LWGEOM(tmp, 0), PARSER_CHECK_NONE)
+                                     );
+                       GEOSGeom_destroy(shp);
+                       GEOSGeom_destroy(extring);
+                       shp = tmp;
+               }
+       }
+
+       GEOSGeom_destroy(geos_result);
+
+       GEOSSetSRID(shp, srid);
+
+       return shp;
+}
+
+/**
+ * Take a geometry and return an areal geometry
+ * (Polygon or MultiPolygon).
+ * Actually a wrapper around GEOSpolygonize,
+ * transforming the resulting collection into
+ * a valid polygon Geometry.
+ */
+LWGEOM*
+lwgeom_buildarea(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, "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;
+}
index 94c29c382d6401782a1766037ef9fbe26732adff..eaa8204648f5615464848104090fe0a416b736ae 100644 (file)
@@ -1,3 +1,15 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ *
+ * Copyright 2011 Sandro Santilli <strk@keybit.net>
+ *
+ * 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);
 
index 52589ebf3028a773b46f5a88c3a0aa2c9052b6a4..e955445930e74c8fc6a9b245496cfd19f8c2e8e9 100644 (file)
@@ -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<ngeoms; ++i)
-       {
-               GEOSGeom extring;
-               GEOSCoordSeq sq;
-
-               /*
-                * Construct a Polygon from geometry i exterior ring
-                * We don't use GEOSGeom_clone on the ExteriorRing
-                * due to a bug in CAPI contained in GEOS 2.2 branch
-                * failing to properly return a LinearRing from
-                * a LinearRing clone.
-                */
-               sq=GEOSCoordSeq_clone(GEOSGeom_getCoordSeq(
-                                         GEOSGetExteriorRing(GEOSGetGeometryN( geos_result, i))
-                                     ));
-               extring = GEOSGeom_createPolygon(
-                             GEOSGeom_createLinearRing(sq),
-                             NULL, 0
-                         );
-
-               if ( extring == NULL ) /* exception */
-               {
-                       lwerror("GEOSCreatePolygon threw an exception");
-                       return 0;
-               }
-
-               if ( shp == NULL )
-               {
-                       shp = extring;
-                       POSTGIS_DEBUGF(3, "GEOSpolygonize: shp:%s",
-                                      lwgeom_to_ewkt(GEOS2LWGEOM(shp, 0), PARSER_CHECK_NONE));
-               }
-               else
-               {
-                       tmp = GEOSSymDifference(shp, extring);
-                       POSTGIS_DEBUGF(3, "GEOSpolygonize: SymDifference(%s, %s):%s",
-                                      lwgeom_to_ewkt(GEOS2LWGEOM(shp, 0), PARSER_CHECK_NONE),
-                                      lwgeom_to_ewkt(GEOS2LWGEOM(extring, 0), PARSER_CHECK_NONE),
-                                      lwgeom_to_ewkt(GEOS2LWGEOM(tmp, 0), PARSER_CHECK_NONE)
-                                     );
-                       GEOSGeom_destroy(shp);
-                       GEOSGeom_destroy(extring);
-                       shp = tmp;
-               }
-       }
-
-       GEOSGeom_destroy(geos_result);
-
-       return shp;
-}
-
 PG_FUNCTION_INFO_V1(postgis_geos_version);
 Datum postgis_geos_version(PG_FUNCTION_ARGS)
 {
@@ -3645,82 +3528,31 @@ Datum linemerge(PG_FUNCTION_ARGS)
  * (Polygon or MultiPolygon).
  * Actually a wrapper around GEOSpolygonize,
  * transforming the resulting collection into
- * a valid polygonzl Geometry.
+ * a valid polygon Geometry.
  */
 PG_FUNCTION_INFO_V1(LWGEOM_buildarea);
 Datum LWGEOM_buildarea(PG_FUNCTION_ARGS)
 {
-       int is3d = 0;
        PG_LWGEOM *result;
        PG_LWGEOM *geom;
-       GEOSGeometry* geos_in;
-       GEOSGeometry* geos_out;
-       LWGEOM *lwgeom;
-       int srid=SRID_UNKNOWN;
-#if POSTGIS_DEBUG_LEVEL >= 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);
-
 }
 
index c98748e8141654f63fc1e96e5a5ab59dac301be6..f03b19f2847501a4c8263542587e32351c18425e 100644 (file)
@@ -1,8 +1,8 @@
 /**********************************************************************
- * $Id$
  *
  * PostGIS - Spatial Types for PostgreSQL
  * http://postgis.refractions.net
+ *
  * Copyright 2008 Paul Ramsey <pramsey@cleverelephant.ca>
  *
  * 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);
-
-