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