Commit 1277c750 authored by Darafei Praliaskouski's avatar Darafei Praliaskouski

ST_PointOnSurface handling of invalid.

Prints a loud notice and passes input through MakeValid.

Closes #4103
Closes https://github.com/postgis/postgis/pull/257



git-svn-id: http://svn.osgeo.org/postgis/trunk@16609 b70326c6-7e19-0410-871a-916f4a2858ee
parent 17f6c5c0
Pipeline #23243548 passed with stage
in 18 minutes and 32 seconds
......@@ -77,6 +77,7 @@ PostGIS 2.5.0
- #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
......
......@@ -2275,6 +2275,7 @@ LWGEOM *lwgeom_normalize(const LWGEOM *geom);
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);
......
......@@ -543,7 +543,7 @@ output_geos_as_lwgeom(GEOSGeometry** g, LWGEOM** geom, const int32_t srid, const
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 @@ geos_clean_and_fail(GEOSGeometry* g1, GEOSGeometry* g2, GEOSGeometry* g3, const
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 @@ lwgeom_centroid(const LWGEOM* geom)
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)
{
......
......@@ -1250,55 +1250,20 @@ Datum geos_difference(PG_FUNCTION_ARGS)
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);
}
initGEOS(lwpgnotice, lwgeom_geos_error);
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);
lwgeom = lwgeom_from_gserialized(geom);
lwresult = lwgeom_pointonsurface(lwgeom);
lwgeom_free(lwgeom);
PG_FREE_IF_COPY(geom, 0);
if (!lwresult) PG_RETURN_NULL();
result = geometry_serialize(lwresult);
lwgeom_free(lwresult);
PG_RETURN_POINTER(result);
}
......
......@@ -1088,5 +1088,8 @@ SELECT '#4055b', ST_SRID(unnest(ST_ClusterIntersecting(ARRAY['SRID=4326;POINT (3
--#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;
......@@ -349,3 +349,8 @@ NOTICE: Self-intersection
#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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment