[postgis-tickets] r16609 - ST_PointOnSurface handling of invalid.
Darafei
komzpa at gmail.com
Tue Jun 5 10:11:34 PDT 2018
Author: komzpa
Date: 2018-06-05 10:11:34 -0700 (Tue, 05 Jun 2018)
New Revision: 16609
Modified:
trunk/NEWS
trunk/liblwgeom/liblwgeom.h.in
trunk/liblwgeom/lwgeom_geos.c
trunk/postgis/lwgeom_geos.c
trunk/regress/tickets.sql
trunk/regress/tickets_expected
Log:
ST_PointOnSurface handling of invalid.
Prints a loud notice and passes input through MakeValid.
Closes #4103
Closes https://github.com/postgis/postgis/pull/257
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2018-06-05 14:40:45 UTC (rev 16608)
+++ trunk/NEWS 2018-06-05 17:11:34 UTC (rev 16609)
@@ -77,6 +77,7 @@
- #4084: Fixed wrong code-comment regarding front/back of BOX3D (Matthias Bay)
- #4060, #4094, PostgreSQL JIT support (Raúl Marín, Laurenz Albe)
- #3960, ST_Centroid now uses lwgeom_centroid (Darafei Praliaskouski)
+ - #4103, ST_PointOnSurface can handle invalid (Darafei Praliaskouski)
PostGIS 2.4.4
2018/04/08
Modified: trunk/liblwgeom/liblwgeom.h.in
===================================================================
--- trunk/liblwgeom/liblwgeom.h.in 2018-06-05 14:40:45 UTC (rev 16608)
+++ trunk/liblwgeom/liblwgeom.h.in 2018-06-05 17:11:34 UTC (rev 16609)
@@ -2275,6 +2275,7 @@
LWGEOM *lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2);
LWGEOM *lwgeom_difference(const LWGEOM *geom1, const LWGEOM *geom2);
LWGEOM *lwgeom_symdifference(const LWGEOM* geom1, const LWGEOM* geom2);
+LWGEOM *lwgeom_pointonsurface(const LWGEOM* geom);
LWGEOM *lwgeom_centroid(const LWGEOM* geom);
LWGEOM *lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2);
LWGEOM *lwgeom_linemerge(const LWGEOM *geom1);
Modified: trunk/liblwgeom/lwgeom_geos.c
===================================================================
--- trunk/liblwgeom/lwgeom_geos.c 2018-06-05 14:40:45 UTC (rev 16608)
+++ trunk/liblwgeom/lwgeom_geos.c 2018-06-05 17:11:34 UTC (rev 16609)
@@ -543,7 +543,7 @@
return LW_TRUE;
}
-/* Output encoder and sanity checker for GEOS wrappers */
+/* Clean up and return NULL */
inline static LWGEOM*
geos_clean_and_fail(GEOSGeometry* g1, GEOSGeometry* g2, GEOSGeometry* g3, const char* funcname)
{
@@ -554,7 +554,7 @@
return NULL;
}
-/* Output encoder and sanity checker for GEOS wrappers */
+/* Clean up */
inline static void
geos_clean(GEOSGeometry* g1, GEOSGeometry* g2, GEOSGeometry* g3)
{
@@ -829,6 +829,55 @@
return result;
}
+LWGEOM *
+lwgeom_pointonsurface(const LWGEOM *geom)
+{
+ LWGEOM *result;
+ int32_t srid = get_result_srid(geom, NULL, __func__);
+ uint8_t is3d = FLAGS_GET_Z(geom->flags);
+ GEOSGeometry *g1, *g3;
+
+ if (srid == SRID_INVALID) return NULL;
+
+ if (lwgeom_is_empty(geom))
+ {
+ LWPOINT *lwp = lwpoint_construct_empty(srid, is3d, lwgeom_has_m(geom));
+ return lwpoint_as_lwgeom(lwp);
+ }
+
+ initGEOS(lwnotice, lwgeom_geos_error);
+
+ if (!input_lwgeom_to_geos(&g1, geom, __func__)) return NULL;
+
+ g3 = GEOSPointOnSurface(g1);
+
+ if (!g3)
+ {
+ GEOSGeometry *g1v;
+ lwnotice("%s: GEOS Error: %s", __func__, lwgeom_geos_errmsg);
+
+ if (!GEOSisValid(g1))
+ {
+ 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);
+ g3 = GEOSPointOnSurface(g1v);
+ geos_clean(g1v, NULL, NULL);
+ }
+ }
+
+ if (!g3) return geos_clean_and_fail(g1, NULL, NULL, __func__);
+
+ if (!output_geos_as_lwgeom(&g3, &result, srid, is3d, __func__))
+ return geos_clean_and_fail(g1, NULL, g3, __func__);
+
+ geos_clean(g1, NULL, g3);
+
+ return result;
+}
+
LWGEOM*
lwgeom_union(const LWGEOM* geom1, const LWGEOM* geom2)
{
Modified: trunk/postgis/lwgeom_geos.c
===================================================================
--- trunk/postgis/lwgeom_geos.c 2018-06-05 14:40:45 UTC (rev 16608)
+++ trunk/postgis/lwgeom_geos.c 2018-06-05 17:11:34 UTC (rev 16609)
@@ -1250,55 +1250,20 @@
PG_FUNCTION_INFO_V1(pointonsurface);
Datum pointonsurface(PG_FUNCTION_ARGS)
{
- GSERIALIZED *geom;
- GEOSGeometry *g1, *g3;
- GSERIALIZED *result;
+ GSERIALIZED *geom, *result;
+ LWGEOM *lwgeom, *lwresult;
geom = PG_GETARG_GSERIALIZED_P(0);
- /* Empty.PointOnSurface == Point Empty */
- if ( gserialized_is_empty(geom) )
- {
- LWPOINT *lwp = lwpoint_construct_empty(
- gserialized_get_srid(geom),
- gserialized_has_z(geom),
- gserialized_has_m(geom));
- result = geometry_serialize(lwpoint_as_lwgeom(lwp));
- lwpoint_free(lwp);
- PG_RETURN_POINTER(result);
- }
+ lwgeom = lwgeom_from_gserialized(geom);
+ lwresult = lwgeom_pointonsurface(lwgeom);
+ lwgeom_free(lwgeom);
+ PG_FREE_IF_COPY(geom, 0);
- initGEOS(lwpgnotice, lwgeom_geos_error);
+ if (!lwresult) PG_RETURN_NULL();
- g1 = POSTGIS2GEOS(geom);
-
- if (!g1) HANDLE_GEOS_ERROR(__func__);
-
- g3 = GEOSPointOnSurface(g1);
-
- if (!g3)
- {
- GEOSGeom_destroy(g1);
- HANDLE_GEOS_ERROR("GEOSPointOnSurface");
- }
-
- GEOSSetSRID(g3, gserialized_get_srid(geom));
-
- result = GEOS2POSTGIS(g3, gserialized_has_z(geom));
-
- if (!result)
- {
- GEOSGeom_destroy(g1);
- GEOSGeom_destroy(g3);
- elog(ERROR,"GEOS pointonsurface() threw an error (result postgis geometry formation)!");
- PG_RETURN_NULL(); /* never get here */
- }
-
- GEOSGeom_destroy(g1);
- GEOSGeom_destroy(g3);
-
- PG_FREE_IF_COPY(geom, 0);
-
+ result = geometry_serialize(lwresult);
+ lwgeom_free(lwresult);
PG_RETURN_POINTER(result);
}
Modified: trunk/regress/tickets.sql
===================================================================
--- trunk/regress/tickets.sql 2018-06-05 14:40:45 UTC (rev 16608)
+++ trunk/regress/tickets.sql 2018-06-05 17:11:34 UTC (rev 16609)
@@ -1088,5 +1088,8 @@
--#4089
select '#4089', st_astext(st_geomfromtwkb(st_AsTWKB(st_GeometryFromText('LINESTRING Z(1 1 1, 3 3 1)'), 1, 0, 0, false, true)));
+select '#4103', ST_Intersects(ST_PointOnSurface(geom), geom)
+from (select '0103000020110F0000010000000A000000000000C41E644741000000EEA2A75A41000000F420644741000000629EA75A410000007A2D644741000000E49FA75A41000000C02E644741000000409DA75A41000000286A64474100000064A4A75A410000007867644741000000FAA9A75A41000000E82B644741000000D2A2A75A41000000222D64474100000046A0A75A41000000242B6447410000006CA4A75A41000000C41E644741000000EEA2A75A41'::geometry geom) z;
+
-- Clean up
DELETE FROM spatial_ref_sys;
Modified: trunk/regress/tickets_expected
===================================================================
--- trunk/regress/tickets_expected 2018-06-05 14:40:45 UTC (rev 16608)
+++ trunk/regress/tickets_expected 2018-06-05 17:11:34 UTC (rev 16609)
@@ -349,3 +349,8 @@
#4055a|4326
#4055b|4326
#4089|LINESTRING Z (1 1 1,3 3 1)
+NOTICE: lwgeom_pointonsurface: GEOS Error: TopologyException: Input geom 1 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
+#4103|t
More information about the postgis-tickets
mailing list