PostGIS  2.5.0beta2dev-r@@SVN_REVISION@@

◆ LWGEOM_GEOS_buildArea()

GEOSGeometry* LWGEOM_GEOS_buildArea ( const GEOSGeometry *  geom_in)

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

1105 {
1106  GEOSGeometry* tmp;
1107  GEOSGeometry *geos_result, *shp;
1108  GEOSGeometry const* vgeoms[1];
1109  uint32_t i, ngeoms;
1110  int srid = GEOSGetSRID(geom_in);
1111  Face** geoms;
1112 #if POSTGIS_DEBUG_LEVEL >= 3
1113  LWGEOM *geos_geom;
1114  char *geom_ewkt;
1115 #endif
1116 
1117  vgeoms[0] = geom_in;
1118  geos_result = GEOSPolygonize(vgeoms, 1);
1119 
1120  LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
1121 
1122  /* Null return from GEOSpolygonize (an exception) */
1123  if (!geos_result) return 0;
1124 
1125  /* We should now have a collection */
1126 #if PARANOIA_LEVEL > 0
1127  if (GEOSGeomTypeId(geos_result) != COLLECTIONTYPE)
1128  {
1129  GEOSGeom_destroy(geos_result);
1130  lwerror("%s [%d] Unexpected return from GEOSpolygonize", __FILE__, __LINE__);
1131  return 0;
1132  }
1133 #endif
1134 
1135  ngeoms = GEOSGetNumGeometries(geos_result);
1136 
1137 #if POSTGIS_DEBUG_LEVEL >= 3
1138  LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
1139  geos_geom = GEOS2LWGEOM(geos_result, 0);
1140  geom_ewkt = lwgeom_to_ewkt(geos_geom);
1141  LWDEBUGF(3, "GEOSpolygonize: polygonized:%s", geom_ewkt);
1142  lwgeom_free(geos_geom);
1143  lwfree(geom_ewkt);
1144 #endif
1145 
1146  /* No geometries in collection, early out */
1147  if (ngeoms == 0)
1148  {
1149  GEOSSetSRID(geos_result, srid);
1150  return geos_result;
1151  }
1152 
1153  /* Return first geometry if we only have one in collection, to avoid the unnecessary Geometry clone below. */
1154  if (ngeoms == 1)
1155  {
1156  tmp = (GEOSGeometry*)GEOSGetGeometryN(geos_result, 0);
1157  if (!tmp)
1158  {
1159  GEOSGeom_destroy(geos_result);
1160  return 0; /* exception */
1161  }
1162  shp = GEOSGeom_clone(tmp);
1163  GEOSGeom_destroy(geos_result); /* only safe after the clone above */
1164  GEOSSetSRID(shp, srid);
1165  return shp;
1166  }
1167 
1168  LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
1169 
1170  /*
1171  * Polygonizer returns a polygon for each face in the built topology.
1172  *
1173  * This means that for any face with holes we'll have other faces representing each hole. We can imagine a
1174  * parent-child relationship between these faces.
1175  *
1176  * In order to maximize the number of visible rings in output we only use those faces which have an even number
1177  * of parents.
1178  *
1179  * Example:
1180  *
1181  * +---------------+
1182  * | L0 | L0 has no parents
1183  * | +---------+ |
1184  * | | L1 | | L1 is an hole of L0
1185  * | | +---+ | |
1186  * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0)
1187  * | | | | | |
1188  * | | +---+ | |
1189  * | +---------+ |
1190  * | |
1191  * +---------------+
1192  *
1193  * See http://trac.osgeo.org/postgis/ticket/1806
1194  *
1195  */
1196 
1197  /* Prepare face structures for later analysis */
1198  geoms = lwalloc(sizeof(Face**) * ngeoms);
1199  for (i = 0; i < ngeoms; ++i)
1200  geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
1201 
1202  /* Find faces representing other faces holes */
1203  findFaceHoles(geoms, ngeoms);
1204 
1205  /* Build a MultiPolygon composed only by faces with an even number of ancestors */
1206  tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
1207 
1208  /* Cleanup face structures */
1209  for (i = 0; i < ngeoms; ++i)
1210  delFace(geoms[i]);
1211  lwfree(geoms);
1212 
1213  /* Faces referenced memory owned by geos_result. It is safe to destroy geos_result after deleting them. */
1214  GEOSGeom_destroy(geos_result);
1215 
1216  /* Run a single overlay operation to dissolve shared edges */
1217  shp = GEOSUnionCascaded(tmp);
1218  if (!shp)
1219  {
1220  GEOSGeom_destroy(tmp);
1221  return 0; /* exception */
1222  }
1223 
1224  GEOSGeom_destroy(tmp);
1225 
1226  GEOSSetSRID(shp, srid);
1227 
1228  return shp;
1229 }
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: