[SCM] PostGIS branch master updated. 3.4.0rc1-746-g4f47efbd4

git at osgeo.org git at osgeo.org
Thu Nov 2 13:53:11 PDT 2023


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".

The branch, master has been updated
       via  4f47efbd4dbe144d61150e468d1756d4501ce078 (commit)
      from  f58ef013c354912e2aaa19f73cc594d3df03033a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 4f47efbd4dbe144d61150e468d1756d4501ce078
Author: Regina Obe <lr at pcorp.us>
Date:   Thu Nov 2 16:52:10 2023 -0400

    Remove GEOS 3.6, 3.7 supporting code
    Closes #5602 for PostGIS 3.5.0

diff --git a/NEWS b/NEWS
index f90510fe4..f472eb1d2 100644
--- a/NEWS
+++ b/NEWS
@@ -10,10 +10,14 @@ xxxx/xx/xx
               topology_id(tg1) <> topology_id(tg2) OR
               layer_id(tg1) <> layer_id(tg2) OR
               type(tg1) <> type(tg2)
-           )
+           ) (Sandro Santilli)
   - #5536, comments are not anymore included in PostGIS extensions
-  - xmllint is now required to build comments and documentation
+    (Sandro Santilli)
+  - xmllint is now required to build comments and 
+    (Sandro Santilli)
   - DocBook5 XSL is now required to build html documentation
+    (Sandro Santilli)
+  - #5602, Drop support for GEOS 3.6 and 3.7 (Regina Obe)
 
 * New Features *
 
diff --git a/configure.ac b/configure.ac
index d8f20e956..cd47d79be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -800,10 +800,10 @@ GEOS_NUMERIC_PATCH_VERSION=`printf "%02d" $GEOS_PATCH_VERSION`
 GEOS_NUMERIC_MINOR_VERSION=`printf "%02d" $GEOS_MINOR_VERSION`
 POSTGIS_GEOS_VERSION="$GEOS_MAJOR_VERSION$GEOS_NUMERIC_MINOR_VERSION$GEOS_NUMERIC_PATCH_VERSION"
 
-dnl Ensure that we are using GEOS >= 3.6.0
+dnl Ensure that we are using GEOS >= 3.8.0
 AC_MSG_RESULT([checking GEOS version... $GEOS_FULL_VERSION])
-if test ! "$POSTGIS_GEOS_VERSION" -ge 30600; then
-	AC_MSG_ERROR([PostGIS requires GEOS >= 3.6.0])
+if test ! "$POSTGIS_GEOS_VERSION" -ge 30800; then
+	AC_MSG_ERROR([PostGIS requires GEOS >= 3.8.0])
 fi
 
 dnl Extract the linker and include flags
diff --git a/liblwgeom/lwgeom_geos.c b/liblwgeom/lwgeom_geos.c
index 56b38b0be..094078a83 100644
--- a/liblwgeom/lwgeom_geos.c
+++ b/liblwgeom/lwgeom_geos.c
@@ -176,16 +176,11 @@ ptarray_from_GEOSCoordSeq(const GEOSCoordSequence* cs, uint8_t want3d)
 #else
 	for (i = 0; i < size; i++)
 	{
-#if POSTGIS_GEOS_VERSION < 30800
-		GEOSCoordSeq_getX(cs, i, &(point.x));
-		GEOSCoordSeq_getY(cs, i, &(point.y));
-		if (dims >= 3) GEOSCoordSeq_getZ(cs, i, &(point.z));
-#else
 		if (dims >= 3)
 			GEOSCoordSeq_getXYZ(cs, i, &(point.x), &(point.y), &(point.z));
 		else
 			GEOSCoordSeq_getXY(cs, i, &(point.x), &(point.y));
-#endif
+
 		ptarray_set_point4d(pa, i, &point);
 	}
 
@@ -331,16 +326,10 @@ ptarray_to_GEOSCoordSeq(const POINTARRAY* pa, uint8_t fix_ring)
 			LWDEBUGF(4, "Point: %g,%g", p2d->x, p2d->y);
 		}
 
-#if POSTGIS_GEOS_VERSION < 30800
-		GEOSCoordSeq_setX(sq, i, p2d->x);
-		GEOSCoordSeq_setY(sq, i, p2d->y);
-		if (dims == 3) GEOSCoordSeq_setZ(sq, i, p3d->z);
-#else
 		if (dims == 3)
 			GEOSCoordSeq_setXYZ(sq, i, p2d->x, p2d->y, p3d->z);
 		else
 			GEOSCoordSeq_setXY(sq, i, p2d->x, p2d->y);
-#endif
 
 	}
 
@@ -355,12 +344,8 @@ ptarray_to_GEOSCoordSeq(const POINTARRAY* pa, uint8_t fix_ring)
 			p2d = getPoint2d_cp(pa, 0);
 		for (i = pa->npoints; i < pa->npoints + append_points; i++)
 		{
-#if POSTGIS_GEOS_VERSION < 30800
-			GEOSCoordSeq_setX(sq, i, p2d->x);
-			GEOSCoordSeq_setY(sq, i, p2d->y);
-#else
+
 			GEOSCoordSeq_setXY(sq, i, p2d->x, p2d->y);
-#endif
 
 			if (dims == 3) GEOSCoordSeq_setZ(sq, i, p3d->z);
 		}
@@ -388,28 +373,11 @@ GBOX2GEOS(const GBOX* box)
 	GEOSCoordSequence* seq = GEOSCoordSeq_create(5, 2);
 	if (!seq) return NULL;
 
-#if POSTGIS_GEOS_VERSION < 30800
-	GEOSCoordSeq_setX(seq, 0, box->xmin);
-	GEOSCoordSeq_setY(seq, 0, box->ymin);
-
-	GEOSCoordSeq_setX(seq, 1, box->xmax);
-	GEOSCoordSeq_setY(seq, 1, box->ymin);
-
-	GEOSCoordSeq_setX(seq, 2, box->xmax);
-	GEOSCoordSeq_setY(seq, 2, box->ymax);
-
-	GEOSCoordSeq_setX(seq, 3, box->xmin);
-	GEOSCoordSeq_setY(seq, 3, box->ymax);
-
-	GEOSCoordSeq_setX(seq, 4, box->xmin);
-	GEOSCoordSeq_setY(seq, 4, box->ymin);
-#else
 	GEOSCoordSeq_setXY(seq, 0, box->xmin, box->ymin);
 	GEOSCoordSeq_setXY(seq, 1, box->xmax, box->ymin);
 	GEOSCoordSeq_setXY(seq, 2, box->xmax, box->ymax);
 	GEOSCoordSeq_setXY(seq, 3, box->xmin, box->ymax);
 	GEOSCoordSeq_setXY(seq, 4, box->xmin, box->ymin);
-#endif
 
 	ring = GEOSGeom_createLinearRing(seq);
 	if (!ring)
@@ -468,10 +436,6 @@ LWGEOM2GEOS(const LWGEOM* lwgeom, uint8_t autofix)
 			else
 			{
 				LWPOINT* lwp = (LWPOINT*)lwgeom;
-	#if POSTGIS_GEOS_VERSION < 30800
-				sq = ptarray_to_GEOSCoordSeq(lwp->point, 0);
-				g = GEOSGeom_createPoint(sq);
-	#else
 				if (lwgeom_has_z(lwgeom))
 				{
 					sq = ptarray_to_GEOSCoordSeq(lwp->point, 0);
@@ -482,7 +446,6 @@ LWGEOM2GEOS(const LWGEOM* lwgeom, uint8_t autofix)
 					const POINT2D* p = getPoint2d_cp(lwp->point, 0);
 					g = GEOSGeom_createPointFromXY(p->x, p->y);
 				}
-	#endif
 			}
 			if (!g) return NULL;
 			break;
@@ -628,12 +591,7 @@ make_geos_point(double x, double y)
 
 	if (!seq) return NULL;
 
-#if POSTGIS_GEOS_VERSION < 30800
-	GEOSCoordSeq_setX(seq, 0, x);
-	GEOSCoordSeq_setY(seq, 0, y);
-#else
 	GEOSCoordSeq_setXY(seq, 0, x, y);
-#endif
 
 	geom = GEOSGeom_createPoint(seq);
 	if (!geom) GEOSCoordSeq_destroy(seq);
@@ -648,15 +606,8 @@ make_geos_segment(double x1, double y1, double x2, double y2)
 
 	if (!seq) return NULL;
 
-#if POSTGIS_GEOS_VERSION < 30800
-	GEOSCoordSeq_setX(seq, 0, x1);
-	GEOSCoordSeq_setY(seq, 0, y1);
-	GEOSCoordSeq_setX(seq, 1, x2);
-	GEOSCoordSeq_setY(seq, 1, y2);
-#else
 	GEOSCoordSeq_setXY(seq, 0, x1, y1);
 	GEOSCoordSeq_setXY(seq, 1, x2, y2);
-#endif
 
 	geom = GEOSGeom_createLineString(seq);
 	if (!geom) GEOSCoordSeq_destroy(seq);
@@ -759,13 +710,7 @@ lwgeom_intersection_prec(const LWGEOM* geom1, const LWGEOM* geom2, double prec)
 	if (!(g2 = LWGEOM2GEOS(geom2, AUTOFIX))) GEOS_FREE_AND_FAIL(g1);
 
 	if ( prec >= 0) {
-#if POSTGIS_GEOS_VERSION < 30900
-		lwgeom_geos_error_minversion("Fixed-precision intersection", "3.9");
-		GEOS_FREE_AND_FAIL(g1, g2);
-		return NULL;
-#else
 		g3 = GEOSIntersectionPrec(g1, g2, prec);
-#endif
 	}
 	else
 	{
@@ -1169,254 +1114,6 @@ lwgeom_clip_by_rect(const LWGEOM *geom1, double x1, double y1, double x2, double
 }
 
 /* ------------ BuildArea stuff ---------------------------------------------------------------------{ */
-#if POSTGIS_GEOS_VERSION < 30800
-typedef struct Face_t
-{
-	const GEOSGeometry* geom;
-	GEOSGeometry* env;
-	double envarea;
-	struct Face_t* parent; /* if this face is an hole of another one, or NULL */
-} Face;
-
-static Face* newFace(const GEOSGeometry* g);
-static void delFace(Face* f);
-static unsigned int countParens(const Face* f);
-static void findFaceHoles(Face** faces, int nfaces);
-
-static Face*
-newFace(const GEOSGeometry* g)
-{
-	Face* f = lwalloc(sizeof(Face));
-	f->geom = g;
-	f->env = GEOSEnvelope(f->geom);
-	GEOSArea(f->env, &f->envarea);
-	f->parent = NULL;
-	return f;
-}
-
-static unsigned int
-countParens(const Face* f)
-{
-	unsigned int pcount = 0;
-	while (f->parent)
-	{
-		++pcount;
-		f = f->parent;
-	}
-	return pcount;
-}
-
-/* Destroy the face and release memory associated with it */
-static void
-delFace(Face* f)
-{
-	GEOSGeom_destroy(f->env);
-	lwfree(f);
-}
-
-static int
-compare_by_envarea(const void* g1, const void* g2)
-{
-	Face* f1 = *(Face**)g1;
-	Face* f2 = *(Face**)g2;
-	double n1 = f1->envarea;
-	double n2 = f2->envarea;
-
-	if (n1 < n2) return 1;
-	if (n1 > n2) return -1;
-	return 0;
-}
-
-/* Find holes of each face */
-static void
-findFaceHoles(Face** faces, int nfaces)
-{
-	int i, j, h;
-
-	/* We sort by envelope area so that we know holes are only after their shells */
-	qsort(faces, nfaces, sizeof(Face*), compare_by_envarea);
-	for (i = 0; i < nfaces; ++i)
-	{
-		Face* f = faces[i];
-		int nholes = GEOSGetNumInteriorRings(f->geom);
-		LWDEBUGF(2, "Scanning face %d with env area %g and %d holes", i, f->envarea, nholes);
-		for (h = 0; h < nholes; ++h)
-		{
-			const GEOSGeometry* hole = GEOSGetInteriorRingN(f->geom, h);
-			LWDEBUGF(2,
-				 "Looking for hole %d/%d of face %d among %d other faces",
-				 h + 1,
-				 nholes,
-				 i,
-				 nfaces - i - 1);
-			for (j = i + 1; j < nfaces; ++j)
-			{
-				const GEOSGeometry* f2er;
-				Face* f2 = faces[j];
-				if (f2->parent) continue; /* hole already assigned */
-				f2er = GEOSGetExteriorRing(f2->geom);
-				/* TODO: can be optimized as the ring would have the same vertices, possibly in
-				 * different order. Maybe comparing number of points could already be useful. */
-				if (GEOSEquals(f2er, hole))
-				{
-					LWDEBUGF(2, "Hole %d/%d of face %d is face %d", h + 1, nholes, i, j);
-					f2->parent = f;
-					break;
-				}
-			}
-		}
-	}
-}
-
-static GEOSGeometry*
-collectFacesWithEvenAncestors(Face** faces, int nfaces)
-{
-	GEOSGeometry** geoms = lwalloc(sizeof(GEOSGeometry*) * nfaces);
-	GEOSGeometry* ret;
-	unsigned int ngeoms = 0;
-	int i;
-
-	for (i = 0; i < nfaces; ++i)
-	{
-		Face* f = faces[i];
-		if (countParens(f) % 2) continue; /* we skip odd parents geoms */
-		geoms[ngeoms++] = GEOSGeom_clone(f->geom);
-	}
-
-	ret = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, geoms, ngeoms);
-	lwfree(geoms);
-	return ret;
-}
-
-GEOSGeometry*
-LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in)
-{
-	GEOSGeometry* tmp;
-	GEOSGeometry *geos_result, *shp;
-	GEOSGeometry const* vgeoms[1];
-	uint32_t i, ngeoms;
-	int srid = GEOSGetSRID(geom_in);
-	Face** geoms;
-#if POSTGIS_DEBUG_LEVEL >= 3
-	LWGEOM *geos_geom;
-	char *geom_ewkt;
-#endif
-
-	vgeoms[0] = geom_in;
-	geos_result = GEOSPolygonize(vgeoms, 1);
-
-	LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result);
-
-	/* Null return from GEOSpolygonize (an exception) */
-	if (!geos_result) return 0;
-
-		/* We should now have a collection */
-#if PARANOIA_LEVEL > 0
-	if (GEOSGeomTypeId(geos_result) != COLLECTIONTYPE)
-	{
-		GEOSGeom_destroy(geos_result);
-		lwerror("%s [%d] Unexpected return from GEOSpolygonize", __FILE__, __LINE__);
-		return 0;
-	}
-#endif
-
-	ngeoms = GEOSGetNumGeometries(geos_result);
-
-#if POSTGIS_DEBUG_LEVEL >= 3
-	LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms);
-	geos_geom = GEOS2LWGEOM(geos_result, 0);
-	geom_ewkt = lwgeom_to_ewkt(geos_geom);
-	LWDEBUGF(3, "GEOSpolygonize: polygonized:%s", geom_ewkt);
-	lwgeom_free(geos_geom);
-	lwfree(geom_ewkt);
-#endif
-
-	/* No geometries in collection, early out */
-	if (ngeoms == 0)
-	{
-		GEOSSetSRID(geos_result, srid);
-		return geos_result;
-	}
-
-	/* Return first geometry if we only have one in collection, to avoid the unnecessary Geometry clone below. */
-	if (ngeoms == 1)
-	{
-		tmp = (GEOSGeometry*)GEOSGetGeometryN(geos_result, 0);
-		if (!tmp)
-		{
-			GEOSGeom_destroy(geos_result);
-			return 0; /* exception */
-		}
-		shp = GEOSGeom_clone(tmp);
-		GEOSGeom_destroy(geos_result); /* only safe after the clone above */
-		GEOSSetSRID(shp, srid);
-		return shp;
-	}
-
-	LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms);
-
-	/*
-	 * Polygonizer returns a polygon for each face in the built topology.
-	 *
-	 * This means that for any face with holes we'll have other faces representing each hole. We can imagine a
-	 * parent-child relationship between these faces.
-	 *
-	 * In order to maximize the number of visible rings in output we only use those faces which have an even number
-	 * of parents.
-	 *
-	 * Example:
-	 *
-	 *   +---------------+
-	 *   |     L0        |  L0 has no parents
-	 *   |  +---------+  |
-	 *   |  |   L1    |  |  L1 is an hole of L0
-	 *   |  |  +---+  |  |
-	 *   |  |  |L2 |  |  |  L2 is an hole of L1 (which is an hole of L0)
-	 *   |  |  |   |  |  |
-	 *   |  |  +---+  |  |
-	 *   |  +---------+  |
-	 *   |               |
-	 *   +---------------+
-	 *
-	 * See http://trac.osgeo.org/postgis/ticket/1806
-	 *
-	 */
-
-	/* Prepare face structures for later analysis */
-	geoms = lwalloc(sizeof(Face**) * ngeoms);
-	for (i = 0; i < ngeoms; ++i)
-		geoms[i] = newFace(GEOSGetGeometryN(geos_result, i));
-
-	/* Find faces representing other faces holes */
-	findFaceHoles(geoms, ngeoms);
-
-	/* Build a MultiPolygon composed only by faces with an even number of ancestors */
-	tmp = collectFacesWithEvenAncestors(geoms, ngeoms);
-
-	/* Cleanup face structures */
-	for (i = 0; i < ngeoms; ++i)
-		delFace(geoms[i]);
-	lwfree(geoms);
-
-	/* Faces referenced memory owned by geos_result. It is safe to destroy geos_result after deleting them. */
-	GEOSGeom_destroy(geos_result);
-
-	/* Run a single overlay operation to dissolve shared edges */
-	shp = GEOSUnionCascaded(tmp);
-	if (!shp)
-	{
-		GEOSGeom_destroy(tmp);
-		return 0; /* exception */
-	}
-
-	GEOSGeom_destroy(tmp);
-
-	GEOSSetSRID(shp, srid);
-
-	return shp;
-}
-#endif
-
 LWGEOM*
 lwgeom_buildarea(const LWGEOM* geom)
 {
@@ -1434,11 +1131,7 @@ lwgeom_buildarea(const LWGEOM* geom)
 
 	if (!(g1 = LWGEOM2GEOS(geom, AUTOFIX))) GEOS_FAIL();
 
-#if POSTGIS_GEOS_VERSION < 30800
-	g3 = LWGEOM_GEOS_buildArea(g1);
-#else
 	g3 = GEOSBuildArea(g1);
-#endif
 
 	if (!g3) GEOS_FREE_AND_FAIL(g1);
 	GEOSSetSRID(g3, srid);
@@ -1832,12 +1525,8 @@ lwpoly_to_points(const LWPOLY* lwpoly, uint32_t npoints, int32_t seed)
 			if (x >= bbox.xmax || y >= bbox.ymax) continue;
 
 			gseq = GEOSCoordSeq_create(1, 2);
-#if POSTGIS_GEOS_VERSION < 30800
-			GEOSCoordSeq_setX(gseq, 0, x);
-			GEOSCoordSeq_setY(gseq, 0, y);
-#else
 			GEOSCoordSeq_setXY(gseq, 0, x, y);
-#endif
+
 			gpt = GEOSGeom_createPoint(gseq);
 
 			contains = GEOSPreparedIntersects(gprep, gpt);
diff --git a/liblwgeom/lwgeom_geos.h b/liblwgeom/lwgeom_geos.h
index bf2f94bf3..e1b278e0c 100644
--- a/liblwgeom/lwgeom_geos.h
+++ b/liblwgeom/lwgeom_geos.h
@@ -34,11 +34,6 @@
 LWGEOM* GEOS2LWGEOM(const GEOSGeometry* geom, uint8_t want3d);
 GEOSGeometry* LWGEOM2GEOS(const LWGEOM* g, uint8_t autofix);
 GEOSGeometry* GBOX2GEOS(const GBOX* g);
-#if POSTGIS_GEOS_VERSION < 30800
-GEOSGeometry* LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in);
-GEOSGeometry* LWGEOM_GEOS_makeValid(const GEOSGeometry*);
-#endif
-
 GEOSGeometry* make_geos_point(double x, double y);
 GEOSGeometry* make_geos_segment(double x1, double y1, double x2, double y2);
 
diff --git a/liblwgeom/lwgeom_geos_clean.c b/liblwgeom/lwgeom_geos_clean.c
index 91430d0b4..7eb1e907e 100644
--- a/liblwgeom/lwgeom_geos_clean.c
+++ b/liblwgeom/lwgeom_geos_clean.c
@@ -38,82 +38,6 @@
 /* #define PARANOIA_LEVEL 2 */
 #undef LWGEOM_PROFILE_MAKEVALID
 
-#if POSTGIS_GEOS_VERSION < 30800
-/*
- * Return Nth vertex in GEOSGeometry as a POINT.
- * May return NULL if the geometry has NO vertex.
- */
-GEOSGeometry* LWGEOM_GEOS_getPointN(const GEOSGeometry*, uint32_t);
-GEOSGeometry*
-LWGEOM_GEOS_getPointN(const GEOSGeometry* g_in, uint32_t n)
-{
-	uint32_t dims = 0;
-	const GEOSCoordSequence* seq_in;
-	GEOSCoordSeq seq_out;
-	double val;
-	uint32_t sz = 0;
-	int gn;
-	GEOSGeometry* ret;
-
-	switch (GEOSGeomTypeId(g_in))
-	{
-	case GEOS_MULTIPOINT:
-	case GEOS_MULTILINESTRING:
-	case GEOS_MULTIPOLYGON:
-	case GEOS_GEOMETRYCOLLECTION:
-	{
-		for (gn = 0; gn < GEOSGetNumGeometries(g_in); ++gn)
-		{
-			const GEOSGeometry* g = GEOSGetGeometryN(g_in, gn);
-			ret = LWGEOM_GEOS_getPointN(g, n);
-			if (ret) return ret;
-		}
-		break;
-	}
-
-	case GEOS_POLYGON:
-	{
-		ret = LWGEOM_GEOS_getPointN(GEOSGetExteriorRing(g_in), n);
-		if (ret) return ret;
-		for (gn = 0; gn < GEOSGetNumInteriorRings(g_in); ++gn)
-		{
-			const GEOSGeometry* g = GEOSGetInteriorRingN(g_in, gn);
-			ret = LWGEOM_GEOS_getPointN(g, n);
-			if (ret) return ret;
-		}
-		break;
-	}
-
-	case GEOS_POINT:
-	case GEOS_LINESTRING:
-	case GEOS_LINEARRING:
-		break;
-	}
-
-	seq_in = GEOSGeom_getCoordSeq(g_in);
-	if (!seq_in) return NULL;
-	if (!GEOSCoordSeq_getSize(seq_in, &sz)) return NULL;
-	if (!sz) return NULL;
-
-	if (!GEOSCoordSeq_getDimensions(seq_in, &dims)) return NULL;
-
-	seq_out = GEOSCoordSeq_create(1, dims);
-	if (!seq_out) return NULL;
-
-	if (!GEOSCoordSeq_getX(seq_in, n, &val)) return NULL;
-	if (!GEOSCoordSeq_setX(seq_out, n, val)) return NULL;
-	if (!GEOSCoordSeq_getY(seq_in, n, &val)) return NULL;
-	if (!GEOSCoordSeq_setY(seq_out, n, val)) return NULL;
-	if (dims > 2)
-	{
-		if (!GEOSCoordSeq_getZ(seq_in, n, &val)) return NULL;
-		if (!GEOSCoordSeq_setZ(seq_out, n, val)) return NULL;
-	}
-
-	return GEOSGeom_createPoint(seq_out);
-}
-#endif
-
 LWGEOM* lwcollection_make_geos_friendly(LWCOLLECTION* g);
 LWGEOM* lwline_make_geos_friendly(LWLINE* line);
 LWGEOM* lwpoly_make_geos_friendly(LWPOLY* poly);
@@ -361,539 +285,6 @@ lwcollection_make_geos_friendly(LWCOLLECTION* g)
 	return (LWGEOM*)ret;
 }
 
-#if POSTGIS_GEOS_VERSION < 30800
-
-/*
- * Fully node given linework
- */
-static GEOSGeometry*
-LWGEOM_GEOS_nodeLines(const GEOSGeometry* lines)
-{
-	/* GEOS3.7 GEOSNode fails on regression tests */
-	/* GEOS3.7 GEOSUnaryUnion fails on regression tests */
-
-	/* union of first point with geometry */
-	GEOSGeometry *unioned, *point;
-	point = LWGEOM_GEOS_getPointN(lines, 0);
-	if (!point) return NULL;
-	unioned = GEOSUnion(lines, point);
-	GEOSGeom_destroy(point);
-	return unioned;
-}
-
-/*
- * We expect initGEOS being called already.
- * Will return NULL on error (expect error handler being called by then)
- */
-static GEOSGeometry*
-LWGEOM_GEOS_makeValidPolygon(const GEOSGeometry* gin)
-{
-	GEOSGeom gout;
-	GEOSGeom geos_bound;
-	GEOSGeom geos_cut_edges, geos_area, collapse_points;
-	GEOSGeometry* vgeoms[3]; /* One for area, one for cut-edges */
-	unsigned int nvgeoms = 0;
-
-	assert(GEOSGeomTypeId(gin) == GEOS_POLYGON || GEOSGeomTypeId(gin) == GEOS_MULTIPOLYGON);
-
-	geos_bound = GEOSBoundary(gin);
-	if (!geos_bound) return NULL;
-
-	/* Use noded boundaries as initial "cut" edges */
-
-	geos_cut_edges = LWGEOM_GEOS_nodeLines(geos_bound);
-	if (!geos_cut_edges)
-	{
-		GEOSGeom_destroy(geos_bound);
-		lwnotice("LWGEOM_GEOS_nodeLines(): %s", lwgeom_geos_errmsg);
-		return NULL;
-	}
-
-	/* NOTE: the noding process may drop lines collapsing to points.
-	 *       We want to retrieve any of those */
-	{
-		GEOSGeometry* pi;
-		GEOSGeometry* po;
-
-		pi = GEOSGeom_extractUniquePoints(geos_bound);
-		if (!pi)
-		{
-			GEOSGeom_destroy(geos_bound);
-			lwnotice("GEOSGeom_extractUniquePoints(): %s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-
-		po = GEOSGeom_extractUniquePoints(geos_cut_edges);
-		if (!po)
-		{
-			GEOSGeom_destroy(geos_bound);
-			GEOSGeom_destroy(pi);
-			lwnotice("GEOSGeom_extractUniquePoints(): %s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-
-		collapse_points = GEOSDifference(pi, po);
-		if (!collapse_points)
-		{
-			GEOSGeom_destroy(geos_bound);
-			GEOSGeom_destroy(pi);
-			GEOSGeom_destroy(po);
-			lwnotice("GEOSDifference(): %s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-
-		GEOSGeom_destroy(pi);
-		GEOSGeom_destroy(po);
-	}
-	GEOSGeom_destroy(geos_bound);
-
-	/* And use an empty geometry as initial "area" */
-	geos_area = GEOSGeom_createEmptyPolygon();
-	if (!geos_area)
-	{
-		lwnotice("GEOSGeom_createEmptyPolygon(): %s", lwgeom_geos_errmsg);
-		GEOSGeom_destroy(geos_cut_edges);
-		return NULL;
-	}
-
-	/*
-	 * See if an area can be build with the remaining edges
-	 * and if it can, symdifference with the original area.
-	 * Iterate this until no more polygons can be created
-	 * with left-over edges.
-	 */
-	while (GEOSGetNumGeometries(geos_cut_edges))
-	{
-		GEOSGeometry* new_area = 0;
-		GEOSGeometry* new_area_bound = 0;
-		GEOSGeometry* symdif = 0;
-		GEOSGeometry* new_cut_edges = 0;
-
-#ifdef LWGEOM_PROFILE_MAKEVALID
-		lwnotice("ST_MakeValid: building area from %d edges", GEOSGetNumGeometries(geos_cut_edges));
-#endif
-
-		/*
-		 * ASSUMPTION: cut_edges should already be fully noded
-		 */
-
-		new_area = LWGEOM_GEOS_buildArea(geos_cut_edges);
-		if (!new_area) /* must be an exception */
-		{
-			GEOSGeom_destroy(geos_cut_edges);
-			GEOSGeom_destroy(geos_area);
-			lwnotice("LWGEOM_GEOS_buildArea() threw an error: %s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-
-		if (GEOSisEmpty(new_area))
-		{
-			/* no more rings can be build with thes edges */
-			GEOSGeom_destroy(new_area);
-			break;
-		}
-
-		/*
-		 * We succeeded in building a ring!
-		 * Save the new ring boundaries first (to compute
-		 * further cut edges later)
-		 */
-		new_area_bound = GEOSBoundary(new_area);
-		if (!new_area_bound)
-		{
-			/* We did check for empty area already so this must be some other error */
-			lwnotice("GEOSBoundary('%s') threw an error: %s",
-				 lwgeom_to_ewkt(GEOS2LWGEOM(new_area, 0)),
-				 lwgeom_geos_errmsg);
-			GEOSGeom_destroy(new_area);
-			GEOSGeom_destroy(geos_area);
-			return NULL;
-		}
-
-		/*
-		 * Now symdif new and old area
-		 */
-		symdif = GEOSSymDifference(geos_area, new_area);
-		if (!symdif) /* must be an exception */
-		{
-			GEOSGeom_destroy(geos_cut_edges);
-			GEOSGeom_destroy(new_area);
-			GEOSGeom_destroy(new_area_bound);
-			GEOSGeom_destroy(geos_area);
-			lwnotice("GEOSSymDifference() threw an error: %s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-
-		GEOSGeom_destroy(geos_area);
-		GEOSGeom_destroy(new_area);
-		geos_area = symdif;
-		symdif = 0;
-
-		/*
-		 * Now let's re-set geos_cut_edges with what's left
-		 * from the original boundary.
-		 * ASSUMPTION: only the previous cut-edges can be
-		 *             left, so we don't need to reconsider
-		 *             the whole original boundaries
-		 *
-		 * NOTE: this is an expensive operation.
-		 *
-		 */
-
-		new_cut_edges = GEOSDifference(geos_cut_edges, new_area_bound);
-		GEOSGeom_destroy(new_area_bound);
-		if (!new_cut_edges) /* an exception ? */
-		{
-			/* cleanup and throw */
-			GEOSGeom_destroy(geos_cut_edges);
-			GEOSGeom_destroy(geos_area);
-			lwerror("GEOSDifference() threw an error: %s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-		GEOSGeom_destroy(geos_cut_edges);
-		geos_cut_edges = new_cut_edges;
-	}
-
-	if (!GEOSisEmpty(geos_area))
-		vgeoms[nvgeoms++] = geos_area;
-	else
-		GEOSGeom_destroy(geos_area);
-
-	if (!GEOSisEmpty(geos_cut_edges))
-		vgeoms[nvgeoms++] = geos_cut_edges;
-	else
-		GEOSGeom_destroy(geos_cut_edges);
-
-	if (!GEOSisEmpty(collapse_points))
-		vgeoms[nvgeoms++] = collapse_points;
-	else
-		GEOSGeom_destroy(collapse_points);
-
-	if (1 == nvgeoms)
-	{
-		/* Return cut edges */
-		gout = vgeoms[0];
-	}
-	else
-	{
-		/* Collect areas and lines (if any line) */
-		gout = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, vgeoms, nvgeoms);
-		if (!gout) /* an exception again */
-		{
-			/* cleanup and throw */
-			lwerror("GEOSGeom_createCollection() threw an error: %s", lwgeom_geos_errmsg);
-			/* TODO: cleanup! */
-			return NULL;
-		}
-	}
-
-	return gout;
-}
-
-static GEOSGeometry*
-LWGEOM_GEOS_makeValidLine(const GEOSGeometry* gin)
-{
-	GEOSGeometry* noded;
-	noded = LWGEOM_GEOS_nodeLines(gin);
-	return noded;
-}
-
-static GEOSGeometry*
-LWGEOM_GEOS_makeValidMultiLine(const GEOSGeometry* gin)
-{
-	GEOSGeometry** lines;
-	GEOSGeometry** points;
-	GEOSGeometry* mline_out = 0;
-	GEOSGeometry* mpoint_out = 0;
-	GEOSGeometry* gout = 0;
-	uint32_t nlines = 0, nlines_alloc;
-	uint32_t npoints = 0;
-	uint32_t ngeoms = 0, nsubgeoms;
-	uint32_t i, j;
-
-	ngeoms = GEOSGetNumGeometries(gin);
-
-	nlines_alloc = ngeoms;
-	lines = lwalloc(sizeof(GEOSGeometry*) * nlines_alloc);
-	points = lwalloc(sizeof(GEOSGeometry*) * ngeoms);
-
-	for (i = 0; i < ngeoms; ++i)
-	{
-		const GEOSGeometry* g = GEOSGetGeometryN(gin, i);
-		GEOSGeometry* vg;
-		vg = LWGEOM_GEOS_makeValidLine(g);
-		/* Drop any invalid or empty geometry */
-		if (!vg)
-			continue;
-		if (GEOSisEmpty(vg))
-		{
-			GEOSGeom_destroy(vg);
-			continue;
-		}
-
-		if (GEOSGeomTypeId(vg) == GEOS_POINT)
-			points[npoints++] = vg;
-		else if (GEOSGeomTypeId(vg) == GEOS_LINESTRING)
-			lines[nlines++] = vg;
-		else if (GEOSGeomTypeId(vg) == GEOS_MULTILINESTRING)
-		{
-			nsubgeoms = GEOSGetNumGeometries(vg);
-			nlines_alloc += nsubgeoms;
-			lines = lwrealloc(lines, sizeof(GEOSGeometry*) * nlines_alloc);
-			for (j = 0; j < nsubgeoms; ++j)
-			{
-				const GEOSGeometry* gc = GEOSGetGeometryN(vg, j);
-				/* NOTE: ownership of the cloned geoms will be
-				 *       taken by final collection */
-				lines[nlines++] = GEOSGeom_clone(gc);
-			}
-		}
-		else
-		{
-			/* NOTE: return from GEOSGeomType will leak
-			 * but we really don't expect this to happen */
-			lwerror("unexpected geom type returned by LWGEOM_GEOS_makeValid: %s", GEOSGeomType(vg));
-		}
-	}
-
-	if (npoints)
-	{
-		if (npoints > 1)
-			mpoint_out = GEOSGeom_createCollection(GEOS_MULTIPOINT, points, npoints);
-		else
-			mpoint_out = points[0];
-	}
-
-	if (nlines)
-	{
-		if (nlines > 1)
-			mline_out = GEOSGeom_createCollection(GEOS_MULTILINESTRING, lines, nlines);
-		else
-			mline_out = lines[0];
-	}
-
-	lwfree(lines);
-
-	if (mline_out && mpoint_out)
-	{
-		points[0] = mline_out;
-		points[1] = mpoint_out;
-		gout = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, points, 2);
-	}
-	else if (mline_out)
-		gout = mline_out;
-
-	else if (mpoint_out)
-		gout = mpoint_out;
-
-	lwfree(points);
-
-	return gout;
-}
-
-/*
- * We expect initGEOS being called already.
- * Will return NULL on error (expect error handler being called by then)
- */
-static GEOSGeometry*
-LWGEOM_GEOS_makeValidCollection(const GEOSGeometry* gin)
-{
-	int nvgeoms;
-	GEOSGeometry** vgeoms;
-	GEOSGeom gout;
-	int i;
-
-	nvgeoms = GEOSGetNumGeometries(gin);
-	if (nvgeoms == -1)
-	{
-		lwerror("GEOSGetNumGeometries: %s", lwgeom_geos_errmsg);
-		return 0;
-	}
-
-	vgeoms = lwalloc(sizeof(GEOSGeometry*) * nvgeoms);
-	if (!vgeoms)
-	{
-		lwerror("LWGEOM_GEOS_makeValidCollection: out of memory");
-		return 0;
-	}
-
-	for (i = 0; i < nvgeoms; ++i)
-	{
-		vgeoms[i] = LWGEOM_GEOS_makeValid(GEOSGetGeometryN(gin, i));
-		if (!vgeoms[i])
-		{
-			int j;
-			for (j = 0; j < i - 1; j++)
-				GEOSGeom_destroy(vgeoms[j]);
-			lwfree(vgeoms);
-			/* we expect lwerror being called already by makeValid */
-			return NULL;
-		}
-	}
-
-	/* Collect areas and lines (if any line) */
-	gout = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, vgeoms, nvgeoms);
-	if (!gout) /* an exception again */
-	{
-		/* cleanup and throw */
-		for (i = 0; i < nvgeoms; ++i)
-			GEOSGeom_destroy(vgeoms[i]);
-		lwfree(vgeoms);
-		lwerror("GEOSGeom_createCollection() threw an error: %s", lwgeom_geos_errmsg);
-		return NULL;
-	}
-	lwfree(vgeoms);
-
-	return gout;
-}
-
-GEOSGeometry*
-LWGEOM_GEOS_makeValid(const GEOSGeometry* gin)
-{
-	GEOSGeometry* gout;
-	char ret_char;
-#if POSTGIS_DEBUG_LEVEL >= 3
-	LWGEOM *geos_geom;
-	char *geom_ewkt;
-#endif
-
-	/*
-	 * Step 2: return what we got so far if already valid
-	 */
-
-	ret_char = GEOSisValid(gin);
-	if (ret_char == 2)
-	{
-		/* I don't think should ever happen */
-		lwerror("GEOSisValid(): %s", lwgeom_geos_errmsg);
-		return NULL;
-	}
-	else if (ret_char)
-	{
-#if POSTGIS_DEBUG_LEVEL >= 3
-		geos_geom = GEOS2LWGEOM(gin, 0);
-		geom_ewkt = lwgeom_to_ewkt(geos_geom);
-		LWDEBUGF(3, "Geometry [%s] is valid. ", geom_ewkt);
-		lwgeom_free(geos_geom);
-		lwfree(geom_ewkt);
-#endif
-
-		/* It's valid at this step, return what we have */
-		return GEOSGeom_clone(gin);
-	}
-
-#if POSTGIS_DEBUG_LEVEL >= 3
-	geos_geom = GEOS2LWGEOM(gin, 0);
-	geom_ewkt = lwgeom_to_ewkt(geos_geom);
-	LWDEBUGF(3,
-		 "Geometry [%s] is still not valid: %s. Will try to clean up further.",
-		 geom_ewkt,
-		 lwgeom_geos_errmsg);
-	lwgeom_free(geos_geom);
-	lwfree(geom_ewkt);
-#endif
-
-	/*
-	 * Step 3 : make what we got valid
-	 */
-
-	switch (GEOSGeomTypeId(gin))
-	{
-	case GEOS_MULTIPOINT:
-	case GEOS_POINT:
-		/* points are always valid, but we might have invalid ordinate values */
-		lwnotice("PUNTUAL geometry resulted invalid to GEOS -- dunno how to clean that up");
-		return NULL;
-		break;
-
-	case GEOS_LINESTRING:
-		gout = LWGEOM_GEOS_makeValidLine(gin);
-		if (!gout) /* an exception or something */
-		{
-			/* cleanup and throw */
-			lwerror("%s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-		break; /* we've done */
-
-	case GEOS_MULTILINESTRING:
-		gout = LWGEOM_GEOS_makeValidMultiLine(gin);
-		if (!gout) /* an exception or something */
-		{
-			/* cleanup and throw */
-			lwerror("%s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-		break; /* we've done */
-
-	case GEOS_POLYGON:
-	case GEOS_MULTIPOLYGON:
-	{
-		gout = LWGEOM_GEOS_makeValidPolygon(gin);
-		if (!gout) /* an exception or something */
-		{
-			/* cleanup and throw */
-			lwerror("%s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-		break; /* we've done */
-	}
-
-	case GEOS_GEOMETRYCOLLECTION:
-	{
-		gout = LWGEOM_GEOS_makeValidCollection(gin);
-		if (!gout) /* an exception or something */
-		{
-			/* cleanup and throw */
-			lwerror("%s", lwgeom_geos_errmsg);
-			return NULL;
-		}
-		break; /* we've done */
-	}
-
-	default:
-	{
-		char* typname = GEOSGeomType(gin);
-		lwnotice("ST_MakeValid: doesn't support geometry type: %s", typname);
-		GEOSFree(typname);
-		return NULL;
-		break;
-	}
-	}
-
-#if PARANOIA_LEVEL > 1
-	/*
-	 * Now check if every point of input is also found in output, or abort by returning NULL
-	 *
-	 * Input geometry was lwgeom_in
-	 */
-	{
-		int loss;
-		GEOSGeometry *pi, *po, *pd;
-
-		/* TODO: handle some errors here...
-		 * Lack of exceptions is annoying indeed,
-		 * I'm getting old --strk;
-		 */
-		pi = GEOSGeom_extractUniquePoints(gin);
-		po = GEOSGeom_extractUniquePoints(gout);
-		pd = GEOSDifference(pi, po); /* input points - output points */
-		GEOSGeom_destroy(pi);
-		GEOSGeom_destroy(po);
-		loss = pd && !GEOSisEmpty(pd);
-		GEOSGeom_destroy(pd);
-		if (loss)
-		{
-			lwnotice("%s [%d] Vertices lost in LWGEOM_GEOS_makeValid", __FILE__, __LINE__);
-			/* return NULL */
-		}
-	}
-#endif /* PARANOIA_LEVEL > 1 */
-
-	return gout;
-}
-#endif
-
 /* Exported. Uses GEOS internally */
 LWGEOM*
 lwgeom_make_valid(LWGEOM* lwgeom_in)
@@ -940,9 +331,7 @@ lwgeom_make_valid_params(LWGEOM* lwgeom_in, char* make_valid_params)
 		LWDEBUG(4, "geom converted to GEOS");
 	}
 
-#if POSTGIS_GEOS_VERSION < 30800
-	geosout = LWGEOM_GEOS_makeValid(geosgeom);
-#elif POSTGIS_GEOS_VERSION < 31000
+#if POSTGIS_GEOS_VERSION < 31000
 	geosout = GEOSMakeValid(geosgeom);
 #else
 	if (!make_valid_params) {
diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c
index 900c561e7..43d5cfd63 100644
--- a/postgis/lwgeom_geos.c
+++ b/postgis/lwgeom_geos.c
@@ -271,15 +271,6 @@ Datum hausdorffdistancedensify(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(ST_FrechetDistance);
 Datum ST_FrechetDistance(PG_FUNCTION_ARGS)
 {
-#if POSTGIS_GEOS_VERSION < 30700
-
-	lwpgerror("The GEOS version this PostGIS binary "
-					"was compiled against (%d) doesn't support "
-					"'GEOSFechetDistance' function (3.7.0+ required)",
-					POSTGIS_GEOS_VERSION);
-	PG_RETURN_NULL();
-
-#else /* POSTGIS_GEOS_VERSION >= 30700 */
 	GSERIALIZED *geom1;
 	GSERIALIZED *geom2;
 	GEOSGeometry *g1;
@@ -326,8 +317,6 @@ Datum ST_FrechetDistance(PG_FUNCTION_ARGS)
 	PG_FREE_IF_COPY(geom2, 1);
 
 	PG_RETURN_FLOAT8(result);
-
-#endif /* POSTGIS_GEOS_VERSION >= 30700 */
 }
 
 
diff --git a/postgis/lwgeom_window.c b/postgis/lwgeom_window.c
index 1132daa84..16411a65b 100644
--- a/postgis/lwgeom_window.c
+++ b/postgis/lwgeom_window.c
@@ -465,7 +465,6 @@ Datum ST_ClusterKMeans(PG_FUNCTION_ARGS)
  *
  */
 
-#if POSTGIS_GEOS_VERSION >= 30800
 /*
  * For CoverageUnion and CoverageSimplify, clean up
  * the start of a collection if things fail in mid-stream.
@@ -481,7 +480,6 @@ coverage_destroy_geoms(GEOSGeometry **geoms, uint32 ngeoms)
 			GEOSGeom_destroy(geoms[i]);
 	}
 }
-#endif
 
 #if POSTGIS_GEOS_VERSION >= 31200
 
@@ -795,15 +793,6 @@ Datum ST_CoverageUnion(PG_FUNCTION_ARGS);
 PG_FUNCTION_INFO_V1(ST_CoverageUnion);
 Datum ST_CoverageUnion(PG_FUNCTION_ARGS)
 {
-#if POSTGIS_GEOS_VERSION < 30800
-	lwpgerror("The GEOS version this PostGIS binary "
-		"was compiled against (%d) doesn't support "
-		"'GEOSCoverageUnion' function (3.8.0+ required)",
-		POSTGIS_GEOS_VERSION);
-	PG_RETURN_NULL();
-
-#else /* POSTGIS_GEOS_VERSION >= 30800 */
-
 	GSERIALIZED *result = NULL;
 
 	Datum value;
@@ -867,7 +856,6 @@ Datum ST_CoverageUnion(PG_FUNCTION_ARGS)
 	GEOSGeom_destroy(geos_result);
 
 	PG_RETURN_POINTER(result);
-#endif
 }
 
 
diff --git a/regress/core/tests.mk.in b/regress/core/tests.mk.in
index 3cd590e98..2e872af78 100644
--- a/regress/core/tests.mk.in
+++ b/regress/core/tests.mk.in
@@ -43,9 +43,11 @@ TESTS += \
 	$(top_srcdir)/regress/core/estimatedextent \
 	$(top_srcdir)/regress/core/forcecurve \
 	$(top_srcdir)/regress/core/flatgeobuf \
+	$(top_srcdir)/regress/core/frechet \
 	$(top_srcdir)/regress/core/geography \
 	$(top_srcdir)/regress/core/geometric_median \
   $(top_srcdir)/regress/core/geos_noop \
+	$(top_srcdir)/regress/core/geos38 \
 	$(top_srcdir)/regress/core/hausdorff \
 	$(top_srcdir)/regress/core/in_flatgeobuf \
 	$(top_srcdir)/regress/core/in_geohash \
@@ -146,19 +148,6 @@ TESTS_SLOW = \
 	$(top_srcdir)/regress/core/concave_hull_hard \
 	$(top_srcdir)/regress/core/knn_recheck
 
-ifeq ($(shell expr "$(POSTGIS_GEOS_VERSION)" ">=" 30700),1)
-	# GEOS-3.7 adds:
-	# ST_FrechetDistance
-	TESTS += \
-		$(top_srcdir)/regress/core/frechet
-endif
-
-ifeq ($(shell expr "$(POSTGIS_GEOS_VERSION)" ">=" 30800),1)
-	# GEOS-3.8 adds stable pointonsurface implementation
-	TESTS += \
-		$(top_srcdir)/regress/core/geos38
-endif
-
 ifeq ($(shell expr "$(POSTGIS_GEOS_VERSION)" ">=" 30900),1)
 	# GEOS-3.9 adds stable maximuminscribedcircle implementation
 	TESTS += \

-----------------------------------------------------------------------

Summary of changes:
 NEWS                          |   8 +-
 configure.ac                  |   6 +-
 liblwgeom/lwgeom_geos.c       | 317 +---------------------
 liblwgeom/lwgeom_geos.h       |   5 -
 liblwgeom/lwgeom_geos_clean.c | 613 +-----------------------------------------
 postgis/lwgeom_geos.c         |  11 -
 postgis/lwgeom_window.c       |  12 -
 regress/core/tests.mk.in      |  15 +-
 8 files changed, 15 insertions(+), 972 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list