**********************************************************************/
#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)
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)));
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;
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);
PG_RETURN_POINTER(out);
-#endif /* POSTGIS_GEOS_VERSION >= 33 */
}
--- 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)'));
+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))