PostGIS  2.3.8dev-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  * 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 
33 static LWGEOM* lwline_split_by_line(const LWLINE* lwgeom_in, const LWGEOM* blade_in);
34 static LWGEOM* lwline_split_by_point(const LWLINE* lwgeom_in, const LWPOINT* blade_in);
35 static LWGEOM* lwline_split_by_mpoint(const LWLINE* lwgeom_in, const LWMPOINT* blade_in);
36 static LWGEOM* lwline_split(const LWLINE* lwgeom_in, const LWGEOM* blade_in);
37 static LWGEOM* lwpoly_split_by_line(const LWPOLY* lwgeom_in, const LWLINE* blade_in);
38 static LWGEOM* lwcollection_split(const LWCOLLECTION* lwcoll_in, const LWGEOM* blade_in);
39 static LWGEOM* lwpoly_split(const LWPOLY* lwpoly_in, const LWGEOM* blade_in);
40 
41 /* Initializes and uses GEOS internally */
42 static LWGEOM*
43 lwline_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 intersecton 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;
137  out = lwcollection_construct(COLLECTIONTYPE, lwline_in->srid,
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 
152 static LWGEOM*
153 lwline_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 
171 static LWGEOM*
172 lwline_split_by_mpoint(const LWLINE* lwline_in, const LWMPOINT* mp)
173 {
174  LWMLINE* out;
175  int 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 
208 int
209 lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in,
210  LWMLINE* v)
211 {
212  double mindist = -1;
213  POINT4D pt, pt_projected;
214  POINT4D p1, p2;
215  POINTARRAY *ipa = lwline_in->points;
216  POINTARRAY* pa1;
217  POINTARRAY* pa2;
218  int i, nsegs, seg = -1;
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  getPoint4d_p(ipa, 0, &p1);
237  nsegs = ipa->npoints - 1;
238  for ( i = 0; i < nsegs; i++ )
239  {
240  getPoint4d_p(ipa, i+1, &p2);
241  double dist;
242  dist = distance2d_pt_seg((POINT2D*)&pt, (POINT2D*)&p1, (POINT2D*)&p2);
243  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);
244  if (i==0 || dist < mindist )
245  {
246  mindist = dist;
247  seg=i;
248  if ( mindist == 0.0 ) break; /* can't be closer than ON line */
249  }
250  p1 = p2;
251  }
252 
253  LWDEBUGF(3, "Closest segment: %d", seg);
254  LWDEBUGF(3, "mindist: %g", mindist);
255 
256  /* No intersection */
257  if ( mindist > 0 ) return 0;
258 
259  /* empty or single-point line, intersection on boundary */
260  if ( seg < 0 ) return 1;
261 
262  /*
263  * We need to project the
264  * point on the closest segment,
265  * to interpolate Z and M if needed
266  */
267  getPoint4d_p(ipa, seg, &p1);
268  getPoint4d_p(ipa, seg+1, &p2);
269  closest_point_on_segment(&pt, &p1, &p2, &pt_projected);
270  /* But X and Y we want the ones of the input point,
271  * as on some architectures the interpolation math moves the
272  * coordinates (see #3422)
273  */
274  pt_projected.x = pt.x;
275  pt_projected.y = pt.y;
276 
277  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);
278 
279  /* When closest point == an endpoint, this is a boundary intersection */
280  if ( ( (seg == nsegs-1) && p4d_same(&pt_projected, &p2) ) ||
281  ( (seg == 0) && p4d_same(&pt_projected, &p1) ) )
282  {
283  return 1;
284  }
285 
286  /* This is an internal intersection, let's build the two new pointarrays */
287 
288  pa1 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), seg+2);
289  /* TODO: replace with a memcpy ? */
290  for (i=0; i<=seg; ++i)
291  {
292  getPoint4d_p(ipa, i, &p1);
293  ptarray_append_point(pa1, &p1, LW_FALSE);
294  }
295  ptarray_append_point(pa1, &pt_projected, LW_FALSE);
296 
297  pa2 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), ipa->npoints-seg);
298  ptarray_append_point(pa2, &pt_projected, LW_FALSE);
299  /* TODO: replace with a memcpy (if so need to check for duplicated point) ? */
300  for (i=seg+1; i<ipa->npoints; ++i)
301  {
302  getPoint4d_p(ipa, i, &p1);
303  ptarray_append_point(pa2, &p1, LW_FALSE);
304  }
305 
306  /* NOTE: I've seen empty pointarrays with loc != 0 and loc != 1 */
307  if ( pa1->npoints == 0 || pa2->npoints == 0 ) {
308  ptarray_free(pa1);
309  ptarray_free(pa2);
310  /* Intersection is on the boundary */
311  return 1;
312  }
313 
316  return 2;
317 }
318 
319 static LWGEOM*
320 lwline_split(const LWLINE* lwline_in, const LWGEOM* blade_in)
321 {
322  switch (blade_in->type)
323  {
324  case POINTTYPE:
325  return lwline_split_by_point(lwline_in, (LWPOINT*)blade_in);
326  case MULTIPOINTTYPE:
327  return lwline_split_by_mpoint(lwline_in, (LWMPOINT*)blade_in);
328 
329  case LINETYPE:
330  case MULTILINETYPE:
331  case POLYGONTYPE:
332  case MULTIPOLYGONTYPE:
333  return lwline_split_by_line(lwline_in, blade_in);
334 
335  default:
336  lwerror("Splitting a Line by a %s is unsupported",
337  lwtype_name(blade_in->type));
338  return NULL;
339  }
340  return NULL;
341 }
342 
343 /* Initializes and uses GEOS internally */
344 static LWGEOM*
345 lwpoly_split_by_line(const LWPOLY* lwpoly_in, const LWLINE* blade_in)
346 {
347  LWCOLLECTION* out;
348  GEOSGeometry* g1;
349  GEOSGeometry* g2;
350  GEOSGeometry* g1_bounds;
351  GEOSGeometry* polygons;
352  const GEOSGeometry *vgeoms[1];
353  int i,n;
354  int hasZ = FLAGS_GET_Z(lwpoly_in->flags);
355 
356 
357  /* Possible outcomes:
358  *
359  * 1. The line does not split the polygon
360  * -> Return a collection with single element
361  * 2. The line does split the polygon
362  * -> Return a collection of all elements resulting from the split
363  */
364 
366 
367  g1 = LWGEOM2GEOS((LWGEOM*)lwpoly_in, 0);
368  if ( NULL == g1 )
369  {
370  lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
371  return NULL;
372  }
373  g1_bounds = GEOSBoundary(g1);
374  if ( NULL == g1_bounds )
375  {
376  GEOSGeom_destroy(g1);
377  lwerror("GEOSBoundary: %s", lwgeom_geos_errmsg);
378  return NULL;
379  }
380 
381  g2 = LWGEOM2GEOS((LWGEOM*)blade_in, 0);
382  if ( NULL == g2 )
383  {
384  GEOSGeom_destroy(g1);
385  GEOSGeom_destroy(g1_bounds);
386  lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
387  return NULL;
388  }
389 
390  vgeoms[0] = GEOSUnion(g1_bounds, g2);
391  if ( NULL == vgeoms[0] )
392  {
393  GEOSGeom_destroy(g1);
394  GEOSGeom_destroy(g2);
395  GEOSGeom_destroy(g1_bounds);
396  lwerror("GEOSUnion: %s", lwgeom_geos_errmsg);
397  return NULL;
398  }
399 
400  /* debugging..
401  lwnotice("Bounds poly: %s",
402  lwgeom_to_ewkt(GEOS2LWGEOM(g1_bounds, hasZ)));
403  lwnotice("Line: %s",
404  lwgeom_to_ewkt(GEOS2LWGEOM(g2, hasZ)));
405 
406  lwnotice("Noded bounds: %s",
407  lwgeom_to_ewkt(GEOS2LWGEOM(vgeoms[0], hasZ)));
408  */
409 
410  polygons = GEOSPolygonize(vgeoms, 1);
411  if ( NULL == polygons )
412  {
413  GEOSGeom_destroy(g1);
414  GEOSGeom_destroy(g2);
415  GEOSGeom_destroy(g1_bounds);
416  GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
417  lwerror("GEOSPolygonize: %s", lwgeom_geos_errmsg);
418  return NULL;
419  }
420 
421 #if PARANOIA_LEVEL > 0
422  if ( GEOSGeometryTypeId(polygons) != COLLECTIONTYPE )
423  {
424  GEOSGeom_destroy(g1);
425  GEOSGeom_destroy(g2);
426  GEOSGeom_destroy(g1_bounds);
427  GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
428  GEOSGeom_destroy(polygons);
429  lwerror("Unexpected return from GEOSpolygonize");
430  return 0;
431  }
432 #endif
433 
434  /* We should now have all polygons, just skip
435  * the ones which are in holes of the original
436  * geometries and return the rest in a collection
437  */
438  n = GEOSGetNumGeometries(polygons);
440  hasZ, 0);
441  /* Allocate space for all polys */
442  out->geoms = lwrealloc(out->geoms, sizeof(LWGEOM*)*n);
443  assert(0 == out->ngeoms);
444  for (i=0; i<n; ++i)
445  {
446  GEOSGeometry* pos; /* point on surface */
447  const GEOSGeometry* p = GEOSGetGeometryN(polygons, i);
448  int contains;
449 
450  pos = GEOSPointOnSurface(p);
451  if ( ! pos )
452  {
453  GEOSGeom_destroy(g1);
454  GEOSGeom_destroy(g2);
455  GEOSGeom_destroy(g1_bounds);
456  GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
457  GEOSGeom_destroy(polygons);
458  lwerror("GEOSPointOnSurface: %s", lwgeom_geos_errmsg);
459  return NULL;
460  }
461 
462  contains = GEOSContains(g1, pos);
463  if ( 2 == contains )
464  {
465  GEOSGeom_destroy(g1);
466  GEOSGeom_destroy(g2);
467  GEOSGeom_destroy(g1_bounds);
468  GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
469  GEOSGeom_destroy(polygons);
470  GEOSGeom_destroy(pos);
471  lwerror("GEOSContains: %s", lwgeom_geos_errmsg);
472  return NULL;
473  }
474 
475  GEOSGeom_destroy(pos);
476 
477  if ( 0 == contains )
478  {
479  /* Original geometry doesn't contain
480  * a point in this ring, must be an hole
481  */
482  continue;
483  }
484 
485  out->geoms[out->ngeoms++] = GEOS2LWGEOM(p, hasZ);
486  }
487 
488  GEOSGeom_destroy(g1);
489  GEOSGeom_destroy(g2);
490  GEOSGeom_destroy(g1_bounds);
491  GEOSGeom_destroy((GEOSGeometry*)vgeoms[0]);
492  GEOSGeom_destroy(polygons);
493 
494  return (LWGEOM*)out;
495 }
496 
497 static LWGEOM*
498 lwcollection_split(const LWCOLLECTION* lwcoll_in, const LWGEOM* blade_in)
499 {
500  LWGEOM** split_vector=NULL;
501  LWCOLLECTION* out;
502  size_t split_vector_capacity;
503  size_t split_vector_size=0;
504  size_t i,j;
505 
506  split_vector_capacity=8;
507  split_vector = lwalloc(split_vector_capacity * sizeof(LWGEOM*));
508  if ( ! split_vector )
509  {
510  lwerror("Out of virtual memory");
511  return NULL;
512  }
513 
514  for (i=0; i<lwcoll_in->ngeoms; ++i)
515  {
516  LWCOLLECTION* col;
517  LWGEOM* split = lwgeom_split(lwcoll_in->geoms[i], blade_in);
518  /* an exception should prevent this from ever returning NULL */
519  if ( ! split ) return NULL;
520 
521  col = lwgeom_as_lwcollection(split);
522  /* Output, if any, will always be a collection */
523  assert(col);
524 
525  /* Reallocate split_vector if needed */
526  if ( split_vector_size + col->ngeoms > split_vector_capacity )
527  {
528  /* NOTE: we could be smarter on reallocations here */
529  split_vector_capacity += col->ngeoms;
530  split_vector = lwrealloc(split_vector,
531  split_vector_capacity * sizeof(LWGEOM*));
532  if ( ! split_vector )
533  {
534  lwerror("Out of virtual memory");
535  return NULL;
536  }
537  }
538 
539  for (j=0; j<col->ngeoms; ++j)
540  {
541  col->geoms[j]->srid = SRID_UNKNOWN; /* strip srid */
542  split_vector[split_vector_size++] = col->geoms[j];
543  }
544  lwfree(col->geoms);
545  lwfree(col);
546  }
547 
548  /* Now split_vector has split_vector_size geometries */
549  out = lwcollection_construct(COLLECTIONTYPE, lwcoll_in->srid,
550  NULL, split_vector_size, split_vector);
551 
552  return (LWGEOM*)out;
553 }
554 
555 static LWGEOM*
556 lwpoly_split(const LWPOLY* lwpoly_in, const LWGEOM* blade_in)
557 {
558  switch (blade_in->type)
559  {
560  case LINETYPE:
561  return lwpoly_split_by_line(lwpoly_in, (LWLINE*)blade_in);
562  default:
563  lwerror("Splitting a Polygon by a %s is unsupported",
564  lwtype_name(blade_in->type));
565  return NULL;
566  }
567  return NULL;
568 }
569 
570 /* exported */
571 LWGEOM*
572 lwgeom_split(const LWGEOM* lwgeom_in, const LWGEOM* blade_in)
573 {
574  switch (lwgeom_in->type)
575  {
576  case LINETYPE:
577  return lwline_split((const LWLINE*)lwgeom_in, blade_in);
578 
579  case POLYGONTYPE:
580  return lwpoly_split((const LWPOLY*)lwgeom_in, blade_in);
581 
582  case MULTIPOLYGONTYPE:
583  case MULTILINETYPE:
584  case COLLECTIONTYPE:
585  return lwcollection_split((const LWCOLLECTION*)lwgeom_in, blade_in);
586 
587  default:
588  lwerror("Splitting of %s geometries is unsupported",
589  lwtype_name(lwgeom_in->type));
590  return NULL;
591  }
592 
593 }
594 
double x
Definition: liblwgeom.h:351
#define LINETYPE
Definition: liblwgeom.h:85
uint8_t type
Definition: liblwgeom.h:417
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
uint8_t type
Definition: liblwgeom.h:476
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:43
void lwfree(void *mem)
Definition: lwutil.c:242
int npoints
Definition: liblwgeom.h:370
uint8_t type
Definition: liblwgeom.h:502
#define POLYGONTYPE
Definition: liblwgeom.h:86
uint8_t flags
Definition: liblwgeom.h:396
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:87
void lwline_free(LWLINE *line)
Definition: lwline.c:76
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:46
int32_t srid
Definition: liblwgeom.h:420
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:2341
POINTARRAY * point
Definition: liblwgeom.h:410
LWMLINE * lwmline_construct_empty(int srid, char hasz, char hasm)
Definition: lwmline.c:38
int32_t srid
Definition: liblwgeom.h:398
int ngeoms
Definition: liblwgeom.h:480
static LWGEOM * lwcollection_split(const LWCOLLECTION *lwcoll_in, const LWGEOM *blade_in)
double x
Definition: liblwgeom.h:327
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
uint8_t type
Definition: liblwgeom.h:463
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, 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:76
uint8_t flags
Definition: liblwgeom.h:368
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWGEOM ** geoms
Definition: liblwgeom.h:508
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:187
LWPOINT ** geoms
Definition: liblwgeom.h:469
int32_t srid
Definition: liblwgeom.h:505
double y
Definition: liblwgeom.h:327
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:139
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:89
LWLINE ** geoms
Definition: liblwgeom.h:482
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:156
static LWGEOM * lwpoly_split(const LWPOLY *lwpoly_in, const LWGEOM *blade_in)
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:235
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:84
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, char want3d)
uint8_t type
Definition: liblwgeom.h:395
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:451
void * lwalloc(size_t size)
Definition: lwutil.c:227
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:351
#define MULTILINETYPE
Definition: liblwgeom.h:88
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
LWLINE * lwline_clone_deep(const LWLINE *lwgeom)
Definition: lwline.c:118
int ngeoms
Definition: liblwgeom.h:467
uint8_t flags
Definition: liblwgeom.h:418
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
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:102
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:244
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
int p4d_same(const POINT4D *p1, const POINT4D *p2)
Definition: lwalgorithm.c:31
static LWGEOM * lwline_split_by_point(const LWLINE *lwgeom_in, const LWPOINT *blade_in)
POINTARRAY * points
Definition: liblwgeom.h:421