PostGIS  2.1.10dev-r@@SVN_REVISION@@
GEOSGeometry* LWGEOM_GEOS_buildArea ( const GEOSGeometry *  geom_in)

Definition at line 898 of file liblwgeom/lwgeom_geos.c.

References collectFacesWithEvenAncestors(), COLLECTIONTYPE, delFace(), findFaceHoles(), GEOS2LWGEOM(), lwalloc(), LWDEBUGF, lwerror(), lwfree(), lwgeom_to_ewkt(), lwnotice(), and newFace().

Referenced by lwgeom_buildarea(), and LWGEOM_GEOS_makeValidPolygon().

899 {
900  GEOSGeometry *tmp;
901  GEOSGeometry *geos_result, *shp;
902  GEOSGeometry const *vgeoms[1];
903  uint32_t i, ngeoms;
904  int srid = GEOSGetSRID(geom_in);
905  Face ** geoms;
906 
907  vgeoms[0] = geom_in;
908 #ifdef LWGEOM_PROFILE_BUILDAREA
909  lwnotice("Polygonizing");
910 #endif
911  geos_result = GEOSPolygonize(vgeoms, 1);
912 
913  LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
914 
915  /* Null return from GEOSpolygonize (an exception) */
916  if ( ! geos_result ) return 0;
917 
918  /*
919  * We should now have a collection
920  */
921 #if PARANOIA_LEVEL > 0
922  if ( GEOSGeometryTypeId(geos_result) != COLLECTIONTYPE )
923  {
924  GEOSGeom_destroy(geos_result);
925  lwerror("Unexpected return from GEOSpolygonize");
926  return 0;
927  }
928 #endif
929 
930  ngeoms = GEOSGetNumGeometries(geos_result);
931 #ifdef LWGEOM_PROFILE_BUILDAREA
932  lwnotice("Num geometries from polygonizer: %d", ngeoms);
933 #endif
934 
935 
936  LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
937  LWDEBUGF(3, "GEOSpolygonize: polygonized:%s",
938  lwgeom_to_ewkt(GEOS2LWGEOM(geos_result, 0)));
939 
940  /*
941  * No geometries in collection, early out
942  */
943  if ( ngeoms == 0 )
944  {
945  GEOSSetSRID(geos_result, srid);
946  return geos_result;
947  }
948 
949  /*
950  * Return first geometry if we only have one in collection,
951  * to avoid the unnecessary Geometry clone below.
952  */
953  if ( ngeoms == 1 )
954  {
955  tmp = (GEOSGeometry *)GEOSGetGeometryN(geos_result, 0);
956  if ( ! tmp )
957  {
958  GEOSGeom_destroy(geos_result);
959  return 0; /* exception */
960  }
961  shp = GEOSGeom_clone(tmp);
962  GEOSGeom_destroy(geos_result); /* only safe after the clone above */
963  GEOSSetSRID(shp, srid);
964  return shp;
965  }
966 
967  LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
968 
969  /*
970  * Polygonizer returns a polygon for each face in the built topology.
971  *
972  * This means that for any face with holes we'll have other faces
973  * representing each hole. We can imagine a parent-child relationship
974  * between these faces.
975  *
976  * In order to maximize the number of visible rings in output we
977  * only use those faces which have an even number of parents.
978  *
979  * Example:
980  *
981  * +---------------+
982  * | L0 | L0 has no parents
983  * | +---------+ |
984  * | | L1 | | L1 is an hole of L0
985  * | | +---+ | |
986  * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0)
987  * | | | | | |
988  * | | +---+ | |
989  * | +---------+ |
990  * | |
991  * +---------------+
992  *
993  * See http://trac.osgeo.org/postgis/ticket/1806
994  *
995  */
996 
997 #ifdef LWGEOM_PROFILE_BUILDAREA
998  lwnotice("Preparing face structures");
999 #endif
1000 
1001  /* Prepare face structures for later analysis */
1002  geoms = lwalloc(sizeof(Face**)*ngeoms);
1003  for (i=0; i<ngeoms; ++i)
1004  geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
1005 
1006 #ifdef LWGEOM_PROFILE_BUILDAREA
1007  lwnotice("Finding face holes");
1008 #endif
1009 
1010  /* Find faces representing other faces holes */
1011  findFaceHoles(geoms, ngeoms);
1012 
1013 #ifdef LWGEOM_PROFILE_BUILDAREA
1014  lwnotice("Colletting even ancestor faces");
1015 #endif
1016 
1017  /* Build a MultiPolygon composed only by faces with an
1018  * even number of ancestors */
1019  tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
1020 
1021 #ifdef LWGEOM_PROFILE_BUILDAREA
1022  lwnotice("Cleaning up");
1023 #endif
1024 
1025  /* Cleanup face structures */
1026  for (i=0; i<ngeoms; ++i) delFace(geoms[i]);
1027  lwfree(geoms);
1028 
1029  /* Faces referenced memory owned by geos_result.
1030  * It is safe to destroy geos_result after deleting them. */
1031  GEOSGeom_destroy(geos_result);
1032 
1033 #ifdef LWGEOM_PROFILE_BUILDAREA
1034  lwnotice("Self-unioning");
1035 #endif
1036 
1037  /* Run a single overlay operation to dissolve shared edges */
1038  shp = GEOSUnionCascaded(tmp);
1039  if ( ! shp )
1040  {
1041  GEOSGeom_destroy(tmp);
1042  return 0; /* exception */
1043  }
1044 
1045 #ifdef LWGEOM_PROFILE_BUILDAREA
1046  lwnotice("Final cleanup");
1047 #endif
1048 
1049  GEOSGeom_destroy(tmp);
1050 
1051  GEOSSetSRID(shp, srid);
1052 
1053  return shp;
1054 }
static void delFace(Face *f)
void lwfree(void *mem)
Definition: lwutil.c:190
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:425
static void findFaceHoles(Face **faces, int nfaces)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:54
static GEOSGeometry * collectFacesWithEvenAncestors(Face **faces, int nfaces)
static Face * newFace(const GEOSGeometry *g)
LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, char want3d)
void * lwalloc(size_t size)
Definition: lwutil.c:175
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:55
#define COLLECTIONTYPE
Definition: liblwgeom.h:66

Here is the call graph for this function:

Here is the caller graph for this function: