From: Sandro Santilli Date: Sat, 13 Mar 2010 10:59:19 +0000 (+0000) Subject: Implement split-line-by-line X-Git-Tag: 2.0.0alpha1~3109 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=87798fdd85cd67f5a98418c7dd95bf41d48efc98;p=postgis Implement split-line-by-line git-svn-id: http://svn.osgeo.org/postgis/trunk@5433 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/postgis/lwgeom_geos_split.c b/postgis/lwgeom_geos_split.c index ccb4543c5..246c98fb9 100644 --- a/postgis/lwgeom_geos_split.c +++ b/postgis/lwgeom_geos_split.c @@ -37,6 +37,7 @@ **********************************************************************/ #include "lwgeom_geos.h" +#include "lwalgorithm.h" #include "funcapi.h" #include @@ -44,6 +45,74 @@ /* #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 */ } diff --git a/regress/split.sql b/regress/split.sql index f9fdeae05..afad002cb 100644 --- a/regress/split.sql +++ b/regress/split.sql @@ -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)')); diff --git a/regress/split_expected b/regress/split_expected index a9937352d..14be28fc5 100644 --- a/regress/split_expected +++ b/regress/split_expected @@ -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))