PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_geos_split.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright 2011-2015 Sandro Santilli <strk@kbt.io>
22 *
23 **********************************************************************/
24
25#include "../postgis_config.h"
26/*#define POSTGIS_DEBUG_LEVEL 4*/
27#include "lwgeom_geos.h"
28#include "liblwgeom_internal.h"
29
30#include <string.h>
31#include <assert.h>
32
33static LWGEOM* lwline_split_by_line(const LWLINE* lwgeom_in, const LWGEOM* blade_in);
34static LWGEOM* lwline_split_by_point(const LWLINE* lwgeom_in, const LWPOINT* blade_in);
35static LWGEOM* lwline_split_by_mpoint(const LWLINE* lwgeom_in, const LWMPOINT* blade_in);
36static LWGEOM* lwline_split(const LWLINE* lwgeom_in, const LWGEOM* blade_in);
37static LWGEOM* lwpoly_split_by_line(const LWPOLY* lwgeom_in, const LWGEOM* blade_in);
38static LWGEOM* lwcollection_split(const LWCOLLECTION* lwcoll_in, const LWGEOM* blade_in);
39static LWGEOM* lwpoly_split(const LWPOLY* lwpoly_in, const LWGEOM* blade_in);
40
41/* Initializes and uses GEOS internally */
42static LWGEOM*
43lwline_split_by_line(const LWLINE* lwline_in, const LWGEOM* blade_in)
44{
45 LWGEOM** components;
46 LWGEOM* diff;
47 LWCOLLECTION* out;
48 GEOSGeometry* gdiff; /* difference */
49 GEOSGeometry* g1;
50 GEOSGeometry* g2;
51 int ret;
52
53 /* ASSERT blade_in is LINE or MULTILINE */
54 assert (blade_in->type == LINETYPE ||
55 blade_in->type == MULTILINETYPE ||
56 blade_in->type == POLYGONTYPE ||
57 blade_in->type == MULTIPOLYGONTYPE );
58
59 /* Possible outcomes:
60 *
61 * 1. The lines do not cross or overlap
62 * -> Return a collection with single element
63 * 2. The lines cross
64 * -> Return a collection of all elements resulting from the split
65 */
66
68
69 g1 = LWGEOM2GEOS((LWGEOM*)lwline_in, 0);
70 if ( ! g1 )
71 {
72 lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
73 return NULL;
74 }
75 g2 = LWGEOM2GEOS(blade_in, 0);
76 if ( ! g2 )
77 {
78 GEOSGeom_destroy(g1);
79 lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
80 return NULL;
81 }
82
83 /* If blade is a polygon, pick its boundary */
84 if ( blade_in->type == POLYGONTYPE || blade_in->type == MULTIPOLYGONTYPE )
85 {
86 gdiff = GEOSBoundary(g2);
87 GEOSGeom_destroy(g2);
88 if ( ! gdiff )
89 {
90 GEOSGeom_destroy(g1);
91 lwerror("GEOSBoundary: %s", lwgeom_geos_errmsg);
92 return NULL;
93 }
94 g2 = gdiff; gdiff = NULL;
95 }
96
97 /* If interior intersection is linear we can't split */
98 ret = GEOSRelatePattern(g1, g2, "1********");
99 if ( 2 == ret )
100 {
101 lwerror("GEOSRelatePattern: %s", lwgeom_geos_errmsg);
102 GEOSGeom_destroy(g1);
103 GEOSGeom_destroy(g2);
104 return NULL;
105 }
106 if ( ret )
107 {
108 GEOSGeom_destroy(g1);
109 GEOSGeom_destroy(g2);
110 lwerror("Splitter line has linear intersection with input");
111 return NULL;
112 }
113
114
115 gdiff = GEOSDifference(g1,g2);
116 GEOSGeom_destroy(g1);
117 GEOSGeom_destroy(g2);
118 if (gdiff == NULL)
119 {
120 lwerror("GEOSDifference: %s", lwgeom_geos_errmsg);
121 return NULL;
122 }
123
124 diff = GEOS2LWGEOM(gdiff, FLAGS_GET_Z(lwline_in->flags));
125 GEOSGeom_destroy(gdiff);
126 if (NULL == diff)
127 {
128 lwerror("GEOS2LWGEOM: %s", lwgeom_geos_errmsg);
129 return NULL;
130 }
131
132 out = lwgeom_as_lwcollection(diff);
133 if ( ! out )
134 {
135 components = lwalloc(sizeof(LWGEOM*)*1);
136 components[0] = diff;
138 NULL, 1, components);
139 }
140 else
141 {
142 /* Set SRID */
143 lwgeom_set_srid((LWGEOM*)out, lwline_in->srid);
144 /* Force collection type */
145 out->type = COLLECTIONTYPE;
146 }
147
148
149 return (LWGEOM*)out;
150}
151
152static LWGEOM*
153lwline_split_by_point(const LWLINE* lwline_in, const LWPOINT* blade_in)
154{
155 LWMLINE* out;
156
157 out = lwmline_construct_empty(lwline_in->srid,
158 FLAGS_GET_Z(lwline_in->flags),
159 FLAGS_GET_M(lwline_in->flags));
160 if ( lwline_split_by_point_to(lwline_in, blade_in, out) < 2 )
161 {
162 lwmline_add_lwline(out, lwline_clone_deep(lwline_in));
163 }
164
165 /* Turn multiline into collection */
166 out->type = COLLECTIONTYPE;
167
168 return (LWGEOM*)out;
169}
170
171static LWGEOM*
172lwline_split_by_mpoint(const LWLINE* lwline_in, const LWMPOINT* mp)
173{
174 LWMLINE* out;
175 uint32_t i, j;
176
177 out = lwmline_construct_empty(lwline_in->srid,
178 FLAGS_GET_Z(lwline_in->flags),
179 FLAGS_GET_M(lwline_in->flags));
180 lwmline_add_lwline(out, lwline_clone_deep(lwline_in));
181
182 for (i=0; i<mp->ngeoms; ++i)
183 {
184 for (j=0; j<out->ngeoms; ++j)
185 {
186 lwline_in = out->geoms[j];
187 LWPOINT *blade_in = mp->geoms[i];
188 int ret = lwline_split_by_point_to(lwline_in, blade_in, out);
189 if ( 2 == ret )
190 {
191 /* the point splits this line,
192 * 2 splits were added to collection.
193 * We'll move the latest added into
194 * the slot of the current one.
195 */
196 lwline_free(out->geoms[j]);
197 out->geoms[j] = out->geoms[--out->ngeoms];
198 }
199 }
200 }
201
202 /* Turn multiline into collection */
203 out->type = COLLECTIONTYPE;
204
205 return (LWGEOM*)out;
206}
207
208int
209lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in,
210 LWMLINE* v)
211{
212 double mindist_sqr = -1;
213 POINT4D pt, pt_projected;
214 POINT4D p1, p2;
215 POINTARRAY *ipa = lwline_in->points;
216 POINTARRAY* pa1;
217 POINTARRAY* pa2;
218 uint32_t i, nsegs, seg = UINT32_MAX;
219
220 /* Possible outcomes:
221 *
222 * 1. The point is not on the line or on the boundary
223 * -> Leave collection untouched, return 0
224 * 2. The point is on the boundary
225 * -> Leave collection untouched, return 1
226 * 3. The point is in the line
227 * -> Push 2 elements on the collection:
228 * o start_point - cut_point
229 * o cut_point - last_point
230 * -> Return 2
231 */
232
233 getPoint4d_p(blade_in->point, 0, &pt);
234
235 /* Find closest segment */
236 if ( ipa->npoints < 1 ) return 0; /* empty input line */
237 getPoint4d_p(ipa, 0, &p1);
238 nsegs = ipa->npoints - 1;
239 for ( i = 0; i < nsegs; i++ )
240 {
241 getPoint4d_p(ipa, i+1, &p2);
242 double dist_sqr = distance2d_sqr_pt_seg((POINT2D *)&pt, (POINT2D *)&p1, (POINT2D *)&p2);
243 LWDEBUGF(4, "Distance (squared) of point %.15g %.15g to segment %.15g %.15g, %.15g %.15g: %.15g",
244 pt.x, pt.y,
245 p1.x, p1.y,
246 p2.x, p2.y,
247 dist_sqr);
248 if (i == 0 || dist_sqr < mindist_sqr)
249 {
250 mindist_sqr = dist_sqr;
251 seg=i;
252 if (mindist_sqr == 0.0)
253 break; /* can't be closer than ON line */
254 }
255 p1 = p2;
256 }
257
258 LWDEBUGF(3, "Closest segment: %d", seg);
259 LWDEBUGF(3, "mindist: %.15g", mindist_sqr);
260
261 /* No intersection */
262 if (mindist_sqr > 0)
263 return 0;
264
265 /* empty or single-point line, intersection on boundary */
266 if ( seg == UINT32_MAX ) return 1;
267
268 /*
269 * We need to project the
270 * point on the closest segment,
271 * to interpolate Z and M if needed
272 */
273 getPoint4d_p(ipa, seg, &p1);
274 getPoint4d_p(ipa, seg+1, &p2);
275 closest_point_on_segment(&pt, &p1, &p2, &pt_projected);
276 /* But X and Y we want the ones of the input point,
277 * as on some architectures the interpolation math moves the
278 * coordinates (see #3422)
279 */
280 pt_projected.x = pt.x;
281 pt_projected.y = pt.y;
282
283 LWDEBUGF(3, "Projected point:(%.15g %.15g), seg:%d, p1:(%.15g %.15g), p2:(%.15g %.15g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y);
284
285 /* When closest point == an endpoint, this is a boundary intersection */
286 if ( ( (seg == nsegs-1) && P4D_SAME_STRICT(&pt_projected, &p2) ) ||
287 ( (seg == 0) && P4D_SAME_STRICT(&pt_projected, &p1) ) )
288 {
289 return 1;
290 }
291
292 /* This is an internal intersection, let's build the two new pointarrays */
293
294 pa1 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), seg+2);
295 /* TODO: replace with a memcpy ? */
296 for (i=0; i<=seg; ++i)
297 {
298 getPoint4d_p(ipa, i, &p1);
300 }
301 ptarray_append_point(pa1, &pt_projected, LW_FALSE);
302
304 ptarray_append_point(pa2, &pt_projected, LW_FALSE);
305 /* TODO: replace with a memcpy (if so need to check for duplicated point) ? */
306 for (i=seg+1; i<ipa->npoints; ++i)
307 {
308 getPoint4d_p(ipa, i, &p1);
310 }
311
312 /* NOTE: I've seen empty pointarrays with loc != 0 and loc != 1 */
313 if ( pa1->npoints == 0 || pa2->npoints == 0 ) {
314 ptarray_free(pa1);
315 ptarray_free(pa2);
316 /* Intersection is on the boundary */
317 return 1;
318 }
319
322 return 2;
323}
324
325static LWGEOM*
326lwline_split(const LWLINE* lwline_in, const LWGEOM* blade_in)
327{
328 switch (blade_in->type)
329 {
330 case POINTTYPE:
331 return lwline_split_by_point(lwline_in, (LWPOINT*)blade_in);
332 case MULTIPOINTTYPE:
333 return lwline_split_by_mpoint(lwline_in, (LWMPOINT*)blade_in);
334
335 case LINETYPE:
336 case MULTILINETYPE:
337 case POLYGONTYPE:
338 case MULTIPOLYGONTYPE:
339 return lwline_split_by_line(lwline_in, blade_in);
340
341 default:
342 lwerror("Splitting a Line by a %s is unsupported",
343 lwtype_name(blade_in->type));
344 return NULL;
345 }
346 return NULL;
347}
348
349/* Initializes and uses GEOS internally */
350static LWGEOM*
351lwpoly_split_by_line(const LWPOLY* lwpoly_in, const LWGEOM* blade_in)
352{
353 LWCOLLECTION* out;
354 GEOSGeometry* g1;
355 GEOSGeometry* g2;
356 GEOSGeometry* g1_bounds;
357 GEOSGeometry* polygons;
358 const GEOSGeometry *vgeoms[1];
359 int i,n;
360 int hasZ = FLAGS_GET_Z(lwpoly_in->flags);
361
362
363 /* Possible outcomes:
364 *
365 * 1. The line does not split the polygon
366 * -> Return a collection with single element
367 * 2. The line does split the polygon
368 * -> Return a collection of all elements resulting from the split
369 */
370
372
373 g1 = LWGEOM2GEOS((LWGEOM*)lwpoly_in, 0);
374 if ( NULL == g1 )
375 {
376 lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
377 return NULL;
378 }
379 g1_bounds = GEOSBoundary(g1);
380 if ( NULL == g1_bounds )
381 {
382 GEOSGeom_destroy(g1);
383 lwerror("GEOSBoundary: %s", lwgeom_geos_errmsg);
384 return NULL;
385 }
386
387 g2 = LWGEOM2GEOS(blade_in, 0);
388 if ( NULL == g2 )
389 {
390 GEOSGeom_destroy(g1);
391 GEOSGeom_destroy(g1_bounds);
392 lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
393 return NULL;
394 }
395
396 vgeoms[0] = GEOSUnion(g1_bounds, g2);
397 if ( NULL == vgeoms[0] )
398 {
399 GEOSGeom_destroy(g1);
400 GEOSGeom_destroy(g2);
401 GEOSGeom_destroy(g1_bounds);
402 lwerror("GEOSUnion: %s", lwgeom_geos_errmsg);
403 return NULL;
404 }
405
406 polygons = GEOSPolygonize(vgeoms, 1);
407 if ( NULL == polygons )
408 {
409 GEOSGeom_destroy(g1);
410 GEOSGeom_destroy(g2);
411 GEOSGeom_destroy(g1_bounds);
412 GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
413 lwerror("GEOSPolygonize: %s", lwgeom_geos_errmsg);
414 return NULL;
415 }
416
417#ifndef NDEBUG
418 if ( GEOSGeomTypeId(polygons) != COLLECTIONTYPE )
419 {
420 GEOSGeom_destroy(g1);
421 GEOSGeom_destroy(g2);
422 GEOSGeom_destroy(g1_bounds);
423 GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
424 GEOSGeom_destroy(polygons);
425 lwerror("%s [%d] Unexpected return from GEOSpolygonize", __FILE__, __LINE__);
426 return 0;
427 }
428#endif
429
430 /* We should now have all polygons, just skip
431 * the ones which are in holes of the original
432 * geometries and return the rest in a collection
433 */
434 n = GEOSGetNumGeometries(polygons);
436 hasZ, 0);
437 /* Allocate space for all polys */
438 out->geoms = lwrealloc(out->geoms, sizeof(LWGEOM*)*n);
439 assert(0 == out->ngeoms);
440 for (i=0; i<n; ++i)
441 {
442 GEOSGeometry* pos; /* point on surface */
443 const GEOSGeometry* p = GEOSGetGeometryN(polygons, i);
444 int contains;
445
446 pos = GEOSPointOnSurface(p);
447 if ( ! pos )
448 {
449 GEOSGeom_destroy(g1);
450 GEOSGeom_destroy(g2);
451 GEOSGeom_destroy(g1_bounds);
452 GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
453 GEOSGeom_destroy(polygons);
454 lwerror("GEOSPointOnSurface: %s", lwgeom_geos_errmsg);
455 return NULL;
456 }
457
458 contains = GEOSContains(g1, pos);
459 if ( 2 == contains )
460 {
461 GEOSGeom_destroy(g1);
462 GEOSGeom_destroy(g2);
463 GEOSGeom_destroy(g1_bounds);
464 GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
465 GEOSGeom_destroy(polygons);
466 GEOSGeom_destroy(pos);
467 lwerror("GEOSContains: %s", lwgeom_geos_errmsg);
468 return NULL;
469 }
470
471 GEOSGeom_destroy(pos);
472
473 if ( 0 == contains )
474 {
475 /* Original geometry doesn't contain
476 * a point in this ring, must be an hole
477 */
478 continue;
479 }
480
481 out->geoms[out->ngeoms++] = GEOS2LWGEOM(p, hasZ);
482 }
483
484 GEOSGeom_destroy(g1);
485 GEOSGeom_destroy(g2);
486 GEOSGeom_destroy(g1_bounds);
487 GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
488 GEOSGeom_destroy(polygons);
489
490 return (LWGEOM*)out;
491}
492
493static LWGEOM*
494lwcollection_split(const LWCOLLECTION* lwcoll_in, const LWGEOM* blade_in)
495{
496 LWGEOM** split_vector=NULL;
497 LWCOLLECTION* out;
498 size_t split_vector_capacity;
499 size_t split_vector_size=0;
500 size_t i,j;
501
502 split_vector_capacity=8;
503 split_vector = lwalloc(split_vector_capacity * sizeof(LWGEOM*));
504 if ( ! split_vector )
505 {
506 lwerror("Out of virtual memory");
507 return NULL;
508 }
509
510 for (i=0; i<lwcoll_in->ngeoms; ++i)
511 {
512 LWCOLLECTION* col;
513 LWGEOM* split = lwgeom_split(lwcoll_in->geoms[i], blade_in);
514 /* an exception should prevent this from ever returning NULL */
515 if ( ! split ) return NULL;
516
517 col = lwgeom_as_lwcollection(split);
518 /* Output, if any, will always be a collection */
519 assert(col);
520
521 /* Reallocate split_vector if needed */
522 if ( split_vector_size + col->ngeoms > split_vector_capacity )
523 {
524 /* NOTE: we could be smarter on reallocations here */
525 split_vector_capacity += col->ngeoms;
526 split_vector = lwrealloc(split_vector,
527 split_vector_capacity * sizeof(LWGEOM*));
528 if ( ! split_vector )
529 {
530 lwerror("Out of virtual memory");
531 return NULL;
532 }
533 }
534
535 for (j=0; j<col->ngeoms; ++j)
536 {
537 col->geoms[j]->srid = SRID_UNKNOWN; /* strip srid */
538 split_vector[split_vector_size++] = col->geoms[j];
539 }
540 lwfree(col->geoms);
541 lwfree(col);
542 }
543
544 /* Now split_vector has split_vector_size geometries */
546 NULL, split_vector_size, split_vector);
547
548 return (LWGEOM*)out;
549}
550
551static LWGEOM*
552lwpoly_split(const LWPOLY* lwpoly_in, const LWGEOM* blade_in)
553{
554 switch (blade_in->type)
555 {
556 case MULTILINETYPE:
557 case LINETYPE:
558 return lwpoly_split_by_line(lwpoly_in, blade_in);
559 default:
560 lwerror("Splitting a Polygon by a %s is unsupported",
561 lwtype_name(blade_in->type));
562 return NULL;
563 }
564 return NULL;
565}
566
567/* exported */
568LWGEOM*
569lwgeom_split(const LWGEOM* lwgeom_in, const LWGEOM* blade_in)
570{
571 switch (lwgeom_in->type)
572 {
573 case LINETYPE:
574 return lwline_split((const LWLINE*)lwgeom_in, blade_in);
575
576 case POLYGONTYPE:
577 return lwpoly_split((const LWPOLY*)lwgeom_in, blade_in);
578
579 case MULTIPOLYGONTYPE:
580 case MULTILINETYPE:
581 case COLLECTIONTYPE:
582 return lwcollection_split((const LWCOLLECTION*)lwgeom_in, blade_in);
583
584 default:
585 lwerror("Splitting of %s geometries is unsupported",
586 lwtype_name(lwgeom_in->type));
587 return NULL;
588 }
589
590}
591
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_geos_error(const char *fmt,...)
void(*) LWGEOM GEOS2LWGEOM)(const GEOSGeometry *geom, uint8_t want3d)
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
#define LW_FALSE
Definition liblwgeom.h:94
#define COLLECTIONTYPE
Definition liblwgeom.h:108
void * lwrealloc(void *mem, size_t size)
Definition lwutil.c:242
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
Definition lwgeom.c:1638
LWMLINE * lwmline_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwmline.c:38
#define MULTILINETYPE
Definition liblwgeom.h:106
#define LINETYPE
Definition liblwgeom.h:103
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition lwgeom.c:261
#define MULTIPOINTTYPE
Definition liblwgeom.h:105
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition ptarray.c:59
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:165
void * lwalloc(size_t size)
Definition lwutil.c:227
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:107
void lwfree(void *mem)
Definition lwutil.c:248
#define POLYGONTYPE
Definition liblwgeom.h:104
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition lwmline.c:46
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:166
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
double distance2d_sqr_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B)
Definition measures.c:2354
void ptarray_free(POINTARRAY *pa)
Definition ptarray.c:327
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition ptarray.c:147
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
void lwline_free(LWLINE *line)
Definition lwline.c:67
#define P4D_SAME_STRICT(a, b)
LWLINE * lwline_clone_deep(const LWLINE *lwgeom)
Definition lwline.c:109
void closest_point_on_segment(const POINT4D *R, const POINT4D *A, const POINT4D *B, POINT4D *ret)
Definition ptarray.c:1408
Datum contains(PG_FUNCTION_ARGS)
static LWGEOM * lwline_split_by_mpoint(const LWLINE *lwgeom_in, const LWMPOINT *blade_in)
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
static LWGEOM * lwpoly_split_by_line(const LWPOLY *lwgeom_in, const LWGEOM *blade_in)
static LWGEOM * lwline_split(const LWLINE *lwgeom_in, const LWGEOM *blade_in)
static LWGEOM * lwline_split_by_point(const LWLINE *lwgeom_in, const LWPOINT *blade_in)
static LWGEOM * lwpoly_split(const LWPOLY *lwpoly_in, const LWGEOM *blade_in)
int lwline_split_by_point_to(const LWLINE *lwline_in, const LWPOINT *blade_in, LWMLINE *v)
Split a line by a point and push components to the provided multiline.
static LWGEOM * lwline_split_by_line(const LWLINE *lwgeom_in, const LWGEOM *blade_in)
static LWGEOM * lwcollection_split(const LWCOLLECTION *lwcoll_in, const LWGEOM *blade_in)
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
#define UINT32_MAX
uint32_t ngeoms
Definition liblwgeom.h:580
LWGEOM ** geoms
Definition liblwgeom.h:575
int32_t srid
Definition liblwgeom.h:576
uint8_t type
Definition liblwgeom.h:462
int32_t srid
Definition liblwgeom.h:460
lwflags_t flags
Definition liblwgeom.h:485
POINTARRAY * points
Definition liblwgeom.h:483
uint8_t type
Definition liblwgeom.h:486
int32_t srid
Definition liblwgeom.h:484
LWLINE ** geoms
Definition liblwgeom.h:547
uint8_t type
Definition liblwgeom.h:550
uint32_t ngeoms
Definition liblwgeom.h:552
uint32_t ngeoms
Definition liblwgeom.h:538
LWPOINT ** geoms
Definition liblwgeom.h:533
POINTARRAY * point
Definition liblwgeom.h:471
uint8_t type
Definition liblwgeom.h:474
lwflags_t flags
Definition liblwgeom.h:521
int32_t srid
Definition liblwgeom.h:520
double y
Definition liblwgeom.h:390
double x
Definition liblwgeom.h:390
double x
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414
lwflags_t flags
Definition liblwgeom.h:431
uint32_t npoints
Definition liblwgeom.h:427