]> granicus.if.org Git - postgis/commitdiff
Fix invalid inputs for GEOS if it cannot process them
authorDarafei Praliaskouski <me@komzpa.net>
Wed, 7 Mar 2018 13:21:45 +0000 (13:21 +0000)
committerDarafei Praliaskouski <me@komzpa.net>
Wed, 7 Mar 2018 13:21:45 +0000 (13:21 +0000)
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

git-svn-id: http://svn.osgeo.org/postgis/trunk@16450 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
liblwgeom/lwgeom_geos.c
regress/tickets.sql
regress/tickets_expected

diff --git a/NEWS b/NEWS
index 24066b564374ae5230afb860d65b4b0ab8e8b759..66d4c7ccb7530adc72b2024266bafbe25199ac3d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,7 +14,7 @@ PostGIS 2.5.0
   - #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 @@ PostGIS 2.5.0
   - #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
index 254be6c4a2729305cc05c01d0fc42ad05f6632ff..963af7467afed232571ead65e8a02776471d12aa 100644 (file)
@@ -603,6 +603,24 @@ lwgeom_intersection(const LWGEOM* geom1, const LWGEOM* geom2)
 
        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 @@ lwgeom_difference(const LWGEOM* geom1, const LWGEOM* geom2)
 
        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 @@ lwgeom_symdifference(const LWGEOM* geom1, const LWGEOM* geom2)
 
        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 @@ lwgeom_union(const LWGEOM* geom1, const LWGEOM* geom2)
 
        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__))
index e65b0acbdb5bf05444d7a89d4c7a9c5042ea68e6..231d2a7091111bfbae038d02228d9e46b9e09869 100644 (file)
@@ -1075,5 +1075,11 @@ select '#4025', ST_DistanceCPA (
        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;
index e57d0900d85c79519d49b5d79557dca2dc7beecb..2e408435270b8dfa311a9820c24237225af3727c 100644 (file)
@@ -326,3 +326,23 @@ NOTICE:  Too few points in geometry component at or near point 0 0
 #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))