]> granicus.if.org Git - postgis/commitdiff
ST_MakeValid : turn collapsed lines into points [RT-SIGTA]
authorSandro Santilli <strk@keybit.net>
Tue, 2 Mar 2010 21:32:09 +0000 (21:32 +0000)
committerSandro Santilli <strk@keybit.net>
Tue, 2 Mar 2010 21:32:09 +0000 (21:32 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@5363 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/lwgeom_geos_clean.c
regress/clean.sql
regress/clean_expected

index 998a3615781812e105961ebb2169c2b7d956ef49..2c8a613f217702db03d4d7e20006abe34a5da50c 100644 (file)
@@ -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<ngeoms; ++i)
+       {
+               const GEOSGeometry* g = GEOSGetGeometryN(gin, i);
+               GEOSGeometry* vg;
+               vg = LWGEOM_GEOS_makeValidLine(g);
+               if ( GEOSisEmpty(vg) ) {
+                       /* we don't care about this one */
+                       GEOSGeom_destroy(vg);
+               }
+               if ( GEOSGeomTypeId(vg) == GEOS_POINT )
+               {
+                       points[npoints++] = vg;
+               }
+               else if ( GEOSGeomTypeId(vg) == GEOS_LINESTRING )
+               {
+                       lines[nlines++] = vg;
+               }
+               else
+               {
+                       /* NOTE: return from GEOSGeomType will leak
+                        * but we really don't expect this to happen */
+                       lwerror("unexpected geom type returned "
+                               "by LWGEOM_GEOS_makeValid: %s",
+                               GEOSGeomType(vg));
+               }
+       }
+
+       if ( npoints )
+       {
+               if ( npoints > 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);
        }
 
index d4cd1bd145a10e2e4d1db950f261c58c82a57c1a..83b301c9259d7539bff0914b7dd5d2893aa8cf2a 100644 (file)
@@ -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,
index e73e7ce88c2c28007b08e5ed5458be7f37f0d102..ba94b8c87898775a8a0ffe303b121363c5ceb9bf 100644 (file)
@@ -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