[postgis-tickets] r16450 - Fix invalid inputs for GEOS if it cannot process them

Darafei komzpa at gmail.com
Wed Mar 7 05:21:46 PST 2018


Author: komzpa
Date: 2018-03-07 05:21:45 -0800 (Wed, 07 Mar 2018)
New Revision: 16450

Modified:
   trunk/NEWS
   trunk/liblwgeom/lwgeom_geos.c
   trunk/regress/tickets.sql
   trunk/regress/tickets_expected
Log:
Fix invalid inputs for GEOS if it cannot process them

Invalid input geometry is fixed with MakeValid for GEOS exceptions in
ST_Intersection, ST_Union, ST_Difference, ST_SymDifference.

Closes #4037
Closes https://github.com/postgis/postgis/pull/228



Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2018-03-07 09:02:05 UTC (rev 16449)
+++ trunk/NEWS	2018-03-07 13:21:45 UTC (rev 16450)
@@ -14,7 +14,7 @@
   - #3885, version number removed from address_standardize lib file
   - #3893, raster support functions can only be loaded in the same schema
            with core PostGIS functions.
-  - #4035, remove dummy pgis_abs type from aggregate/collect routines. 
+  - #4035, remove dummy pgis_abs type from aggregate/collect routines.
 
 * Enhancements and Fixes*
   - #3944, Update to EPSG register v9.2 (Even Rouault)
@@ -43,6 +43,9 @@
   - #4020, Casting from box3d to geometry now returns correctly connected
            PolyhedralSurface (Matthias Bay)
   - #2508, ST_OffsetCurve now works with collections (Darafei Praliaskouski)
+  - #4037, Invalid input geometry is fixed with MakeValid for GEOS exceptions in
+           ST_Intersection, ST_Union, ST_Difference, ST_SymDifference (Darafei
+           Praliaskouski)
 
 PostGIS 2.4.0
 2017/09/30

Modified: trunk/liblwgeom/lwgeom_geos.c
===================================================================
--- trunk/liblwgeom/lwgeom_geos.c	2018-03-07 09:02:05 UTC (rev 16449)
+++ trunk/liblwgeom/lwgeom_geos.c	2018-03-07 13:21:45 UTC (rev 16450)
@@ -603,6 +603,24 @@
 
 	g3 = GEOSIntersection(g1, g2);
 
+	if (!g3)
+	{
+		GEOSGeometry *g1v, *g2v;
+		lwnotice("%s: GEOS Error: %s", __func__, lwgeom_geos_errmsg);
+
+		if (!GEOSisValid(g1) || !GEOSisValid(g2))
+		{
+			lwnotice(
+			    "Your geometry dataset is not valid per OGC Specification. "
+			    "Please fix it with manual review of entries that are not ST_IsValid(geom). "
+			    "Retrying GEOS operation with ST_MakeValid of your input.");
+			g1v = LWGEOM_GEOS_makeValid(g1);
+			g2v = LWGEOM_GEOS_makeValid(g2);
+			g3 = GEOSIntersection(g1v, g2v);
+			geos_clean(g1v, g2v, NULL);
+		}
+	}
+
 	if (!g3) return geos_clean_and_fail(g1, g2, NULL, __func__);
 
 	if (!output_geos_as_lwgeom(&g3, &result, srid, is3d, __func__))
@@ -695,6 +713,24 @@
 
 	g3 = GEOSDifference(g1, g2);
 
+	if (!g3)
+	{
+		GEOSGeometry *g1v, *g2v;
+		lwnotice("%s: GEOS Error: %s", __func__, lwgeom_geos_errmsg);
+
+		if (!GEOSisValid(g1) || !GEOSisValid(g2))
+		{
+			lwnotice(
+			    "Your geometry dataset is not valid per OGC Specification. "
+			    "Please fix it with manual review of entries that are not ST_IsValid(geom). "
+			    "Retrying GEOS operation with ST_MakeValid of your input.");
+			g1v = LWGEOM_GEOS_makeValid(g1);
+			g2v = LWGEOM_GEOS_makeValid(g2);
+			g3 = GEOSDifference(g1v, g2v);
+			geos_clean(g1v, g2v, NULL);
+		}
+	}
+
 	if (!g3) return geos_clean_and_fail(g1, g2, NULL, __func__);
 
 	if (!output_geos_as_lwgeom(&g3, &result, srid, is3d, __func__))
@@ -727,6 +763,24 @@
 
 	g3 = GEOSSymDifference(g1, g2);
 
+	if (!g3)
+	{
+		GEOSGeometry *g1v, *g2v;
+		lwnotice("%s: GEOS Error: %s", __func__, lwgeom_geos_errmsg);
+
+		if (!GEOSisValid(g1) || !GEOSisValid(g2))
+		{
+			lwnotice(
+			    "Your geometry dataset is not valid per OGC Specification. "
+			    "Please fix it with manual review of entries that are not ST_IsValid(geom). "
+			    "Retrying GEOS operation with ST_MakeValid of your input.");
+			g1v = LWGEOM_GEOS_makeValid(g1);
+			g2v = LWGEOM_GEOS_makeValid(g2);
+			g3 = GEOSSymDifference(g1v, g2v);
+			geos_clean(g1v, g2v, NULL);
+		}
+	}
+
 	if (!g3) return geos_clean_and_fail(g1, g2, NULL, __func__);
 
 	if (!output_geos_as_lwgeom(&g3, &result, srid, is3d, __func__))
@@ -791,6 +845,24 @@
 
 	g3 = GEOSUnion(g1, g2);
 
+	if (!g3)
+	{
+		GEOSGeometry *g1v, *g2v;
+		lwnotice("%s: GEOS Error: %s", __func__, lwgeom_geos_errmsg);
+
+		if (!GEOSisValid(g1) || !GEOSisValid(g2))
+		{
+			lwnotice(
+			    "Your geometry dataset is not valid per OGC Specification. "
+			    "Please fix it with manual review of entries that are not ST_IsValid(geom). "
+			    "Retrying GEOS operation with ST_MakeValid of your input.");
+			g1v = LWGEOM_GEOS_makeValid(g1);
+			g2v = LWGEOM_GEOS_makeValid(g2);
+			g3 = GEOSUnion(g1v, g2v);
+			geos_clean(g1v, g2v, NULL);
+		}
+	}
+
 	if (!g3) return geos_clean_and_fail(g1, g2, NULL, __func__);
 
 	if (!output_geos_as_lwgeom(&g3, &result, srid, is3d, __func__))

Modified: trunk/regress/tickets.sql
===================================================================
--- trunk/regress/tickets.sql	2018-03-07 09:02:05 UTC (rev 16449)
+++ trunk/regress/tickets.sql	2018-03-07 13:21:45 UTC (rev 16450)
@@ -1075,5 +1075,11 @@
 	2996311.81673704 5844916.90864168 1180471541.171)'::geometry
 	);
 
+-- a butterfly polygon in all cases
+SELECT '#4037.1', ST_AsText(ST_Intersection('POLYGON((0 0, 10 10, 0 10, 10 0, 0 0))', ST_MakeEnvelope(2,2,8,8)));
+SELECT '#4037.2', ST_AsText(ST_Difference('POLYGON((0 0, 10 10, 0 10, 10 0, 0 0))', ST_MakeEnvelope(2,2,8,8)));
+SELECT '#4037.3', ST_AsText(ST_SymDifference('POLYGON((0 0, 10 10, 0 10, 10 0, 0 0))', ST_MakeEnvelope(2,2,8,8)));
+SELECT '#4037.4', ST_AsText(ST_Union('POLYGON((0 0, 10 10, 0 10, 10 0, 0 0))', ST_MakeEnvelope(2,2,8,8)));
+
 -- Clean up
 DELETE FROM spatial_ref_sys;

Modified: trunk/regress/tickets_expected
===================================================================
--- trunk/regress/tickets_expected	2018-03-07 09:02:05 UTC (rev 16449)
+++ trunk/regress/tickets_expected	2018-03-07 13:21:45 UTC (rev 16450)
@@ -326,3 +326,23 @@
 #4011|ST_MultiLineString|MULTILINESTRING EMPTY|t|t
 #4011|ST_GeometryCollection|MULTILINESTRING((0 0,0 0))|f|f
 #4025|
+NOTICE:  lwgeom_intersection: GEOS Error: TopologyException: Input geom 0 is invalid: Self-intersection
+NOTICE:  Self-intersection
+NOTICE:  Your geometry dataset is not valid per OGC Specification. Please fix it with manual review of entries that are not ST_IsValid(geom). Retrying GEOS operation with ST_MakeValid of your input.
+NOTICE:  Self-intersection
+#4037.1|MULTIPOLYGON(((2 2,5 5,8 2,2 2)),((5 5,2 8,8 8,5 5)))
+NOTICE:  lwgeom_difference: GEOS Error: TopologyException: Input geom 0 is invalid: Self-intersection
+NOTICE:  Self-intersection
+NOTICE:  Your geometry dataset is not valid per OGC Specification. Please fix it with manual review of entries that are not ST_IsValid(geom). Retrying GEOS operation with ST_MakeValid of your input.
+NOTICE:  Self-intersection
+#4037.2|MULTIPOLYGON(((0 0,2 2,8 2,10 0,0 0)),((2 8,0 10,10 10,8 8,2 8)))
+NOTICE:  lwgeom_symdifference: GEOS Error: TopologyException: Input geom 0 is invalid: Self-intersection
+NOTICE:  Self-intersection
+NOTICE:  Your geometry dataset is not valid per OGC Specification. Please fix it with manual review of entries that are not ST_IsValid(geom). Retrying GEOS operation with ST_MakeValid of your input.
+NOTICE:  Self-intersection
+#4037.3|MULTIPOLYGON(((0 0,2 2,8 2,10 0,0 0)),((5 5,2 2,2 8,5 5)),((8 2,5 5,8 8,8 2)),((2 8,0 10,10 10,8 8,2 8)))
+NOTICE:  lwgeom_union: GEOS Error: TopologyException: Input geom 0 is invalid: Self-intersection
+NOTICE:  Self-intersection
+NOTICE:  Your geometry dataset is not valid per OGC Specification. Please fix it with manual review of entries that are not ST_IsValid(geom). Retrying GEOS operation with ST_MakeValid of your input.
+NOTICE:  Self-intersection
+#4037.4|POLYGON((0 0,2 2,2 8,0 10,10 10,8 8,8 2,10 0,0 0))



More information about the postgis-tickets mailing list