PostGIS  2.5.1dev-r@@SVN_REVISION@@

◆ LWGEOM_GEOS_buildArea()

GEOSGeometry* LWGEOM_GEOS_buildArea ( const GEOSGeometry *  geom_in)

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

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

Referenced by lwgeom_buildarea(), and LWGEOM_GEOS_makeValidPolygon().

1012 {
1013  GEOSGeometry* tmp;
1014  GEOSGeometry *geos_result, *shp;
1015  GEOSGeometry const* vgeoms[1];
1016  uint32_t i, ngeoms;
1017  int srid = GEOSGetSRID(geom_in);
1018  Face** geoms;
1019 #if POSTGIS_DEBUG_LEVEL >= 3
1020  LWGEOM *geos_geom;
1021  char *geom_ewkt;
1022 #endif
1023 
1024  vgeoms[0] = geom_in;
1025  geos_result = GEOSPolygonize(vgeoms, 1);
1026 
1027  LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
1028 
1029  /* Null return from GEOSpolygonize (an exception) */
1030  if (!geos_result) return 0;
1031 
1032  /* We should now have a collection */
1033 #if PARANOIA_LEVEL > 0
1034  if (GEOSGeomTypeId(geos_result) != COLLECTIONTYPE)
1035  {
1036  GEOSGeom_destroy(geos_result);
1037  lwerror("%s [%d] Unexpected return from GEOSpolygonize", __FILE__, __LINE__);
1038  return 0;
1039  }
1040 #endif
1041 
1042  ngeoms = GEOSGetNumGeometries(geos_result);
1043 
1044 #if POSTGIS_DEBUG_LEVEL >= 3
1045  LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
1046  geos_geom = GEOS2LWGEOM(geos_result, 0);
1047  geom_ewkt = lwgeom_to_ewkt(geos_geom);
1048  LWDEBUGF(3, "GEOSpolygonize: polygonized:%s", geom_ewkt);
1049  lwgeom_free(geos_geom);
1050  lwfree(geom_ewkt);
1051 #endif
1052 
1053  /* No geometries in collection, early out */
1054  if (ngeoms == 0)
1055  {
1056  GEOSSetSRID(geos_result, srid);
1057  return geos_result;
1058  }
1059 
1060  /* Return first geometry if we only have one in collection, to avoid the unnecessary Geometry clone below. */
1061  if (ngeoms == 1)
1062  {
1063  tmp = (GEOSGeometry*)GEOSGetGeometryN(geos_result, 0);
1064  if (!tmp)
1065  {
1066  GEOSGeom_destroy(geos_result);
1067  return 0; /* exception */
1068  }
1069  shp = GEOSGeom_clone(tmp);
1070  GEOSGeom_destroy(geos_result); /* only safe after the clone above */
1071  GEOSSetSRID(shp, srid);
1072  return shp;
1073  }
1074 
1075  LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
1076 
1077  /*
1078  * Polygonizer returns a polygon for each face in the built topology.
1079  *
1080  * This means that for any face with holes we'll have other faces representing each hole. We can imagine a
1081  * parent-child relationship between these faces.
1082  *
1083  * In order to maximize the number of visible rings in output we only use those faces which have an even number
1084  * of parents.
1085  *
1086  * Example:
1087  *
1088  * +---------------+
1089  * | L0 | L0 has no parents
1090  * | +---------+ |
1091  * | | L1 | | L1 is an hole of L0
1092  * | | +---+ | |
1093  * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0)
1094  * | | | | | |
1095  * | | +---+ | |
1096  * | +---------+ |
1097  * | |
1098  * +---------------+
1099  *
1100  * See http://trac.osgeo.org/postgis/ticket/1806
1101  *
1102  */
1103 
1104  /* Prepare face structures for later analysis */
1105  geoms = lwalloc(sizeof(Face**) * ngeoms);
1106  for (i = 0; i < ngeoms; ++i)
1107  geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
1108 
1109  /* Find faces representing other faces holes */
1110  findFaceHoles(geoms, ngeoms);
1111 
1112  /* Build a MultiPolygon composed only by faces with an even number of ancestors */
1113  tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
1114 
1115  /* Cleanup face structures */
1116  for (i = 0; i < ngeoms; ++i)
1117  delFace(geoms[i]);
1118  lwfree(geoms);
1119 
1120  /* Faces referenced memory owned by geos_result. It is safe to destroy geos_result after deleting them. */
1121  GEOSGeom_destroy(geos_result);
1122 
1123  /* Run a single overlay operation to dissolve shared edges */
1124  shp = GEOSUnionCascaded(tmp);
1125  if (!shp)
1126  {
1127  GEOSGeom_destroy(tmp);
1128  return 0; /* exception */
1129  }
1130 
1131  GEOSGeom_destroy(tmp);
1132 
1133  GEOSSetSRID(shp, srid);
1134 
1135  return shp;
1136 }
LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, uint8_t want3d)
static void delFace(Face *f)
void lwfree(void *mem)
Definition: lwutil.c:244
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:556
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
static void findFaceHoles(Face **faces, int nfaces)
unsigned int uint32_t
Definition: uthash.h:78
static GEOSGeometry * collectFacesWithEvenAncestors(Face **faces, int nfaces)
static Face * newFace(const GEOSGeometry *g)
void * lwalloc(size_t size)
Definition: lwutil.c:229
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
Here is the call graph for this function:
Here is the caller graph for this function: