PostGIS  2.5.0dev-r@@SVN_REVISION@@

◆ LWGEOM_GEOS_buildArea()

GEOSGeometry* LWGEOM_GEOS_buildArea ( const GEOSGeometry *  geom_in)

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

1061 {
1062  GEOSGeometry* tmp;
1063  GEOSGeometry *geos_result, *shp;
1064  GEOSGeometry const* vgeoms[1];
1065  uint32_t i, ngeoms;
1066  int srid = GEOSGetSRID(geom_in);
1067  Face** geoms;
1068 #if POSTGIS_DEBUG_LEVEL >= 3
1069  LWGEOM *geos_geom;
1070  char *geom_ewkt;
1071 #endif
1072 
1073  vgeoms[0] = geom_in;
1074  geos_result = GEOSPolygonize(vgeoms, 1);
1075 
1076  LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
1077 
1078  /* Null return from GEOSpolygonize (an exception) */
1079  if (!geos_result) return 0;
1080 
1081  /* We should now have a collection */
1082 #if PARANOIA_LEVEL > 0
1083  if (GEOSGeomTypeId(geos_result) != COLLECTIONTYPE)
1084  {
1085  GEOSGeom_destroy(geos_result);
1086  lwerror("%s [%d] Unexpected return from GEOSpolygonize", __FILE__, __LINE__);
1087  return 0;
1088  }
1089 #endif
1090 
1091  ngeoms = GEOSGetNumGeometries(geos_result);
1092 
1093 #if POSTGIS_DEBUG_LEVEL >= 3
1094  LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
1095  geos_geom = GEOS2LWGEOM(geos_result, 0);
1096  geom_ewkt = lwgeom_to_ewkt(geos_geom);
1097  LWDEBUGF(3, "GEOSpolygonize: polygonized:%s", geom_ewkt);
1098  lwgeom_free(geos_geom);
1099  lwfree(geom_ewkt);
1100 #endif
1101 
1102  /* No geometries in collection, early out */
1103  if (ngeoms == 0)
1104  {
1105  GEOSSetSRID(geos_result, srid);
1106  return geos_result;
1107  }
1108 
1109  /* Return first geometry if we only have one in collection, to avoid the unnecessary Geometry clone below. */
1110  if (ngeoms == 1)
1111  {
1112  tmp = (GEOSGeometry*)GEOSGetGeometryN(geos_result, 0);
1113  if (!tmp)
1114  {
1115  GEOSGeom_destroy(geos_result);
1116  return 0; /* exception */
1117  }
1118  shp = GEOSGeom_clone(tmp);
1119  GEOSGeom_destroy(geos_result); /* only safe after the clone above */
1120  GEOSSetSRID(shp, srid);
1121  return shp;
1122  }
1123 
1124  LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
1125 
1126  /*
1127  * Polygonizer returns a polygon for each face in the built topology.
1128  *
1129  * This means that for any face with holes we'll have other faces representing each hole. We can imagine a
1130  * parent-child relationship between these faces.
1131  *
1132  * In order to maximize the number of visible rings in output we only use those faces which have an even number
1133  * of parents.
1134  *
1135  * Example:
1136  *
1137  * +---------------+
1138  * | L0 | L0 has no parents
1139  * | +---------+ |
1140  * | | L1 | | L1 is an hole of L0
1141  * | | +---+ | |
1142  * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0)
1143  * | | | | | |
1144  * | | +---+ | |
1145  * | +---------+ |
1146  * | |
1147  * +---------------+
1148  *
1149  * See http://trac.osgeo.org/postgis/ticket/1806
1150  *
1151  */
1152 
1153  /* Prepare face structures for later analysis */
1154  geoms = lwalloc(sizeof(Face**) * ngeoms);
1155  for (i = 0; i < ngeoms; ++i)
1156  geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
1157 
1158  /* Find faces representing other faces holes */
1159  findFaceHoles(geoms, ngeoms);
1160 
1161  /* Build a MultiPolygon composed only by faces with an even number of ancestors */
1162  tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
1163 
1164  /* Cleanup face structures */
1165  for (i = 0; i < ngeoms; ++i)
1166  delFace(geoms[i]);
1167  lwfree(geoms);
1168 
1169  /* Faces referenced memory owned by geos_result. It is safe to destroy geos_result after deleting them. */
1170  GEOSGeom_destroy(geos_result);
1171 
1172  /* Run a single overlay operation to dissolve shared edges */
1173  shp = GEOSUnionCascaded(tmp);
1174  if (!shp)
1175  {
1176  GEOSGeom_destroy(tmp);
1177  return 0; /* exception */
1178  }
1179 
1180  GEOSGeom_destroy(tmp);
1181 
1182  GEOSSetSRID(shp, srid);
1183 
1184  return shp;
1185 }
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: