From ebc424f290348d56fbd53c06438d18c69d55e120 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Tue, 2 Mar 2010 21:32:09 +0000 Subject: [PATCH] ST_MakeValid : turn collapsed lines into points [RT-SIGTA] git-svn-id: http://svn.osgeo.org/postgis/trunk@5363 b70326c6-7e19-0410-871a-916f4a2858ee --- postgis/lwgeom_geos_clean.c | 102 +++++++++++++++++++++++++++++++++++- regress/clean.sql | 3 +- regress/clean_expected | 1 + 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/postgis/lwgeom_geos_clean.c b/postgis/lwgeom_geos_clean.c index 998a36157..2c8a613f2 100644 --- a/postgis/lwgeom_geos_clean.c +++ b/postgis/lwgeom_geos_clean.c @@ -581,6 +581,95 @@ LWGEOM_GEOS_makeValidLine(const GEOSGeometry* gin) return noded; } +static GEOSGeometry* +LWGEOM_GEOS_makeValidMultiLine(const GEOSGeometry* gin) +{ + GEOSGeometry** lines; + GEOSGeometry** points; + GEOSGeometry* mline_out=0; + GEOSGeometry* mpoint_out=0; + GEOSGeometry* gout; + unsigned int nlines; + unsigned int npoints=0; + unsigned int ngeoms=0; + unsigned int i; + + ngeoms = GEOSGetNumGeometries(gin); + + lines = lwalloc(sizeof(GEOSGeometry*)*ngeoms); + points = lwalloc(sizeof(GEOSGeometry*)*ngeoms); + + for (i=0; i 1 ) { + mpoint_out = GEOSGeom_createCollection(GEOS_MULTIPOINT, + points, npoints); + } else { + mpoint_out = points[0]; + } + } + + if ( nlines ) + { + if ( nlines > 1 ) { + mline_out = GEOSGeom_createCollection( + GEOS_MULTILINESTRING, lines, nlines); + } else { + mline_out = lines[0]; + } + } + + lwfree(lines); + + if ( mline_out && mpoint_out ) + { + points[0] = mline_out; + points[1] = mpoint_out; + gout = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, + points, 2); + } + else if ( mline_out ) + { + gout = mline_out; + } + else if ( mpoint_out ) + { + gout = mpoint_out; + } + + lwfree(points); + + return gout; +} + + static GEOSGeometry* LWGEOM_GEOS_makeValid(const GEOSGeometry* gin) { @@ -631,7 +720,6 @@ LWGEOM_GEOS_makeValid(const GEOSGeometry* gin) break; case GEOS_LINESTRING: - case GEOS_MULTILINESTRING: gout = LWGEOM_GEOS_makeValidLine(gin); if ( ! gout ) /* an exception or something */ { @@ -640,7 +728,16 @@ LWGEOM_GEOS_makeValid(const GEOSGeometry* gin) return NULL; } break; /* we've done */ - break; + + case GEOS_MULTILINESTRING: + gout = LWGEOM_GEOS_makeValidMultiLine(gin); + if ( ! gout ) /* an exception or something */ + { + /* cleanup and throw */ + lwerror("%s", loggederror); + return NULL; + } + break; /* we've done */ case GEOS_POLYGON: case GEOS_MULTIPOLYGON: @@ -764,6 +861,7 @@ lwgeom_make_valid(LWGEOM* lwgeom_in) if ( lwgeom_is_collection(TYPE_GETTYPE(lwgeom_in->type)) && ! lwgeom_is_collection(TYPE_GETTYPE(lwgeom_out->type)) ) { + POSTGIS_DEBUG(3, "lwgeom_make_valid: forcing multi"); lwgeom_out = lwgeom_as_multi(lwgeom_out); } diff --git a/regress/clean.sql b/regress/clean.sql index d4cd1bd14..83b301c92 100644 --- a/regress/clean.sql +++ b/regress/clean.sql @@ -27,12 +27,11 @@ RT 16.4 010600000002000000010300000001000000080000000000000000C05040000000000000 RT 17.1 010300000003000000050000000000000000004E4000000000000014C0000000000000544000000000000014C0000000000000544000000000000034400000000000004E4000000000000034400000000000004E4000000000000014C0050000000000000000804B4000000000000000000000000000805140000000000000000000000000008051400000000000002E400000000000804B400000000000002E400000000000804B40000000000000000005000000000000000040504000000000000014400000000000C0524000000000000014400000000000C0524000000000000024400000000000405040000000000000244000000000004050400000000000001440 0106000000030000000103000000010000000D0000000000000000004E400000000000002E400000000000004E40000000000000344000000000000054400000000000003440000000000000544000000000000014C00000000000004E4000000000000014C00000000000004E40000000000000000000000000008051400000000000000000000000000080514000000000000014400000000000C0524000000000000014400000000000C0524000000000000024400000000000805140000000000000244000000000008051400000000000002E400000000000004E400000000000002E40010300000001000000050000000000000000004E4000000000000000000000000000804B4000000000000000000000000000804B400000000000002E400000000000004E400000000000002E400000000000004E400000000000000000010300000001000000050000000000000000805140000000000000244000000000008051400000000000001440000000000040504000000000000014400000000000405040000000000000244000000000008051400000000000002440 PG 1 0103000000010000000100000000000000000000000000000000000000 POINT(0 0) PG 2 LINESTRING(0 0, 0 0) POINT(0 0) +PG 3 MULTILINESTRING((0 0, 10 0),(20 20, 20 20)) GEOMETRYCOLLECTION(LINESTRING(0 0, 10 0),POINT(20 20)) \. -- PG.1 : polygon with single ring with single point in it -- to be converted to a POINT --- PG.2 : linestring composed by two equal points to be converted --- to a point -- SELECT origin,caseno, diff --git a/regress/clean_expected b/regress/clean_expected index e73e7ce88..ba94b8c87 100644 --- a/regress/clean_expected +++ b/regress/clean_expected @@ -23,3 +23,4 @@ RT|16.4|t|t|f RT|17.1|t|t|f PG|1|t|t|f PG|2|t|t|f +PG|3|t|t|f -- 2.40.0