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

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

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