PostGIS  2.5.0dev-r@@SVN_REVISION@@

◆ LWGEOM_GEOS_buildArea()

GEOSGeometry* LWGEOM_GEOS_buildArea ( const GEOSGeometry *  geom_in)

Definition at line 1040 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().

1041 {
1042  GEOSGeometry* tmp;
1043  GEOSGeometry *geos_result, *shp;
1044  GEOSGeometry const* vgeoms[1];
1045  uint32_t i, ngeoms;
1046  int srid = GEOSGetSRID(geom_in);
1047  Face** geoms;
1048 #if POSTGIS_DEBUG_LEVEL >= 3
1049  LWGEOM *geos_geom;
1050  char *geom_ewkt;
1051 #endif
1052 
1053  vgeoms[0] = geom_in;
1054  geos_result = GEOSPolygonize(vgeoms, 1);
1055 
1056  LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
1057 
1058  /* Null return from GEOSpolygonize (an exception) */
1059  if (!geos_result) return 0;
1060 
1061  /* We should now have a collection */
1062 #if PARANOIA_LEVEL > 0
1063  if (GEOSGeomTypeId(geos_result) != COLLECTIONTYPE)
1064  {
1065  GEOSGeom_destroy(geos_result);
1066  lwerror("%s [%d] Unexpected return from GEOSpolygonize", __FILE__, __LINE__);
1067  return 0;
1068  }
1069 #endif
1070 
1071  ngeoms = GEOSGetNumGeometries(geos_result);
1072 
1073 #if POSTGIS_DEBUG_LEVEL >= 3
1074  LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
1075  geos_geom = GEOS2LWGEOM(geos_result, 0);
1076  geom_ewkt = lwgeom_to_ewkt(geos_geom);
1077  LWDEBUGF(3, "GEOSpolygonize: polygonized:%s", geom_ewkt);
1078  lwgeom_free(geos_geom);
1079  lwfree(geom_ewkt);
1080 #endif
1081 
1082  /* No geometries in collection, early out */
1083  if (ngeoms == 0)
1084  {
1085  GEOSSetSRID(geos_result, srid);
1086  return geos_result;
1087  }
1088 
1089  /* Return first geometry if we only have one in collection, to avoid the unnecessary Geometry clone below. */
1090  if (ngeoms == 1)
1091  {
1092  tmp = (GEOSGeometry*)GEOSGetGeometryN(geos_result, 0);
1093  if (!tmp)
1094  {
1095  GEOSGeom_destroy(geos_result);
1096  return 0; /* exception */
1097  }
1098  shp = GEOSGeom_clone(tmp);
1099  GEOSGeom_destroy(geos_result); /* only safe after the clone above */
1100  GEOSSetSRID(shp, srid);
1101  return shp;
1102  }
1103 
1104  LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
1105 
1106  /*
1107  * Polygonizer returns a polygon for each face in the built topology.
1108  *
1109  * This means that for any face with holes we'll have other faces representing each hole. We can imagine a
1110  * parent-child relationship between these faces.
1111  *
1112  * In order to maximize the number of visible rings in output we only use those faces which have an even number
1113  * of parents.
1114  *
1115  * Example:
1116  *
1117  * +---------------+
1118  * | L0 | L0 has no parents
1119  * | +---------+ |
1120  * | | L1 | | L1 is an hole of L0
1121  * | | +---+ | |
1122  * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0)
1123  * | | | | | |
1124  * | | +---+ | |
1125  * | +---------+ |
1126  * | |
1127  * +---------------+
1128  *
1129  * See http://trac.osgeo.org/postgis/ticket/1806
1130  *
1131  */
1132 
1133  /* Prepare face structures for later analysis */
1134  geoms = lwalloc(sizeof(Face**) * ngeoms);
1135  for (i = 0; i < ngeoms; ++i)
1136  geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
1137 
1138  /* Find faces representing other faces holes */
1139  findFaceHoles(geoms, ngeoms);
1140 
1141  /* Build a MultiPolygon composed only by faces with an even number of ancestors */
1142  tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
1143 
1144  /* Cleanup face structures */
1145  for (i = 0; i < ngeoms; ++i)
1146  delFace(geoms[i]);
1147  lwfree(geoms);
1148 
1149  /* Faces referenced memory owned by geos_result. It is safe to destroy geos_result after deleting them. */
1150  GEOSGeom_destroy(geos_result);
1151 
1152  /* Run a single overlay operation to dissolve shared edges */
1153  shp = GEOSUnionCascaded(tmp);
1154  if (!shp)
1155  {
1156  GEOSGeom_destroy(tmp);
1157  return 0; /* exception */
1158  }
1159 
1160  GEOSGeom_destroy(tmp);
1161 
1162  GEOSSetSRID(shp, srid);
1163 
1164  return shp;
1165 }
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: