PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ LWGEOM_GEOS_buildArea()

GEOSGeometry* LWGEOM_GEOS_buildArea ( const GEOSGeometry *  geom_in)

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

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