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

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

1144 {
1145  GEOSGeometry *tmp;
1146  GEOSGeometry *geos_result, *shp;
1147  GEOSGeometry const *vgeoms[1];
1148  uint32_t i, ngeoms;
1149  int srid = GEOSGetSRID(geom_in);
1150  Face ** geoms;
1151 
1152  vgeoms[0] = geom_in;
1153 #ifdef LWGEOM_PROFILE_BUILDAREA
1154  lwnotice("Polygonizing");
1155 #endif
1156  geos_result = GEOSPolygonize(vgeoms, 1);
1157 
1158  LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
1159 
1160  /* Null return from GEOSpolygonize (an exception) */
1161  if ( ! geos_result ) return 0;
1162 
1163  /*
1164  * We should now have a collection
1165  */
1166 #if PARANOIA_LEVEL > 0
1167  if ( GEOSGeometryTypeId(geos_result) != COLLECTIONTYPE )
1168  {
1169  GEOSGeom_destroy(geos_result);
1170  lwerror("Unexpected return from GEOSpolygonize");
1171  return 0;
1172  }
1173 #endif
1174 
1175  ngeoms = GEOSGetNumGeometries(geos_result);
1176 #ifdef LWGEOM_PROFILE_BUILDAREA
1177  lwnotice("Num geometries from polygonizer: %d", ngeoms);
1178 #endif
1179 
1180 
1181  LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
1182  LWDEBUGF(3, "GEOSpolygonize: polygonized:%s",
1183  lwgeom_to_ewkt(GEOS2LWGEOM(geos_result, 0)));
1184 
1185  /*
1186  * No geometries in collection, early out
1187  */
1188  if ( ngeoms == 0 )
1189  {
1190  GEOSSetSRID(geos_result, srid);
1191  return geos_result;
1192  }
1193 
1194  /*
1195  * Return first geometry if we only have one in collection,
1196  * to avoid the unnecessary Geometry clone below.
1197  */
1198  if ( ngeoms == 1 )
1199  {
1200  tmp = (GEOSGeometry *)GEOSGetGeometryN(geos_result, 0);
1201  if ( ! tmp )
1202  {
1203  GEOSGeom_destroy(geos_result);
1204  return 0; /* exception */
1205  }
1206  shp = GEOSGeom_clone(tmp);
1207  GEOSGeom_destroy(geos_result); /* only safe after the clone above */
1208  GEOSSetSRID(shp, srid);
1209  return shp;
1210  }
1211 
1212  LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
1213 
1214  /*
1215  * Polygonizer returns a polygon for each face in the built topology.
1216  *
1217  * This means that for any face with holes we'll have other faces
1218  * representing each hole. We can imagine a parent-child relationship
1219  * between these faces.
1220  *
1221  * In order to maximize the number of visible rings in output we
1222  * only use those faces which have an even number of parents.
1223  *
1224  * Example:
1225  *
1226  * +---------------+
1227  * | L0 | L0 has no parents
1228  * | +---------+ |
1229  * | | L1 | | L1 is an hole of L0
1230  * | | +---+ | |
1231  * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0)
1232  * | | | | | |
1233  * | | +---+ | |
1234  * | +---------+ |
1235  * | |
1236  * +---------------+
1237  *
1238  * See http://trac.osgeo.org/postgis/ticket/1806
1239  *
1240  */
1241 
1242 #ifdef LWGEOM_PROFILE_BUILDAREA
1243  lwnotice("Preparing face structures");
1244 #endif
1245 
1246  /* Prepare face structures for later analysis */
1247  geoms = lwalloc(sizeof(Face**)*ngeoms);
1248  for (i=0; i<ngeoms; ++i)
1249  geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
1250 
1251 #ifdef LWGEOM_PROFILE_BUILDAREA
1252  lwnotice("Finding face holes");
1253 #endif
1254 
1255  /* Find faces representing other faces holes */
1256  findFaceHoles(geoms, ngeoms);
1257 
1258 #ifdef LWGEOM_PROFILE_BUILDAREA
1259  lwnotice("Colletting even ancestor faces");
1260 #endif
1261 
1262  /* Build a MultiPolygon composed only by faces with an
1263  * even number of ancestors */
1264  tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
1265 
1266 #ifdef LWGEOM_PROFILE_BUILDAREA
1267  lwnotice("Cleaning up");
1268 #endif
1269 
1270  /* Cleanup face structures */
1271  for (i=0; i<ngeoms; ++i) delFace(geoms[i]);
1272  lwfree(geoms);
1273 
1274  /* Faces referenced memory owned by geos_result.
1275  * It is safe to destroy geos_result after deleting them. */
1276  GEOSGeom_destroy(geos_result);
1277 
1278 #ifdef LWGEOM_PROFILE_BUILDAREA
1279  lwnotice("Self-unioning");
1280 #endif
1281 
1282  /* Run a single overlay operation to dissolve shared edges */
1283  shp = GEOSUnionCascaded(tmp);
1284  if ( ! shp )
1285  {
1286  GEOSGeom_destroy(tmp);
1287  return 0; /* exception */
1288  }
1289 
1290 #ifdef LWGEOM_PROFILE_BUILDAREA
1291  lwnotice("Final cleanup");
1292 #endif
1293 
1294  GEOSGeom_destroy(tmp);
1295 
1296  GEOSSetSRID(shp, srid);
1297 
1298  return shp;
1299 }
static void delFace(Face *f)
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:61
void lwfree(void *mem)
Definition: lwutil.c:214
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:469
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:199
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:55
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:74
#define COLLECTIONTYPE
Definition: liblwgeom.h:76

Here is the call graph for this function:

Here is the caller graph for this function: