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

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

1224 {
1225  GEOSGeometry *tmp;
1226  GEOSGeometry *geos_result, *shp;
1227  GEOSGeometry const *vgeoms[1];
1228  uint32_t i, ngeoms;
1229  int srid = GEOSGetSRID(geom_in);
1230  Face ** geoms;
1231 
1232  vgeoms[0] = geom_in;
1233 #ifdef LWGEOM_PROFILE_BUILDAREA
1234  lwnotice("Polygonizing");
1235 #endif
1236  geos_result = GEOSPolygonize(vgeoms, 1);
1237 
1238  LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
1239 
1240  /* Null return from GEOSpolygonize (an exception) */
1241  if ( ! geos_result ) return 0;
1242 
1243  /*
1244  * We should now have a collection
1245  */
1246 #if PARANOIA_LEVEL > 0
1247  if ( GEOSGeometryTypeId(geos_result) != COLLECTIONTYPE )
1248  {
1249  GEOSGeom_destroy(geos_result);
1250  lwerror("Unexpected return from GEOSpolygonize");
1251  return 0;
1252  }
1253 #endif
1254 
1255  ngeoms = GEOSGetNumGeometries(geos_result);
1256 #ifdef LWGEOM_PROFILE_BUILDAREA
1257  lwnotice("Num geometries from polygonizer: %d", ngeoms);
1258 #endif
1259 
1260 
1261  LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
1262  LWDEBUGF(3, "GEOSpolygonize: polygonized:%s",
1263  lwgeom_to_ewkt(GEOS2LWGEOM(geos_result, 0)));
1264 
1265  /*
1266  * No geometries in collection, early out
1267  */
1268  if ( ngeoms == 0 )
1269  {
1270  GEOSSetSRID(geos_result, srid);
1271  return geos_result;
1272  }
1273 
1274  /*
1275  * Return first geometry if we only have one in collection,
1276  * to avoid the unnecessary Geometry clone below.
1277  */
1278  if ( ngeoms == 1 )
1279  {
1280  tmp = (GEOSGeometry *)GEOSGetGeometryN(geos_result, 0);
1281  if ( ! tmp )
1282  {
1283  GEOSGeom_destroy(geos_result);
1284  return 0; /* exception */
1285  }
1286  shp = GEOSGeom_clone(tmp);
1287  GEOSGeom_destroy(geos_result); /* only safe after the clone above */
1288  GEOSSetSRID(shp, srid);
1289  return shp;
1290  }
1291 
1292  LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
1293 
1294  /*
1295  * Polygonizer returns a polygon for each face in the built topology.
1296  *
1297  * This means that for any face with holes we'll have other faces
1298  * representing each hole. We can imagine a parent-child relationship
1299  * between these faces.
1300  *
1301  * In order to maximize the number of visible rings in output we
1302  * only use those faces which have an even number of parents.
1303  *
1304  * Example:
1305  *
1306  * +---------------+
1307  * | L0 | L0 has no parents
1308  * | +---------+ |
1309  * | | L1 | | L1 is an hole of L0
1310  * | | +---+ | |
1311  * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0)
1312  * | | | | | |
1313  * | | +---+ | |
1314  * | +---------+ |
1315  * | |
1316  * +---------------+
1317  *
1318  * See http://trac.osgeo.org/postgis/ticket/1806
1319  *
1320  */
1321 
1322 #ifdef LWGEOM_PROFILE_BUILDAREA
1323  lwnotice("Preparing face structures");
1324 #endif
1325 
1326  /* Prepare face structures for later analysis */
1327  geoms = lwalloc(sizeof(Face**)*ngeoms);
1328  for (i=0; i<ngeoms; ++i)
1329  geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
1330 
1331 #ifdef LWGEOM_PROFILE_BUILDAREA
1332  lwnotice("Finding face holes");
1333 #endif
1334 
1335  /* Find faces representing other faces holes */
1336  findFaceHoles(geoms, ngeoms);
1337 
1338 #ifdef LWGEOM_PROFILE_BUILDAREA
1339  lwnotice("Colletting even ancestor faces");
1340 #endif
1341 
1342  /* Build a MultiPolygon composed only by faces with an
1343  * even number of ancestors */
1344  tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
1345 
1346 #ifdef LWGEOM_PROFILE_BUILDAREA
1347  lwnotice("Cleaning up");
1348 #endif
1349 
1350  /* Cleanup face structures */
1351  for (i=0; i<ngeoms; ++i) delFace(geoms[i]);
1352  lwfree(geoms);
1353 
1354  /* Faces referenced memory owned by geos_result.
1355  * It is safe to destroy geos_result after deleting them. */
1356  GEOSGeom_destroy(geos_result);
1357 
1358 #ifdef LWGEOM_PROFILE_BUILDAREA
1359  lwnotice("Self-unioning");
1360 #endif
1361 
1362  /* Run a single overlay operation to dissolve shared edges */
1363  shp = GEOSUnionCascaded(tmp);
1364  if ( ! shp )
1365  {
1366  GEOSGeom_destroy(tmp);
1367  return 0; /* exception */
1368  }
1369 
1370 #ifdef LWGEOM_PROFILE_BUILDAREA
1371  lwnotice("Final cleanup");
1372 #endif
1373 
1374  GEOSGeom_destroy(tmp);
1375 
1376  GEOSSetSRID(shp, srid);
1377 
1378  return shp;
1379 }
static void delFace(Face *f)
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:89
void lwfree(void *mem)
Definition: lwutil.c:242
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:482
static void findFaceHoles(Face **faces, int nfaces)
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:227
#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:102
#define COLLECTIONTYPE
Definition: liblwgeom.h:90

Here is the call graph for this function:

Here is the caller graph for this function: