[postgis-tickets] r16676 - Make lwgeom_subdivide use lwgeom_intersection for clipping

Daniel Baston dbaston at gmail.com
Tue Jul 31 05:45:02 PDT 2018


Author: dbaston
Date: 2018-07-31 17:45:01 -0700 (Tue, 31 Jul 2018)
New Revision: 16676

Modified:
   trunk/liblwgeom/lwgeom.c
Log:
Make lwgeom_subdivide use lwgeom_intersection for clipping

lwgeom_clip_by_rect describes itself as clipping in a "fast but possibly
dirty way." This is not a good fit for lwgeom_subdivide, a primary use of
which is the optimization of point-in-polygon processes. That application
requires that the area covered by the subdivided geometry be the same as
the area covered by the original geometry, which in turn requires that a
robust intersection routine be used.

References #4038
Closes https://github.com/postgis/postgis/pull/281



Modified: trunk/liblwgeom/lwgeom.c
===================================================================
--- trunk/liblwgeom/lwgeom.c	2018-07-30 16:38:45 UTC (rev 16675)
+++ trunk/liblwgeom/lwgeom.c	2018-08-01 00:45:01 UTC (rev 16676)
@@ -2249,10 +2249,10 @@
 
 
 /* Prototype for recursion */
-static int lwgeom_subdivide_recursive(const LWGEOM *geom, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col);
+static int lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col);
 
 static int
-lwgeom_subdivide_recursive(const LWGEOM *geom, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col)
+lwgeom_subdivide_recursive(const LWGEOM *geom, uint8_t dimension, uint32_t maxvertices, uint32_t depth, LWCOLLECTION *col)
 {
 	const uint32_t maxdepth = 50;
 	GBOX clip, subbox1, subbox2;
@@ -2275,7 +2275,7 @@
 
 	if ( width == 0.0 && height == 0.0 )
 	{
-		if ( geom->type == POINTTYPE )
+		if ( geom->type == POINTTYPE && dimension == 0)
 		{
 			lwcollection_add_lwgeom(col, lwgeom_clone_deep(geom));
 			return 1;
@@ -2303,12 +2303,19 @@
 		LWCOLLECTION *incol = (LWCOLLECTION*)geom;
 		int n = 0;
 		/* Don't increment depth yet, since we aren't actually
-		 * subdividing geomtries yet */
+		 * subdividing geometries yet */
 		for ( i = 0; i < incol->ngeoms; i++ )
-			n += lwgeom_subdivide_recursive(incol->geoms[i], maxvertices, depth, col);
+			n += lwgeom_subdivide_recursive(incol->geoms[i], dimension, maxvertices, depth, col);
 		return n;
 	}
 
+	if (lwgeom_dimension(geom) < dimension)
+	{
+		/* We've hit a lower dimension object produced by clipping at
+		 * a shallower recursion level. Ignore it. */
+		return 0;
+	}
+
 	/* But don't go too far. 2^50 ~= 10^15, that's enough subdivision */
 	/* Just add what's left */
 	if ( depth > maxdepth )
@@ -2391,17 +2398,23 @@
 
 	++depth;
 
-	clipped = lwgeom_clip_by_rect(geom, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
+	LWGEOM* subbox = (LWGEOM*) lwpoly_construct_envelope(geom->srid, subbox1.xmin, subbox1.ymin, subbox1.xmax, subbox1.ymax);
+	clipped = lwgeom_intersection(geom, subbox);
+	lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
+	lwgeom_free(subbox);
 	if (clipped)
 	{
-		n += lwgeom_subdivide_recursive(clipped, maxvertices, depth, col);
+		n += lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
 		lwgeom_free(clipped);
 	}
 
-	clipped = lwgeom_clip_by_rect(geom, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
+	subbox = (LWGEOM*) lwpoly_construct_envelope(geom->srid, subbox2.xmin, subbox2.ymin, subbox2.xmax, subbox2.ymax);
+	clipped = lwgeom_intersection(geom, subbox);
+	lwgeom_simplify_in_place(clipped, 0.0, LW_TRUE);
+	lwgeom_free(subbox);
 	if (clipped)
 	{
-		n += lwgeom_subdivide_recursive(clipped, maxvertices, depth, col);
+		n += lwgeom_subdivide_recursive(clipped, dimension, maxvertices, depth, col);
 		lwgeom_free(clipped);
 	}
 
@@ -2426,7 +2439,7 @@
 		lwerror("%s: cannot subdivide to fewer than %d vertices per output", __func__, minmaxvertices);
 	}
 
-	lwgeom_subdivide_recursive(geom, maxvertices, startdepth, col);
+	lwgeom_subdivide_recursive(geom, lwgeom_dimension(geom), maxvertices, startdepth, col);
 	lwgeom_set_srid((LWGEOM*)col, geom->srid);
 	return col;
 }



More information about the postgis-tickets mailing list