]> granicus.if.org Git - postgis/commitdiff
Implement split-line-by-line
authorSandro Santilli <strk@keybit.net>
Sat, 13 Mar 2010 10:59:19 +0000 (10:59 +0000)
committerSandro Santilli <strk@keybit.net>
Sat, 13 Mar 2010 10:59:19 +0000 (10:59 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@5433 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/lwgeom_geos_split.c
regress/split.sql
regress/split_expected

index ccb4543c597184787a71fd5fc39a9f0b3eb63c04..246c98fb9a1c517f89db580f1b73a6e0db3130b2 100644 (file)
@@ -37,6 +37,7 @@
  **********************************************************************/
 
 #include "lwgeom_geos.h"
+#include "lwalgorithm.h"
 #include "funcapi.h"
 
 #include <string.h>
 
 /* #define POSTGIS_DEBUG_LEVEL 4 */
 
+/* Initializes and uses GEOS internally */
+static LWGEOM* lwline_split_by_line(LWLINE* lwgeom_in, LWLINE* blade_in);
+static LWGEOM*
+lwline_split_by_line(LWLINE* lwline_in, LWLINE* blade_in)
+{
+       LWGEOM** components;
+       LWGEOM* diff;
+       LWCOLLECTION* out;
+       GEOSGeometry* gdiff; /* difference */
+       GEOSGeometry* g1; 
+       GEOSGeometry* g2; 
+
+       /* Possible outcomes:
+        *
+        *  1. The lines do not cross (touch != cross)
+        *      -> Return a collection with single element
+        *  2. The lines cross
+        *      -> Return a collection 2 elements:
+        *         o segments falling on the left of the directed blade
+        *         o segments falling on the right of the directed blade
+        */
+
+       initGEOS(lwgeom_geos_error, lwgeom_geos_error);
+
+       g1 = LWGEOM2GEOS((LWGEOM*)lwline_in);
+       if ( ! g1 ) {
+               lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
+               return NULL;
+       }
+       g2 = LWGEOM2GEOS((LWGEOM*)blade_in);
+       if ( ! g2 ) {
+               GEOSGeom_destroy(g1);
+               lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
+               return NULL;
+       }
+       gdiff = GEOSDifference(g1,g2);
+       GEOSGeom_destroy(g1);
+       GEOSGeom_destroy(g2);
+       if (gdiff == NULL) {
+               lwerror("GEOSDifference: %s", lwgeom_geos_errmsg);
+               return NULL;
+       }
+
+       diff = GEOS2LWGEOM(gdiff, TYPE_HASZ(lwline_in->type));
+       GEOSGeom_destroy(gdiff);
+       if (NULL == diff) {
+               lwerror("GEOS2LWGEOM: %s", lwgeom_geos_errmsg);
+               return NULL;
+       }
+
+       if ( ! lwgeom_is_collection(TYPE_GETTYPE(diff->type)) )
+       {
+               components = lwalloc(sizeof(LWGEOM*)*1);
+               components[0] = diff;
+               out = lwcollection_construct(COLLECTIONTYPE, lwline_in->SRID,
+                       NULL, 1, components);
+       }
+       else
+       {
+               out = lwcollection_construct(COLLECTIONTYPE, lwline_in->SRID,
+                       NULL, ((LWCOLLECTION*)diff)->ngeoms,
+                       ((LWCOLLECTION*)diff)->geoms);
+       }
+
+
+       return (LWGEOM*)out;
+}
+
 static LWGEOM* lwline_split_by_point(LWLINE* lwgeom_in, LWPOINT* blade_in);
 static LWGEOM*
 lwline_split_by_point(LWLINE* lwline_in, LWPOINT* blade_in)
@@ -120,6 +189,8 @@ lwline_split(LWLINE* lwline_in, LWGEOM* blade_in)
                return lwline_split_by_point(lwline_in, (LWPOINT*)blade_in);
 
        case LINETYPE:
+               return lwline_split_by_line(lwline_in, (LWLINE*)blade_in);
+
        default:
                lwerror("Splitting a Line by a %s is unsupported",
                        lwgeom_typename(TYPE_GETTYPE(blade_in->type)));
@@ -168,11 +239,6 @@ Datum ST_SplitGeometry(PG_FUNCTION_ARGS);
 PG_FUNCTION_INFO_V1(ST_SplitGeometry);
 Datum ST_SplitGeometry(PG_FUNCTION_ARGS)
 {
-#if 0 && POSTGIS_GEOS_VERSION < 33
-       elog(ERROR, "You need GEOS-3.3.0 or up for ST_CleanGeometry");
-       PG_RETURN_NULL();
-#else /* POSTGIS_GEOS_VERSION >= 33 */
-
        PG_LWGEOM *in, *blade_in, *out;
        LWGEOM *lwgeom_in, *lwblade_in, *lwgeom_out;
 
@@ -182,6 +248,8 @@ Datum ST_SplitGeometry(PG_FUNCTION_ARGS)
        blade_in = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
        lwblade_in = lwgeom_deserialize(SERIALIZED_FORM(blade_in));
 
+       errorIfSRIDMismatch(lwgeom_in->SRID, lwblade_in->SRID);
+
        lwgeom_out = lwgeom_split(lwgeom_in, lwblade_in);
        if ( ! lwgeom_out ) {
                PG_FREE_IF_COPY(in, 0);
@@ -196,6 +264,5 @@ Datum ST_SplitGeometry(PG_FUNCTION_ARGS)
 
        PG_RETURN_POINTER(out);
 
-#endif /* POSTGIS_GEOS_VERSION >= 33 */
 }
 
index f9fdeae059990df37ad1bba8b616f869b5df8ef6..afad002cbf722d43bbb9b06cc42e23ab7577cc3a 100644 (file)
@@ -1,11 +1,27 @@
--- Point on line
-select '1',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'POINT(5 0)'));
+-- Split line by point of different SRID
+select st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=5;POINT(5 1)');
 
-select '1.1',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(10 0, 0 0)', 'POINT(5 0)'));
+-- Split line by point on the line interior
+select '1',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=10;POINT(5 0)'));
+select '1.1',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(10 0, 0 0)', 'SRID=10;POINT(5 0)'));
 
--- Point on line boundary
-select '2',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'POINT(10 0)'));
+-- Split line by point on the line boundary
+select '2',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=10;POINT(10 0)'));
 
--- Point off line
-select '3',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'POINT(5 1)'));
+-- Split line by point on the line exterior
+select '3',st_asewkt(st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=10;POINT(5 1)'));
 
+-- Split line by line of different SRID
+select st_splitgeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=5;LINESTRING(5 1, 10 1)');
+
+-- Split line by disjoint line 
+select '4', st_asewkt(ST_SplitGeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=10;LINESTRING(20 0, 20 20)'));
+
+-- Split line by touching line
+select '5', st_asewkt(ST_SplitGeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=10;LINESTRING(10 -5, 10 5)'));
+
+-- Split line by intersecting line
+select '6', st_asewkt(ST_SplitGeometry('SRID=10;LINESTRING(0 0, 10 0)', 'SRID=10;LINESTRING(5 -5, 5 5)'));
+
+-- Split line by multiply-intersecting line
+select '7', st_asewkt(ST_SplitGeometry('SRID=10;LINESTRING(0 0, 10 0, 10 10, 0 10, 0 20, 10 20)', 'SRID=10;LINESTRING(5 -5, 5 25)'));
index a9937352d239ee5775cdbab005c2d3da16d5fef1..14be28fc5c0a145b1117943aeaaf104409c7f993 100644 (file)
@@ -1,4 +1,10 @@
+ERROR:  Operation on mixed SRID geometries
 1|SRID=10;GEOMETRYCOLLECTION(LINESTRING(0 0,5 0),LINESTRING(5 0,10 0))
 1.1|SRID=10;GEOMETRYCOLLECTION(LINESTRING(10 0,5 0),LINESTRING(5 0,0 0))
 2|SRID=10;GEOMETRYCOLLECTION(LINESTRING(0 0,10 0))
 3|SRID=10;GEOMETRYCOLLECTION(LINESTRING(0 0,10 0))
+ERROR:  Operation on mixed SRID geometries
+4|SRID=10;GEOMETRYCOLLECTION(LINESTRING(0 0,10 0))
+5|SRID=10;GEOMETRYCOLLECTION(LINESTRING(0 0,10 0))
+6|SRID=10;GEOMETRYCOLLECTION(LINESTRING(0 0,5 0),LINESTRING(5 0,10 0))
+7|SRID=10;GEOMETRYCOLLECTION(LINESTRING(0 0,5 0),LINESTRING(5 0,10 0,10 10,5 10),LINESTRING(5 10,0 10,0 20,5 20),LINESTRING(5 20,10 20))