Allow splitting lines by multipoints
authorSandro Santilli <strk@keybit.net>
Wed, 22 Apr 2015 15:25:42 +0000 (15:25 +0000)
committerSandro Santilli <strk@keybit.net>
Wed, 22 Apr 2015 15:25:42 +0000 (15:25 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@13434 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
doc/reference_processing.xml
liblwgeom/cunit/cu_split.c
liblwgeom/lwgeom_geos_split.c
regress/split.sql
regress/split_expected

diff --git a/NEWS b/NEWS
index 920c55eed58371c1c3d76255763b315a147fa214..7da25d146ed9fb92426d7c306b8f1f77fd713807 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -63,7 +63,8 @@ PostGIS 2.2.0
 
  * Enhancements *
 
-  - Allow splitting lines by multilines and (multi)polygon boundaries
+  - ST_Split: allow splitting lines by multilines, multipoints
+              and (multi)polygon boundaries
   - #3070, Simplify geometry type constraint
   - #2839, Implement selectivity estimator for functional indexes,
            speeding up spatial queries on raster tables.
index e6e60e6adf4701e9dd66d908e0fb01efe9231f6e..c1a545ee9aaab4fc1697d668745be77cf41a75ce 100644 (file)
@@ -2868,7 +2868,7 @@ LINESTRING M (5 2 3.40282346638529e+38,3 8 29,6 20 1.5,7 25 49.5,10 10 3.4028234
         <refsection>
             <title>Description</title>
             <para>
-            The function supports splitting a line by point, a line by (multi)line or (multi)polygon boundary, a polygon by line. The returned geometry is always a collection.
+            The function supports splitting a line by (multi)point, (multi)line or (multi)polygon boundary, a polygon by line. The returned geometry is always a collection.
             </para>
             
             <para>
@@ -2878,7 +2878,7 @@ LINESTRING M (5 2 3.40282346638529e+38,3 8 29,6 20 1.5,7 25 49.5,10 10 3.4028234
             </para>
             
             <para>Availability: 2.0.0</para>
-            <para>Changed: 2.2.0 support for splitting a line by a multiline or (multi)polygon boundary was introduced.</para>
+            <para>Changed: 2.2.0 support for splitting a line by a multiline, a multipoint or (multi)polygon boundary was introduced.</para>
 
             <note><para>To improve the robustness of ST_Split it may be convenient to <xref linkend="ST_Snap"/> the input to the blade in advance using a very low tolerance. Otherwise the internally used coordinate grid may cause tolerance problems, where coordinates of input and blade do not fall onto each other and the input is not being split correctly (see <ulink url="http://trac.osgeo.org/postgis/ticket/2192">#2192</ulink>).</para></note> 
 
index 2a8fcdb1ac7f51aee64c295c501e9f809f28d3b3..205b9a5e40ddc5d04ca78e03501d5264472bd32e 100644 (file)
@@ -231,6 +231,24 @@ static void test_lwgeom_split(void)
        lwgeom_free(ret);
        lwgeom_free(geom);
        lwgeom_free(blade);
+
+  /* Split line by multipoint */
+  geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE);
+  CU_ASSERT_FATAL(geom != NULL);
+  blade = lwgeom_from_wkt("MULTIPOINT(2 0,8 0,4 0)", LW_PARSER_CHECK_NONE);
+  ret = lwgeom_split(geom, blade);
+  if ( ! ret ) printf("%s", cu_error_msg);
+  CU_ASSERT_FATAL(ret != NULL);
+  wkt = lwgeom_to_ewkt(ret);
+  CU_ASSERT_FATAL(wkt != NULL);
+       in_wkt = "GEOMETRYCOLLECTION(LINESTRING(8 0,10 0),LINESTRING(0 0,2 0),LINESTRING(4 0,8 0),LINESTRING(2 0,4 0))";
+  if (strcmp(in_wkt, wkt))
+                fprintf(stderr, "\nExp:  %s\nObt:  %s\n", in_wkt, wkt);
+  CU_ASSERT_STRING_EQUAL(wkt, in_wkt);
+  lwfree(wkt);
+       lwgeom_free(ret);
+       lwgeom_free(geom);
+       lwgeom_free(blade);
 }
 
 
index 89d66816d2725ef90124d601414aa5b9e0c9d394..83665c698f669416fbce8c77b9201491c8d076bf 100644 (file)
@@ -43,6 +43,7 @@
 
 static LWGEOM* lwline_split_by_line(const LWLINE* lwgeom_in, const LWGEOM* blade_in);
 static LWGEOM* lwline_split_by_point(const LWLINE* lwgeom_in, const LWPOINT* blade_in);
+static LWGEOM* lwline_split_by_mpoint(const LWLINE* lwgeom_in, const LWMPOINT* blade_in);
 static LWGEOM* lwline_split(const LWLINE* lwgeom_in, const LWGEOM* blade_in);
 static LWGEOM* lwpoly_split_by_line(const LWPOLY* lwgeom_in, const LWLINE* blade_in);
 static LWGEOM* lwcollection_split(const LWCOLLECTION* lwcoll_in, const LWGEOM* blade_in);
@@ -178,6 +179,43 @@ lwline_split_by_point(const LWLINE* lwline_in, const LWPOINT* blade_in)
        return (LWGEOM*)out;
 }
 
+static LWGEOM*
+lwline_split_by_mpoint(const LWLINE* lwline_in, const LWMPOINT* mp)
+{
+  LWMLINE* out;
+  int i, j;
+
+  out = lwmline_construct_empty(lwline_in->srid,
+          FLAGS_GET_Z(lwline_in->flags),
+          FLAGS_GET_M(lwline_in->flags));
+  lwmline_add_lwline(out, lwline_clone(lwline_in));
+
+  for (i=0; i<mp->ngeoms; ++i)
+  {
+    for (j=0; j<out->ngeoms; ++j)
+    {
+      lwline_in = out->geoms[j];
+      LWPOINT *blade_in = mp->geoms[i];
+      int ret = lwline_split_by_point_to(lwline_in, blade_in, out);
+      if ( 2 == ret )
+      {
+        /* the point splits this line,
+         * 2 splits were added to collection.
+         * We'll move the latest added into
+         * the slot of the current one.
+         */
+        lwline_free(out->geoms[j]);
+        out->geoms[j] = out->geoms[--out->ngeoms];
+      }
+    }
+  }
+
+  /* Turn multiline into collection */
+  out->type = COLLECTIONTYPE;
+
+  return (LWGEOM*)out;
+}
+
 int
 lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in,
                          LWMLINE* v)
@@ -247,6 +285,8 @@ lwline_split(const LWLINE* lwline_in, const LWGEOM* blade_in)
        {
        case POINTTYPE:
                return lwline_split_by_point(lwline_in, (LWPOINT*)blade_in);
+       case MULTIPOINTTYPE:
+               return lwline_split_by_mpoint(lwline_in, (LWMPOINT*)blade_in);
 
        case LINETYPE:
        case MULTILINETYPE:
index 1906fdc533da3d715d7f0d073ad77b2ac26ba330..cb110e39d8f4a1cb3da23645f1e5fe4784a07fd5 100644 (file)
@@ -96,4 +96,10 @@ select '85', st_asewkt(ST_Split(
   'SRID=3;MULTIPOLYGON(((0 -1,0 -3,2 -3,2 -1,0 -1)),((3 0,3 2,5 2,5 0,3 0)))'
 ));
 
+-- Split multiline by multipoint
+select '86', st_asewkt(ST_Split(
+  'SRID=3;MULTILINESTRING((0 0,10 0),(5 -5, 5 5),(0 20,10 20))',
+  'SRID=3;MULTIPOINT(2 6,5 0,5 20,2 20,8 20,8 0,5 -2,0 0, 5 -5, 10 20)'
+));
+
 -- TODO: split line by collapsed line 
index e4ebfee102276af5e09897f6eab19a8ac343a4bd..64735cf0ce91662fe1a5ef48cbf0ac9fec2cef53 100644 (file)
@@ -27,3 +27,4 @@ ERROR:  Splitter line has linear intersection with input
 83|SRID=3;GEOMETRYCOLLECTION(LINESTRING(1 -1,1 0),LINESTRING(1 0,1 1))
 84|SRID=3;GEOMETRYCOLLECTION(LINESTRING(1 -1,1 0),LINESTRING(1 0,1 1))
 85|SRID=3;GEOMETRYCOLLECTION(LINESTRING(1 -2,1 -1),LINESTRING(1 -1,1 1,3 1),LINESTRING(3 1,4 1))
+86|SRID=3;GEOMETRYCOLLECTION(LINESTRING(8 0,10 0),LINESTRING(0 0,5 0),LINESTRING(5 0,8 0),LINESTRING(5 0,5 5),LINESTRING(5 -2,5 0),LINESTRING(5 -5,5 -2),LINESTRING(8 20,10 20),LINESTRING(2 20,5 20),LINESTRING(0 20,2 20),LINESTRING(5 20,8 20))