PostGIS  3.4.0dev-r@@SVN_REVISION@@
ptarray.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 (C) 2012-2021 Sandro Santilli <strk@kbt.io>
22  * Copyright (C) 2001-2006 Refractions Research Inc.
23  *
24  **********************************************************************/
25 
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 
31 #include "../postgis_config.h"
32 /*#define POSTGIS_DEBUG_LEVEL 4*/
33 #include "liblwgeom_internal.h"
34 #include "lwgeom_log.h"
35 
36 int
38 {
39  if ( ! pa ) return LW_FALSE;
40  return FLAGS_GET_Z(pa->flags);
41 }
42 
43 int
45 {
46  if ( ! pa ) return LW_FALSE;
47  return FLAGS_GET_M(pa->flags);
48 }
49 
51 ptarray_construct(char hasz, char hasm, uint32_t npoints)
52 {
53  POINTARRAY *pa = ptarray_construct_empty(hasz, hasm, npoints);
54  pa->npoints = npoints;
55  return pa;
56 }
57 
59 ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
60 {
61  POINTARRAY *pa = lwalloc(sizeof(POINTARRAY));
62  pa->serialized_pointlist = NULL;
63 
64  /* Set our dimensionality info on the bitmap */
65  pa->flags = lwflags(hasz, hasm, 0);
66 
67  /* We will be allocating a bit of room */
68  pa->npoints = 0;
69  pa->maxpoints = maxpoints;
70 
71  /* Allocate the coordinate array */
72  if ( maxpoints > 0 )
73  pa->serialized_pointlist = lwalloc(maxpoints * ptarray_point_size(pa));
74  else
75  pa->serialized_pointlist = NULL;
76 
77  return pa;
78 }
79 
80 /*
81 * Add a point into a pointarray. Only adds as many dimensions as the
82 * pointarray supports.
83 */
84 int
85 ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, uint32_t where)
86 {
87  if (!pa || !p)
88  return LW_FAILURE;
89  size_t point_size = ptarray_point_size(pa);
90  LWDEBUGF(5,"pa = %p; p = %p; where = %d", pa, p, where);
91  LWDEBUGF(5,"pa->npoints = %d; pa->maxpoints = %d", pa->npoints, pa->maxpoints);
92 
93  if ( FLAGS_GET_READONLY(pa->flags) )
94  {
95  lwerror("ptarray_insert_point: called on read-only point array");
96  return LW_FAILURE;
97  }
98 
99  /* Error on invalid offset value */
100  if ( where > pa->npoints )
101  {
102  lwerror("ptarray_insert_point: offset out of range (%d)", where);
103  return LW_FAILURE;
104  }
105 
106  /* If we have no storage, let's allocate some */
107  if( pa->maxpoints == 0 || ! pa->serialized_pointlist )
108  {
109  pa->maxpoints = 32;
110  pa->npoints = 0;
112  }
113 
114  /* Error out if we have a bad situation */
115  if ( pa->npoints > pa->maxpoints )
116  {
117  lwerror("npoints (%d) is greater than maxpoints (%d)", pa->npoints, pa->maxpoints);
118  return LW_FAILURE;
119  }
120 
121  /* Check if we have enough storage, add more if necessary */
122  if( pa->npoints == pa->maxpoints )
123  {
124  pa->maxpoints *= 2;
126  }
127 
128  /* Make space to insert the new point */
129  if( where < pa->npoints )
130  {
131  size_t copy_size = point_size * (pa->npoints - where);
132  memmove(getPoint_internal(pa, where+1), getPoint_internal(pa, where), copy_size);
133  LWDEBUGF(5,"copying %d bytes to start vertex %d from start vertex %d", copy_size, where+1, where);
134  }
135 
136  /* We have one more point */
137  ++pa->npoints;
138 
139  /* Copy the new point into the gap */
140  ptarray_set_point4d(pa, where, p);
141  LWDEBUGF(5,"copying new point to start vertex %d", point_size, where);
142 
143  return LW_SUCCESS;
144 }
145 
146 int
147 ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int repeated_points)
148 {
149  /* Check for pathology */
150  if( ! pa || ! pt )
151  {
152  lwerror("ptarray_append_point: null input");
153  return LW_FAILURE;
154  }
155 
156  /* Check for duplicate end point */
157  if ( repeated_points == LW_FALSE && pa->npoints > 0 )
158  {
159  POINT4D tmp;
160  getPoint4d_p(pa, pa->npoints-1, &tmp);
161  LWDEBUGF(4,"checking for duplicate end point (pt = POINT(%g %g) pa->npoints-q = POINT(%g %g))",pt->x,pt->y,tmp.x,tmp.y);
162 
163  /* Return LW_SUCCESS and do nothing else if previous point in list is equal to this one */
164  if ( (pt->x == tmp.x) && (pt->y == tmp.y) &&
165  (FLAGS_GET_Z(pa->flags) ? pt->z == tmp.z : 1) &&
166  (FLAGS_GET_M(pa->flags) ? pt->m == tmp.m : 1) )
167  {
168  return LW_SUCCESS;
169  }
170  }
171 
172  /* Append is just a special case of insert */
173  return ptarray_insert_point(pa, pt, pa->npoints);
174 }
175 
176 int
177 ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
178 {
179  unsigned int poff = 0;
180  unsigned int npoints;
181  unsigned int ncap;
182  unsigned int ptsize;
183 
184  /* Check for pathology */
185  if( ! pa1 || ! pa2 )
186  {
187  lwerror("ptarray_append_ptarray: null input");
188  return LW_FAILURE;
189  }
190 
191  npoints = pa2->npoints;
192 
193  if ( ! npoints ) return LW_SUCCESS; /* nothing more to do */
194 
195  if( FLAGS_GET_READONLY(pa1->flags) )
196  {
197  lwerror("ptarray_append_ptarray: target pointarray is read-only");
198  return LW_FAILURE;
199  }
200 
201  if( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) )
202  {
203  lwerror("ptarray_append_ptarray: appending mixed dimensionality is not allowed");
204  return LW_FAILURE;
205  }
206 
207  ptsize = ptarray_point_size(pa1);
208 
209  /* Check for duplicate end point */
210  if ( pa1->npoints )
211  {
212  POINT2D tmp1, tmp2;
213  getPoint2d_p(pa1, pa1->npoints-1, &tmp1);
214  getPoint2d_p(pa2, 0, &tmp2);
215 
216  /* If the end point and start point are the same, then don't copy start point */
217  if (p2d_same(&tmp1, &tmp2)) {
218  poff = 1;
219  --npoints;
220  }
221  else if ( gap_tolerance == 0 || ( gap_tolerance > 0 &&
222  distance2d_pt_pt(&tmp1, &tmp2) > gap_tolerance ) )
223  {
224  lwerror("Second line start point too far from first line end point");
225  return LW_FAILURE;
226  }
227  }
228 
229  /* Check if we need extra space */
230  ncap = pa1->npoints + npoints;
231  if ( pa1->maxpoints < ncap )
232  {
233  pa1->maxpoints = ncap > pa1->maxpoints*2 ?
234  ncap : pa1->maxpoints*2;
235  pa1->serialized_pointlist = lwrealloc(pa1->serialized_pointlist, ptsize * pa1->maxpoints);
236  }
237 
238  memcpy(getPoint_internal(pa1, pa1->npoints),
239  getPoint_internal(pa2, poff), ptsize * npoints);
240 
241  pa1->npoints = ncap;
242 
243  return LW_SUCCESS;
244 }
245 
246 /*
247 * Add a point into a pointarray. Only adds as many dimensions as the
248 * pointarray supports.
249 */
250 int
251 ptarray_remove_point(POINTARRAY *pa, uint32_t where)
252 {
253  /* Check for pathology */
254  if( ! pa )
255  {
256  lwerror("ptarray_remove_point: null input");
257  return LW_FAILURE;
258  }
259 
260  /* Error on invalid offset value */
261  if ( where >= pa->npoints )
262  {
263  lwerror("ptarray_remove_point: offset out of range (%d)", where);
264  return LW_FAILURE;
265  }
266 
267  /* If the point is any but the last, we need to copy the data back one point */
268  if (where < pa->npoints - 1)
269  memmove(getPoint_internal(pa, where),
270  getPoint_internal(pa, where + 1),
271  ptarray_point_size(pa) * (pa->npoints - where - 1));
272 
273  /* We have one less point */
274  pa->npoints--;
275 
276  return LW_SUCCESS;
277 }
278 
283 POINTARRAY* ptarray_construct_reference_data(char hasz, char hasm, uint32_t npoints, uint8_t *ptlist)
284 {
285  POINTARRAY *pa = lwalloc(sizeof(POINTARRAY));
286  LWDEBUGF(5, "hasz = %d, hasm = %d, npoints = %d, ptlist = %p", hasz, hasm, npoints, ptlist);
287  pa->flags = lwflags(hasz, hasm, 0);
288  FLAGS_SET_READONLY(pa->flags, 1); /* We don't own this memory, so we can't alter or free it. */
289  pa->npoints = npoints;
290  pa->maxpoints = npoints;
291  pa->serialized_pointlist = ptlist;
292  return pa;
293 }
294 
295 
296 POINTARRAY*
297 ptarray_construct_copy_data(char hasz, char hasm, uint32_t npoints, const uint8_t *ptlist)
298 {
299  POINTARRAY *pa = lwalloc(sizeof(POINTARRAY));
300 
301  pa->flags = lwflags(hasz, hasm, 0);
302  pa->npoints = npoints;
303  pa->maxpoints = npoints;
304 
305  if ( npoints > 0 )
306  {
307  pa->serialized_pointlist = lwalloc(ptarray_point_size(pa) * npoints);
308  memcpy(pa->serialized_pointlist, ptlist, ptarray_point_size(pa) * npoints);
309  }
310  else
311  {
312  pa->serialized_pointlist = NULL;
313  }
314 
315  return pa;
316 }
317 
318 void
320 {
321  if (pa)
322  {
323  if (pa->serialized_pointlist && (!FLAGS_GET_READONLY(pa->flags)))
325  lwfree(pa);
326  }
327 }
328 
329 
330 void
332 {
333  if (!pa->npoints)
334  return;
335  uint32_t i;
336  uint32_t last = pa->npoints - 1;
337  uint32_t mid = pa->npoints / 2;
338 
339  double *d = (double*)(pa->serialized_pointlist);
340  int j;
341  int ndims = FLAGS_NDIMS(pa->flags);
342  for (i = 0; i < mid; i++)
343  {
344  for (j = 0; j < ndims; j++)
345  {
346  double buf;
347  buf = d[i*ndims+j];
348  d[i*ndims+j] = d[(last-i)*ndims+j];
349  d[(last-i)*ndims+j] = buf;
350  }
351  }
352  return;
353 }
354 
355 
359 POINTARRAY*
361 {
362  uint32_t i;
363  double d;
364  POINT4D p;
365 
366  for (i=0 ; i < pa->npoints ; i++)
367  {
368  getPoint4d_p(pa, i, &p);
369  d = p.y;
370  p.y = p.x;
371  p.x = d;
372  ptarray_set_point4d(pa, i, &p);
373  }
374 
375  return pa;
376 }
377 
378 void
380 {
381  uint32_t i;
382  double d, *dp1, *dp2;
383  POINT4D p;
384 
385  dp1 = ((double*)&p)+(unsigned)o1;
386  dp2 = ((double*)&p)+(unsigned)o2;
387  for (i=0 ; i < pa->npoints ; i++)
388  {
389  getPoint4d_p(pa, i, &p);
390  d = *dp2;
391  *dp2 = *dp1;
392  *dp1 = d;
393  ptarray_set_point4d(pa, i, &p);
394  }
395 }
396 
404 POINTARRAY *
405 ptarray_segmentize2d(const POINTARRAY *ipa, double dist)
406 {
407  double segdist;
408  POINT4D p1, p2;
409  POINT4D pbuf;
410  POINTARRAY *opa;
411  uint32_t i, j, nseg;
412  int hasz = FLAGS_GET_Z(ipa->flags);
413  int hasm = FLAGS_GET_M(ipa->flags);
414 
415  pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;
416 
417  /* Initial storage */
418  opa = ptarray_construct_empty(hasz, hasm, ipa->npoints);
419 
420  /* Add first point */
421  getPoint4d_p(ipa, 0, &p1);
422  ptarray_append_point(opa, &p1, LW_FALSE);
423 
424  /* Loop on all other input points */
425  for (i = 1; i < ipa->npoints; i++)
426  {
427  /*
428  * We use these pointers to avoid
429  * "strict-aliasing rules break" warning raised
430  * by gcc (3.3 and up).
431  *
432  * It looks that casting a variable address (also
433  * referred to as "type-punned pointer")
434  * breaks those "strict" rules.
435  */
436  POINT4D *p1ptr=&p1, *p2ptr=&p2;
437  double segments;
438 
439  getPoint4d_p(ipa, i, &p2);
440 
441  segdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
442  /* Split input segment into shorter even chunks */
443  segments = ceil(segdist / dist);
444 
445  /* Uses INT32_MAX instead of UINT32_MAX to be safe that it fits */
446  if (segments >= INT32_MAX)
447  {
448  lwnotice("%s:%d - %s: Too many segments required (%e)",
449  __FILE__, __LINE__,__func__, segments);
450  ptarray_free(opa);
451  return NULL;
452  }
453  nseg = segments;
454 
455  for (j = 1; j < nseg; j++)
456  {
457  pbuf.x = p1.x + (p2.x - p1.x) * j / nseg;
458  pbuf.y = p1.y + (p2.y - p1.y) * j / nseg;
459  if (hasz)
460  pbuf.z = p1.z + (p2.z - p1.z) * j / nseg;
461  if (hasm)
462  pbuf.m = p1.m + (p2.m - p1.m) * j / nseg;
463  ptarray_append_point(opa, &pbuf, LW_FALSE);
464  LW_ON_INTERRUPT(ptarray_free(opa); return NULL);
465  }
466 
467  ptarray_append_point(opa, &p2, (ipa->npoints == 2) ? LW_TRUE : LW_FALSE);
468  p1 = p2;
469  LW_ON_INTERRUPT(ptarray_free(opa); return NULL);
470  }
471 
472  return opa;
473 }
474 
475 char
476 ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
477 {
478  uint32_t i;
479  size_t ptsize;
480 
481  if ( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) ) return LW_FALSE;
482  LWDEBUG(5,"dimensions are the same");
483 
484  if ( pa1->npoints != pa2->npoints ) return LW_FALSE;
485  LWDEBUG(5,"npoints are the same");
486 
487  ptsize = ptarray_point_size(pa1);
488  LWDEBUGF(5, "ptsize = %d", ptsize);
489 
490  for (i=0; i<pa1->npoints; i++)
491  {
492  if ( memcmp(getPoint_internal(pa1, i), getPoint_internal(pa2, i), ptsize) )
493  return LW_FALSE;
494  LWDEBUGF(5,"point #%d is the same",i);
495  }
496 
497  return LW_TRUE;
498 }
499 
500 char
501 ptarray_same2d(const POINTARRAY *pa1, const POINTARRAY *pa2)
502 {
503  uint32_t i;
504 
505  if ( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) ) return LW_FALSE;
506  LWDEBUG(5,"dimensions are the same");
507 
508  if ( pa1->npoints != pa2->npoints ) return LW_FALSE;
509  LWDEBUG(5,"npoints are the same");
510 
511  for (i=0; i<pa1->npoints; i++)
512  {
513  if ( memcmp(getPoint_internal(pa1, i), getPoint_internal(pa2, i), sizeof(POINT2D)) )
514  return LW_FALSE;
515  LWDEBUGF(5,"point #%d is the same",i);
516  }
517 
518  return LW_TRUE;
519 }
520 
521 POINTARRAY *
522 ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where)
523 {
524  POINTARRAY *ret;
525  POINT4D pbuf;
526  size_t ptsize = ptarray_point_size(pa);
527 
528  LWDEBUGF(3, "pa %x p %x size %d where %d",
529  pa, p, pdims, where);
530 
531  if ( pdims < 2 || pdims > 4 )
532  {
533  lwerror("ptarray_addPoint: point dimension out of range (%d)",
534  pdims);
535  return NULL;
536  }
537 
538  if ( where > pa->npoints )
539  {
540  lwerror("ptarray_addPoint: offset out of range (%d)",
541  where);
542  return NULL;
543  }
544 
545  LWDEBUG(3, "called with a %dD point");
546 
547  pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0.0;
548  memcpy((uint8_t *)&pbuf, p, pdims*sizeof(double));
549 
550  LWDEBUG(3, "initialized point buffer");
551 
553  FLAGS_GET_M(pa->flags), pa->npoints+1);
554 
555 
556  if ( where )
557  {
558  memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*where);
559  }
560 
561  memcpy(getPoint_internal(ret, where), (uint8_t *)&pbuf, ptsize);
562 
563  if ( where+1 != ret->npoints )
564  {
565  memcpy(getPoint_internal(ret, where+1),
566  getPoint_internal(pa, where),
567  ptsize*(pa->npoints-where));
568  }
569 
570  return ret;
571 }
572 
573 POINTARRAY *
574 ptarray_removePoint(POINTARRAY *pa, uint32_t which)
575 {
576  POINTARRAY *ret;
577  size_t ptsize = ptarray_point_size(pa);
578 
579  LWDEBUGF(3, "pa %x which %d", pa, which);
580 
581 #if PARANOIA_LEVEL > 0
582  if ( which > pa->npoints-1 )
583  {
584  lwerror("%s [%d] offset (%d) out of range (%d..%d)", __FILE__, __LINE__,
585  which, 0, pa->npoints-1);
586  return NULL;
587  }
588 
589  if ( pa->npoints < 3 )
590  {
591  lwerror("%s [%d] can't remove a point from a 2-vertex POINTARRAY", __FILE__, __LINE__);
592  return NULL;
593  }
594 #endif
595 
597  FLAGS_GET_M(pa->flags), pa->npoints-1);
598 
599  /* copy initial part */
600  if ( which )
601  {
602  memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which);
603  }
604 
605  /* copy final part */
606  if ( which < pa->npoints-1 )
607  {
608  memcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1),
609  ptsize*(pa->npoints-which-1));
610  }
611 
612  return ret;
613 }
614 
615 POINTARRAY *
617 {
618  POINTARRAY *pa;
619  size_t ptsize = ptarray_point_size(pa1);
620 
621  if (FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags))
622  lwerror("ptarray_cat: Mixed dimension");
623 
624  pa = ptarray_construct( FLAGS_GET_Z(pa1->flags),
625  FLAGS_GET_M(pa1->flags),
626  pa1->npoints + pa2->npoints);
627 
628  memcpy( getPoint_internal(pa, 0),
629  getPoint_internal(pa1, 0),
630  ptsize*(pa1->npoints));
631 
632  memcpy( getPoint_internal(pa, pa1->npoints),
633  getPoint_internal(pa2, 0),
634  ptsize*(pa2->npoints));
635 
636  ptarray_free(pa1);
637  ptarray_free(pa2);
638 
639  return pa;
640 }
641 
642 
646 POINTARRAY *
648 {
649  POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
650 
651  LWDEBUG(3, "ptarray_clone_deep called.");
652 
653  out->flags = in->flags;
654  out->npoints = in->npoints;
655  out->maxpoints = in->npoints;
656 
657  FLAGS_SET_READONLY(out->flags, 0);
658 
659  if (!in->npoints)
660  {
661  // Avoid calling lwalloc of 0 bytes
662  out->serialized_pointlist = NULL;
663  }
664  else
665  {
666  size_t size = in->npoints * ptarray_point_size(in);
667  out->serialized_pointlist = lwalloc(size);
668  memcpy(out->serialized_pointlist, in->serialized_pointlist, size);
669  }
670 
671  return out;
672 }
673 
677 POINTARRAY *
679 {
680  POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
681 
682  LWDEBUG(3, "ptarray_clone called.");
683 
684  out->flags = in->flags;
685  out->npoints = in->npoints;
686  out->maxpoints = in->maxpoints;
687 
688  FLAGS_SET_READONLY(out->flags, 1);
689 
691 
692  return out;
693 }
694 
699 int
701 {
702  if (!in)
703  {
704  lwerror("ptarray_is_closed: called with null point array");
705  return 0;
706  }
707  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
708 
709  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), ptarray_point_size(in));
710 }
711 
712 
713 int
715 {
716  if (!in)
717  {
718  lwerror("ptarray_is_closed_2d: called with null point array");
719  return 0;
720  }
721  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
722 
723  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT2D) );
724 }
725 
726 int
728 {
729  if (!in)
730  {
731  lwerror("ptarray_is_closed_3d: called with null point array");
732  return 0;
733  }
734  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
735 
736  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT3D) );
737 }
738 
739 int
741 {
742  if ( FLAGS_GET_Z(in->flags) )
743  return ptarray_is_closed_3d(in);
744  else
745  return ptarray_is_closed_2d(in);
746 }
747 
752 int
754 {
755  return ptarray_contains_point_partial(pa, pt, LW_TRUE, NULL);
756 }
757 
758 int
759 ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
760 {
761  int wn = 0;
762  uint32_t i;
763  double side;
764  const POINT2D *seg1;
765  const POINT2D *seg2;
766  double ymin, ymax;
767 
768  seg1 = getPoint2d_cp(pa, 0);
769  seg2 = getPoint2d_cp(pa, pa->npoints-1);
770  if ( check_closed && ! p2d_same(seg1, seg2) )
771  lwerror("ptarray_contains_point called on unclosed ring");
772 
773  for ( i=1; i < pa->npoints; i++ )
774  {
775  seg2 = getPoint2d_cp(pa, i);
776 
777  /* Zero length segments are ignored. */
778  if ( seg1->x == seg2->x && seg1->y == seg2->y )
779  {
780  seg1 = seg2;
781  continue;
782  }
783 
784  ymin = FP_MIN(seg1->y, seg2->y);
785  ymax = FP_MAX(seg1->y, seg2->y);
786 
787  /* Only test segments in our vertical range */
788  if ( pt->y > ymax || pt->y < ymin )
789  {
790  seg1 = seg2;
791  continue;
792  }
793 
794  side = lw_segment_side(seg1, seg2, pt);
795 
796  /*
797  * A point on the boundary of a ring is not contained.
798  * WAS: if (fabs(side) < 1e-12), see #852
799  */
800  if ( (side == 0) && lw_pt_in_seg(pt, seg1, seg2) )
801  {
802  return LW_BOUNDARY;
803  }
804 
805  /*
806  * If the point is to the left of the line, and it's rising,
807  * then the line is to the right of the point and
808  * circling counter-clockwise, so increment.
809  */
810  if ( (side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y) )
811  {
812  wn++;
813  }
814 
815  /*
816  * If the point is to the right of the line, and it's falling,
817  * then the line is to the right of the point and circling
818  * clockwise, so decrement.
819  */
820  else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) )
821  {
822  wn--;
823  }
824 
825  seg1 = seg2;
826  }
827 
828  /* Sent out the winding number for calls that are building on this as a primitive */
829  if ( winding_number )
830  *winding_number = wn;
831 
832  /* Outside */
833  if (wn == 0)
834  {
835  return LW_OUTSIDE;
836  }
837 
838  /* Inside */
839  return LW_INSIDE;
840 }
841 
851 int
853 {
854  return ptarrayarc_contains_point_partial(pa, pt, LW_TRUE /* Check closed*/, NULL);
855 }
856 
857 int
858 ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
859 {
860  int wn = 0;
861  uint32_t i;
862  int side;
863  const POINT2D *seg1;
864  const POINT2D *seg2;
865  const POINT2D *seg3;
866  GBOX gbox;
867 
868  /* Check for not an arc ring (always have odd # of points) */
869  if ( (pa->npoints % 2) == 0 )
870  {
871  lwerror("ptarrayarc_contains_point called with even number of points");
872  return LW_OUTSIDE;
873  }
874 
875  /* Check for not an arc ring (always have >= 3 points) */
876  if ( pa->npoints < 3 )
877  {
878  lwerror("ptarrayarc_contains_point called too-short pointarray");
879  return LW_OUTSIDE;
880  }
881 
882  /* Check for unclosed case */
883  seg1 = getPoint2d_cp(pa, 0);
884  seg3 = getPoint2d_cp(pa, pa->npoints-1);
885  if ( check_closed && ! p2d_same(seg1, seg3) )
886  {
887  lwerror("ptarrayarc_contains_point called on unclosed ring");
888  return LW_OUTSIDE;
889  }
890  /* OK, it's closed. Is it just one circle? */
891  else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
892  {
893  double radius, d;
894  POINT2D c;
895  seg2 = getPoint2d_cp(pa, 1);
896 
897  /* Wait, it's just a point, so it can't contain anything */
898  if ( lw_arc_is_pt(seg1, seg2, seg3) )
899  return LW_OUTSIDE;
900 
901  /* See if the point is within the circle radius */
902  radius = lw_arc_center(seg1, seg2, seg3, &c);
903  d = distance2d_pt_pt(pt, &c);
904  if ( FP_EQUALS(d, radius) )
905  return LW_BOUNDARY; /* Boundary of circle */
906  else if ( d < radius )
907  return LW_INSIDE; /* Inside circle */
908  else
909  return LW_OUTSIDE; /* Outside circle */
910  }
911  else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
912  {
913  return LW_BOUNDARY; /* Boundary case */
914  }
915 
916  /* Start on the ring */
917  seg1 = getPoint2d_cp(pa, 0);
918  for ( i=1; i < pa->npoints; i += 2 )
919  {
920  seg2 = getPoint2d_cp(pa, i);
921  seg3 = getPoint2d_cp(pa, i+1);
922 
923  /* Catch an easy boundary case */
924  if( p2d_same(seg3, pt) )
925  return LW_BOUNDARY;
926 
927  /* Skip arcs that have no size */
928  if ( lw_arc_is_pt(seg1, seg2, seg3) )
929  {
930  seg1 = seg3;
931  continue;
932  }
933 
934  /* Only test segments in our vertical range */
935  lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
936  if ( pt->y > gbox.ymax || pt->y < gbox.ymin )
937  {
938  seg1 = seg3;
939  continue;
940  }
941 
942  /* Outside of horizontal range, and not between end points we also skip */
943  if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) &&
944  (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) )
945  {
946  seg1 = seg3;
947  continue;
948  }
949 
950  side = lw_arc_side(seg1, seg2, seg3, pt);
951 
952  /* On the boundary */
953  if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
954  {
955  return LW_BOUNDARY;
956  }
957 
958  /* Going "up"! Point to left of arc. */
959  if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
960  {
961  wn++;
962  }
963 
964  /* Going "down"! */
965  if ( side > 0 && (seg3->y <= pt->y) && (pt->y < seg1->y) )
966  {
967  wn--;
968  }
969 
970  /* Inside the arc! */
971  if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin )
972  {
973  POINT2D C;
974  double radius = lw_arc_center(seg1, seg2, seg3, &C);
975  double d = distance2d_pt_pt(pt, &C);
976 
977  /* On the boundary! */
978  if ( d == radius )
979  return LW_BOUNDARY;
980 
981  /* Within the arc! */
982  if ( d < radius )
983  {
984  /* Left side, increment winding number */
985  if ( side < 0 )
986  wn++;
987  /* Right side, decrement winding number */
988  if ( side > 0 )
989  wn--;
990  }
991  }
992 
993  seg1 = seg3;
994  }
995 
996  /* Sent out the winding number for calls that are building on this as a primitive */
997  if ( winding_number )
998  *winding_number = wn;
999 
1000  /* Outside */
1001  if (wn == 0)
1002  {
1003  return LW_OUTSIDE;
1004  }
1005 
1006  /* Inside */
1007  return LW_INSIDE;
1008 }
1009 
1015 double
1017 {
1018  const POINT2D *P1;
1019  const POINT2D *P2;
1020  const POINT2D *P3;
1021  double sum = 0.0;
1022  double x0, x, y1, y2;
1023  uint32_t i;
1024 
1025  if (! pa || pa->npoints < 3 )
1026  return 0.0;
1027 
1028  P1 = getPoint2d_cp(pa, 0);
1029  P2 = getPoint2d_cp(pa, 1);
1030  x0 = P1->x;
1031  for ( i = 2; i < pa->npoints; i++ )
1032  {
1033  P3 = getPoint2d_cp(pa, i);
1034  x = P2->x - x0;
1035  y1 = P3->y;
1036  y2 = P1->y;
1037  sum += x * (y2-y1);
1038 
1039  /* Move forwards! */
1040  P1 = P2;
1041  P2 = P3;
1042  }
1043  return sum / 2.0;
1044 }
1045 
1046 int
1048 {
1049  double area = 0;
1050  area = ptarray_signed_area(pa);
1051  if ( area > 0 ) return LW_FALSE;
1052  else return LW_TRUE;
1053 }
1054 
1055 POINTARRAY*
1056 ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm, double zval, double mval)
1057 {
1058  /* TODO handle zero-length point arrays */
1059  uint32_t i;
1060  int in_hasz = FLAGS_GET_Z(pa->flags);
1061  int in_hasm = FLAGS_GET_M(pa->flags);
1062  POINT4D pt;
1063  POINTARRAY *pa_out = ptarray_construct_empty(hasz, hasm, pa->npoints);
1064 
1065  for( i = 0; i < pa->npoints; i++ )
1066  {
1067  getPoint4d_p(pa, i, &pt);
1068  if( hasz && ! in_hasz )
1069  pt.z = zval;
1070  if( hasm && ! in_hasm )
1071  pt.m = mval;
1072  ptarray_append_point(pa_out, &pt, LW_TRUE);
1073  }
1074 
1075  return pa_out;
1076 }
1077 
1078 POINTARRAY *
1079 ptarray_substring(POINTARRAY *ipa, double from, double to, double tolerance)
1080 {
1081  POINTARRAY *dpa;
1082  POINT4D pt;
1083  POINT4D p1, p2;
1084  POINT4D *p1ptr=&p1; /* don't break strict-aliasing rule */
1085  POINT4D *p2ptr=&p2;
1086  int nsegs, i;
1087  double length, slength, tlength;
1088  int state = 0; /* 0=before, 1=inside */
1089 
1090  /*
1091  * Create a dynamic pointarray with an initial capacity
1092  * equal to full copy of input points
1093  */
1095 
1096  /* Compute total line length */
1097  length = ptarray_length_2d(ipa);
1098 
1099 
1100  LWDEBUGF(3, "Total length: %g", length);
1101 
1102 
1103  /* Get 'from' and 'to' lengths */
1104  from = length*from;
1105  to = length*to;
1106 
1107 
1108  LWDEBUGF(3, "From/To: %g/%g", from, to);
1109 
1110 
1111  tlength = 0;
1112  getPoint4d_p(ipa, 0, &p1);
1113  nsegs = ipa->npoints - 1;
1114  for ( i = 0; i < nsegs; i++ )
1115  {
1116  double dseg;
1117 
1118  getPoint4d_p(ipa, i+1, &p2);
1119 
1120 
1121  LWDEBUGF(3 ,"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)",
1122  i, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m);
1123 
1124 
1125  /* Find the length of this segment */
1126  slength = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
1127 
1128  /*
1129  * We are before requested start.
1130  */
1131  if ( state == 0 ) /* before */
1132  {
1133 
1134  LWDEBUG(3, " Before start");
1135 
1136  if ( fabs ( from - ( tlength + slength ) ) <= tolerance )
1137  {
1138 
1139  LWDEBUG(3, " Second point is our start");
1140 
1141  /*
1142  * Second point is our start
1143  */
1144  ptarray_append_point(dpa, &p2, LW_FALSE);
1145  state=1; /* we're inside now */
1146  goto END;
1147  }
1148 
1149  else if ( fabs(from - tlength) <= tolerance )
1150  {
1151 
1152  LWDEBUG(3, " First point is our start");
1153 
1154  /*
1155  * First point is our start
1156  */
1157  ptarray_append_point(dpa, &p1, LW_FALSE);
1158 
1159  /*
1160  * We're inside now, but will check
1161  * 'to' point as well
1162  */
1163  state=1;
1164  }
1165 
1166  /*
1167  * Didn't reach the 'from' point,
1168  * nothing to do
1169  */
1170  else if ( from > tlength + slength ) goto END;
1171 
1172  else /* tlength < from < tlength+slength */
1173  {
1174 
1175  LWDEBUG(3, " Seg contains first point");
1176 
1177  /*
1178  * Our start is between first and
1179  * second point
1180  */
1181  dseg = (from - tlength) / slength;
1182 
1183  interpolate_point4d(&p1, &p2, &pt, dseg);
1184 
1185  ptarray_append_point(dpa, &pt, LW_FALSE);
1186 
1187  /*
1188  * We're inside now, but will check
1189  * 'to' point as well
1190  */
1191  state=1;
1192  }
1193  }
1194 
1195  if ( state == 1 ) /* inside */
1196  {
1197 
1198  LWDEBUG(3, " Inside");
1199 
1200  /*
1201  * 'to' point is our second point.
1202  */
1203  if ( fabs(to - ( tlength + slength ) ) <= tolerance )
1204  {
1205 
1206  LWDEBUG(3, " Second point is our end");
1207 
1208  ptarray_append_point(dpa, &p2, LW_FALSE);
1209  break; /* substring complete */
1210  }
1211 
1212  /*
1213  * 'to' point is our first point.
1214  * (should only happen if 'to' is 0)
1215  */
1216  else if ( fabs(to - tlength) <= tolerance )
1217  {
1218 
1219  LWDEBUG(3, " First point is our end");
1220 
1221  ptarray_append_point(dpa, &p1, LW_FALSE);
1222 
1223  break; /* substring complete */
1224  }
1225 
1226  /*
1227  * Didn't reach the 'end' point,
1228  * just copy second point
1229  */
1230  else if ( to > tlength + slength )
1231  {
1232  ptarray_append_point(dpa, &p2, LW_FALSE);
1233  goto END;
1234  }
1235 
1236  /*
1237  * 'to' point falls on this segment
1238  * Interpolate and break.
1239  */
1240  else if ( to < tlength + slength )
1241  {
1242 
1243  LWDEBUG(3, " Seg contains our end");
1244 
1245  dseg = (to - tlength) / slength;
1246  interpolate_point4d(&p1, &p2, &pt, dseg);
1247 
1248  ptarray_append_point(dpa, &pt, LW_FALSE);
1249 
1250  break;
1251  }
1252 
1253  else
1254  {
1255  LWDEBUG(3, "Unhandled case");
1256  }
1257  }
1258 
1259 
1260 END:
1261 
1262  tlength += slength;
1263  memcpy(&p1, &p2, sizeof(POINT4D));
1264  }
1265 
1266  LWDEBUGF(3, "Out of loop, ptarray has %d points", dpa->npoints);
1267 
1268  return dpa;
1269 }
1270 
1271 /*
1272  * Write into the *ret argument coordinates of the closes point on
1273  * the given segment to the reference input point.
1274  */
1275 void
1276 closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
1277 {
1278  double r;
1279 
1280  if ( FP_EQUALS(A->x, B->x) && FP_EQUALS(A->y, B->y) )
1281  {
1282  *ret = *A;
1283  return;
1284  }
1285 
1286  /*
1287  * We use comp.graphics.algorithms Frequently Asked Questions method
1288  *
1289  * (1) AC dot AB
1290  * r = ----------
1291  * ||AB||^2
1292  * r has the following meaning:
1293  * r=0 P = A
1294  * r=1 P = B
1295  * r<0 P is on the backward extension of AB
1296  * r>1 P is on the forward extension of AB
1297  * 0<r<1 P is interior to AB
1298  *
1299  */
1300  r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
1301 
1302  if (r<=0)
1303  {
1304  *ret = *A;
1305  return;
1306  }
1307  if (r>=1)
1308  {
1309  *ret = *B;
1310  return;
1311  }
1312 
1313  ret->x = A->x + ( (B->x - A->x) * r );
1314  ret->y = A->y + ( (B->y - A->y) * r );
1315  ret->z = A->z + ( (B->z - A->z) * r );
1316  ret->m = A->m + ( (B->m - A->m) * r );
1317 }
1318 
1319 int
1320 ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
1321 {
1322  const POINT2D *start = getPoint2d_cp(pa, 0), *end = NULL;
1323  uint32_t t, seg=0;
1324  double mindist=DBL_MAX;
1325 
1326  /* Loop through pointarray looking for nearest segment */
1327  for (t=1; t<pa->npoints; t++)
1328  {
1329  double dist_sqr;
1330  end = getPoint2d_cp(pa, t);
1331  dist_sqr = distance2d_sqr_pt_seg(qp, start, end);
1332 
1333  if (dist_sqr < mindist)
1334  {
1335  mindist = dist_sqr;
1336  seg=t-1;
1337  if ( mindist == 0 )
1338  {
1339  LWDEBUG(3, "Breaking on mindist=0");
1340  break;
1341  }
1342  }
1343 
1344  start = end;
1345  }
1346 
1347  if ( dist ) *dist = sqrt(mindist);
1348  return seg;
1349 }
1350 
1351 
1352 int
1353 ptarray_closest_vertex_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
1354 {
1355  uint32_t t, pn=0;
1356  const POINT2D *p;
1357  double mindist = DBL_MAX;
1358 
1359  /* Loop through pointarray looking for nearest segment */
1360  for (t=0; t<pa->npoints; t++)
1361  {
1362  double dist_sqr;
1363  p = getPoint2d_cp(pa, t);
1364  dist_sqr = distance2d_sqr_pt_pt(p, qp);
1365 
1366  if (dist_sqr < mindist)
1367  {
1368  mindist = dist_sqr;
1369  pn = t;
1370  if ( mindist == 0 )
1371  {
1372  LWDEBUG(3, "Breaking on mindist=0");
1373  break;
1374  }
1375  }
1376  }
1377  if ( dist ) *dist = sqrt(mindist);
1378  return pn;
1379 }
1380 
1381 /*
1382  * Given a point, returns the location of closest point on pointarray
1383  * and, optionally, it's actual distance from the point array.
1384  */
1385 double
1386 ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
1387 {
1388  double mindist=DBL_MAX;
1389  double tlen, plen;
1390  uint32_t t, seg=0;
1391  POINT4D start4d, end4d, projtmp;
1392  POINT2D proj, p;
1393  const POINT2D *start = NULL, *end = NULL;
1394 
1395  /* Initialize our 2D copy of the input parameter */
1396  p.x = p4d->x;
1397  p.y = p4d->y;
1398 
1399  if ( ! proj4d ) proj4d = &projtmp;
1400 
1401  /* Check for special cases (length 0 and 1) */
1402  if ( pa->npoints <= 1 )
1403  {
1404  if ( pa->npoints == 1 )
1405  {
1406  getPoint4d_p(pa, 0, proj4d);
1407  if ( mindistout )
1408  *mindistout = distance2d_pt_pt(&p, getPoint2d_cp(pa, 0));
1409  }
1410  return 0.0;
1411  }
1412 
1413  start = getPoint2d_cp(pa, 0);
1414  /* Loop through pointarray looking for nearest segment */
1415  for (t=1; t<pa->npoints; t++)
1416  {
1417  double dist_sqr;
1418  end = getPoint2d_cp(pa, t);
1419  dist_sqr = distance2d_sqr_pt_seg(&p, start, end);
1420 
1421  if (dist_sqr < mindist)
1422  {
1423  mindist = dist_sqr;
1424  seg=t-1;
1425  if ( mindist == 0 )
1426  {
1427  LWDEBUG(3, "Breaking on mindist=0");
1428  break;
1429  }
1430  }
1431 
1432  start = end;
1433  }
1434  mindist = sqrt(mindist);
1435 
1436  if ( mindistout ) *mindistout = mindist;
1437 
1438  LWDEBUGF(3, "Closest segment: %d", seg);
1439  LWDEBUGF(3, "mindist: %g", mindist);
1440 
1441  /*
1442  * We need to project the
1443  * point on the closest segment.
1444  */
1445  getPoint4d_p(pa, seg, &start4d);
1446  getPoint4d_p(pa, seg+1, &end4d);
1447  closest_point_on_segment(p4d, &start4d, &end4d, proj4d);
1448 
1449  /* Copy 4D values into 2D holder */
1450  proj.x = proj4d->x;
1451  proj.y = proj4d->y;
1452 
1453  LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints);
1454 
1455  /* For robustness, force 1 when closest point == endpoint */
1456  if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, end) )
1457  {
1458  return 1.0;
1459  }
1460 
1461  LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);
1462 
1463  tlen = ptarray_length_2d(pa);
1464 
1465  LWDEBUGF(3, "tlen %g", tlen);
1466 
1467  /* Location of any point on a zero-length line is 0 */
1468  /* See http://trac.osgeo.org/postgis/ticket/1772#comment:2 */
1469  if ( tlen == 0 ) return 0;
1470 
1471  plen=0;
1472  start = getPoint2d_cp(pa, 0);
1473  for (t=0; t<seg; t++, start=end)
1474  {
1475  end = getPoint2d_cp(pa, t+1);
1476  plen += distance2d_pt_pt(start, end);
1477 
1478  LWDEBUGF(4, "Segment %d made plen %g", t, plen);
1479  }
1480 
1481  plen+=distance2d_pt_pt(&proj, start);
1482 
1483  LWDEBUGF(3, "plen %g, tlen %g", plen, tlen);
1484 
1485  return plen/tlen;
1486 }
1487 
1497 void
1499 {
1500  uint32_t i;
1501  double x;
1502 
1503  for (i=0; i<pa->npoints; i++)
1504  {
1505  memcpy(&x, getPoint_internal(pa, i), sizeof(double));
1506  if ( x < 0 ) x+= 360;
1507  else if ( x > 180 ) x -= 360;
1508  memcpy(getPoint_internal(pa, i), &x, sizeof(double));
1509  }
1510 }
1511 
1512 
1513 /*
1514  * Returns a POINTARRAY with consecutive equal points
1515  * removed. Equality test on all dimensions of input.
1516  *
1517  * Always returns a newly allocated object.
1518  */
1519 static POINTARRAY *
1520 ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
1521 {
1522  POINTARRAY *out = ptarray_clone_deep(in);
1523  ptarray_remove_repeated_points_in_place(out, tolerance, minpoints);
1524  return out;
1525 }
1526 
1527 POINTARRAY *
1528 ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
1529 {
1530  return ptarray_remove_repeated_points_minpoints(in, tolerance, 2);
1531 }
1532 
1533 
1534 void
1535 ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
1536 {
1537  uint32_t i;
1538  double tolsq = tolerance * tolerance;
1539  const POINT2D *last = NULL;
1540  const POINT2D *pt;
1541  uint32_t n_points = pa->npoints;
1542  uint32_t n_points_out = 1;
1543  size_t pt_size = ptarray_point_size(pa);
1544 
1545  double dsq = FLT_MAX;
1546 
1547  /* No-op on short inputs */
1548  if ( n_points <= min_points ) return;
1549 
1550  last = getPoint2d_cp(pa, 0);
1551  void *p_to = ((char *)last) + pt_size;
1552  for (i = 1; i < n_points; i++)
1553  {
1554  int last_point = (i == n_points - 1);
1555 
1556  /* Look straight into the abyss */
1557  pt = getPoint2d_cp(pa, i);
1558 
1559  /* Don't drop points if we are running short of points */
1560  if (n_points + n_points_out > min_points + i)
1561  {
1562  if (tolerance > 0.0)
1563  {
1564  /* Only drop points that are within our tolerance */
1565  dsq = distance2d_sqr_pt_pt(last, pt);
1566  /* Allow any point but the last one to be dropped */
1567  if (!last_point && dsq <= tolsq)
1568  {
1569  continue;
1570  }
1571  }
1572  else
1573  {
1574  /* At tolerance zero, only skip exact dupes */
1575  if (memcmp((char*)pt, (char*)last, pt_size) == 0)
1576  continue;
1577  }
1578 
1579  /* Got to last point, and it's not very different from */
1580  /* the point that preceded it. We want to keep the last */
1581  /* point, not the second-to-last one, so we pull our write */
1582  /* index back one value */
1583  if (last_point && n_points_out > 1 && tolerance > 0.0 && dsq <= tolsq)
1584  {
1585  n_points_out--;
1586  p_to = (char*)p_to - pt_size;
1587  }
1588  }
1589 
1590  /* Compact all remaining values to front of array */
1591  memcpy(p_to, pt, pt_size);
1592  n_points_out++;
1593  p_to = (char*)p_to + pt_size;
1594  last = pt;
1595  }
1596  /* Adjust array length */
1597  pa->npoints = n_points_out;
1598  return;
1599 }
1600 
1601 /* Out of the points in pa [itfist .. itlast], finds the one that's farthest away from
1602  * the segment determined by pts[itfist] and pts[itlast].
1603  * Returns itfirst if no point was found futher away than max_distance_sqr
1604  */
1605 static uint32_t
1606 ptarray_dp_findsplit_in_place(const POINTARRAY *pts, uint32_t it_first, uint32_t it_last, double max_distance_sqr)
1607 {
1608  uint32_t split = it_first;
1609  if ((it_first - it_last) < 2)
1610  return it_first;
1611 
1612  const POINT2D *A = getPoint2d_cp(pts, it_first);
1613  const POINT2D *B = getPoint2d_cp(pts, it_last);
1614 
1615  if (distance2d_sqr_pt_pt(A, B) < DBL_EPSILON)
1616  {
1617  /* If p1 == p2, we can just calculate the distance from each point to A */
1618  for (uint32_t itk = it_first + 1; itk < it_last; itk++)
1619  {
1620  const POINT2D *pk = getPoint2d_cp(pts, itk);
1621  double distance_sqr = distance2d_sqr_pt_pt(pk, A);
1622  if (distance_sqr > max_distance_sqr)
1623  {
1624  split = itk;
1625  max_distance_sqr = distance_sqr;
1626  }
1627  }
1628  return split;
1629  }
1630 
1631  /* This is based on distance2d_sqr_pt_seg, but heavily inlined here to avoid recalculations */
1632  double ba_x = (B->x - A->x);
1633  double ba_y = (B->y - A->y);
1634  double ab_length_sqr = (ba_x * ba_x + ba_y * ba_y);
1635  /* To avoid the division by ab_length_sqr in the 3rd path, we normalize here
1636  * and multiply in the first two paths [(dot_ac_ab < 0) and (> ab_length_sqr)] */
1637  max_distance_sqr *= ab_length_sqr;
1638  for (uint32_t itk = it_first + 1; itk < it_last; itk++)
1639  {
1640  const POINT2D *C = getPoint2d_cp(pts, itk);
1641  double distance_sqr;
1642  double ca_x = (C->x - A->x);
1643  double ca_y = (C->y - A->y);
1644  double dot_ac_ab = (ca_x * ba_x + ca_y * ba_y);
1645 
1646  if (dot_ac_ab <= 0.0)
1647  {
1648  distance_sqr = distance2d_sqr_pt_pt(C, A) * ab_length_sqr;
1649  }
1650  else if (dot_ac_ab >= ab_length_sqr)
1651  {
1652  distance_sqr = distance2d_sqr_pt_pt(C, B) * ab_length_sqr;
1653  }
1654  else
1655  {
1656  double s_numerator = ca_x * ba_y - ca_y * ba_x;
1657  distance_sqr = s_numerator * s_numerator; /* Missing division by ab_length_sqr on purpose */
1658  }
1659 
1660  if (distance_sqr > max_distance_sqr)
1661  {
1662  split = itk;
1663  max_distance_sqr = distance_sqr;
1664  }
1665  }
1666  return split;
1667 }
1668 
1669 /* O(N) simplification for tolearnce = 0 */
1670 static void
1672 {
1673  uint32_t kept_it = 0;
1674  uint32_t last_it = pa->npoints - 1;
1675  const POINT2D *kept_pt = getPoint2d_cp(pa, 0);
1676  const size_t pt_size = ptarray_point_size(pa);
1677 
1678  for (uint32_t i = 1; i < last_it; i++)
1679  {
1680  const POINT2D *curr_pt = getPoint2d_cp(pa, i);
1681  const POINT2D *next_pt = getPoint2d_cp(pa, i + 1);
1682 
1683  double ba_x = next_pt->x - kept_pt->x;
1684  double ba_y = next_pt->y - kept_pt->y;
1685  double ab_length_sqr = ba_x * ba_x + ba_y * ba_y;
1686 
1687  double ca_x = curr_pt->x - kept_pt->x;
1688  double ca_y = curr_pt->y - kept_pt->y;
1689  double dot_ac_ab = ca_x * ba_x + ca_y * ba_y;
1690  double s_numerator = ca_x * ba_y - ca_y * ba_x;
1691 
1692  if (dot_ac_ab < 0.0 || dot_ac_ab > ab_length_sqr || s_numerator != 0)
1693  {
1694  kept_it++;
1695  kept_pt = curr_pt;
1696  if (kept_it != i)
1697  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1698  pa->serialized_pointlist + pt_size * i,
1699  pt_size);
1700  }
1701  }
1702 
1703  /* Append last point */
1704  kept_it++;
1705  if (kept_it != last_it)
1706  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1707  pa->serialized_pointlist + pt_size * last_it,
1708  pt_size);
1709  pa->npoints = kept_it + 1;
1710 }
1711 
1712 void
1713 ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
1714 {
1715  /* Do not try to simplify really short things */
1716  if (pa->npoints < 3 || pa->npoints <= minpts)
1717  return;
1718 
1719  if (tolerance == 0 && minpts <= 2)
1720  {
1722  return;
1723  }
1724 
1725  /* We use this array to keep track of the points we are keeping, so
1726  * we store just TRUE / FALSE in their position */
1727  uint8_t *kept_points = lwalloc(sizeof(uint8_t) * pa->npoints);
1728  memset(kept_points, LW_FALSE, sizeof(uint8_t) * pa->npoints);
1729  kept_points[0] = LW_TRUE;
1730  kept_points[pa->npoints - 1] = LW_TRUE;
1731  uint32_t keptn = 2;
1732 
1733  /* We use this array as a stack to store the iterators that we are going to need
1734  * in the following steps.
1735  * This is ~10% faster than iterating over @kept_points looking for them
1736  */
1737  uint32_t *iterator_stack = lwalloc(sizeof(uint32_t) * pa->npoints);
1738  iterator_stack[0] = 0;
1739  uint32_t iterator_stack_size = 1;
1740 
1741  uint32_t it_first = 0;
1742  uint32_t it_last = pa->npoints - 1;
1743 
1744  const double tolerance_sqr = tolerance * tolerance;
1745  /* For the first @minpts points we ignore the tolerance */
1746  double it_tol = keptn >= minpts ? tolerance_sqr : -1.0;
1747 
1748  while (iterator_stack_size)
1749  {
1750  uint32_t split = ptarray_dp_findsplit_in_place(pa, it_first, it_last, it_tol);
1751  if (split == it_first)
1752  {
1753  it_first = it_last;
1754  it_last = iterator_stack[--iterator_stack_size];
1755  }
1756  else
1757  {
1758  kept_points[split] = LW_TRUE;
1759  keptn++;
1760 
1761  iterator_stack[iterator_stack_size++] = it_last;
1762  it_last = split;
1763  it_tol = keptn >= minpts ? tolerance_sqr : -1.0;
1764  }
1765  }
1766 
1767  const size_t pt_size = ptarray_point_size(pa);
1768  /* The first point is already in place, so we don't need to copy it */
1769  size_t kept_it = 1;
1770  if (keptn == 2)
1771  {
1772  /* If there are 2 points remaining, it has to be first and last as
1773  * we added those at the start */
1774  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1775  pa->serialized_pointlist + pt_size * (pa->npoints - 1),
1776  pt_size);
1777  }
1778  else if (pa->npoints != keptn) /* We don't need to move any points if we are keeping them all */
1779  {
1780  for (uint32_t i = 1; i < pa->npoints; i++)
1781  {
1782  if (kept_points[i])
1783  {
1784  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1785  pa->serialized_pointlist + pt_size * i,
1786  pt_size);
1787  kept_it++;
1788  }
1789  }
1790  }
1791  pa->npoints = keptn;
1792 
1793  lwfree(kept_points);
1794  lwfree(iterator_stack);
1795 }
1796 
1797 /************************************************************************/
1798 
1804 double
1806 {
1807  double dist = 0.0;
1808  uint32_t i;
1809  const POINT2D *a1;
1810  const POINT2D *a2;
1811  const POINT2D *a3;
1812 
1813  if ( pts->npoints % 2 != 1 )
1814  lwerror("arc point array with even number of points");
1815 
1816  a1 = getPoint2d_cp(pts, 0);
1817 
1818  for ( i=2; i < pts->npoints; i += 2 )
1819  {
1820  a2 = getPoint2d_cp(pts, i-1);
1821  a3 = getPoint2d_cp(pts, i);
1822  dist += lw_arc_length(a1, a2, a3);
1823  a1 = a3;
1824  }
1825  return dist;
1826 }
1827 
1831 double
1833 {
1834  double dist = 0.0;
1835  uint32_t i;
1836  const POINT2D *frm;
1837  const POINT2D *to;
1838 
1839  if ( pts->npoints < 2 ) return 0.0;
1840 
1841  frm = getPoint2d_cp(pts, 0);
1842 
1843  for ( i=1; i < pts->npoints; i++ )
1844  {
1845  to = getPoint2d_cp(pts, i);
1846 
1847  dist += sqrt( ((frm->x - to->x)*(frm->x - to->x)) +
1848  ((frm->y - to->y)*(frm->y - to->y)) );
1849 
1850  frm = to;
1851  }
1852  return dist;
1853 }
1854 
1859 double
1861 {
1862  double dist = 0.0;
1863  uint32_t i;
1864  POINT3DZ frm;
1865  POINT3DZ to;
1866 
1867  if ( pts->npoints < 2 ) return 0.0;
1868 
1869  /* compute 2d length if 3d is not available */
1870  if ( ! FLAGS_GET_Z(pts->flags) ) return ptarray_length_2d(pts);
1871 
1872  getPoint3dz_p(pts, 0, &frm);
1873  for ( i=1; i < pts->npoints; i++ )
1874  {
1875  getPoint3dz_p(pts, i, &to);
1876  dist += sqrt( ((frm.x - to.x)*(frm.x - to.x)) +
1877  ((frm.y - to.y)*(frm.y - to.y)) +
1878  ((frm.z - to.z)*(frm.z - to.z)) );
1879  frm = to;
1880  }
1881  return dist;
1882 }
1883 
1884 
1885 
1889 void
1891 {
1892  if (FLAGS_GET_Z(pa->flags))
1893  {
1894  for (uint32_t i = 0; i < pa->npoints; i++)
1895  {
1896  POINT4D *p4d = (POINT4D *)(getPoint_internal(pa, i));
1897  double x = p4d->x;
1898  double y = p4d->y;
1899  double z = p4d->z;
1900  p4d->x = a->afac * x + a->bfac * y + a->cfac * z + a->xoff;
1901  p4d->y = a->dfac * x + a->efac * y + a->ffac * z + a->yoff;
1902  p4d->z = a->gfac * x + a->hfac * y + a->ifac * z + a->zoff;
1903  }
1904  }
1905  else
1906  {
1907  for (uint32_t i = 0; i < pa->npoints; i++)
1908  {
1909  POINT2D *pt = (POINT2D *)(getPoint_internal(pa, i));
1910  double x = pt->x;
1911  double y = pt->y;
1912  pt->x = a->afac * x + a->bfac * y + a->xoff;
1913  pt->y = a->dfac * x + a->efac * y + a->yoff;
1914  }
1915  }
1916 }
1917 
1922 #if 0
1923 static int gluInvertMatrix(const double *m, double *invOut)
1924 {
1925  double inv[16], det;
1926  int i;
1927 
1928  inv[0] = m[5] * m[10] * m[15] -
1929  m[5] * m[11] * m[14] -
1930  m[9] * m[6] * m[15] +
1931  m[9] * m[7] * m[14] +
1932  m[13] * m[6] * m[11] -
1933  m[13] * m[7] * m[10];
1934 
1935  inv[4] = -m[4] * m[10] * m[15] +
1936  m[4] * m[11] * m[14] +
1937  m[8] * m[6] * m[15] -
1938  m[8] * m[7] * m[14] -
1939  m[12] * m[6] * m[11] +
1940  m[12] * m[7] * m[10];
1941 
1942  inv[8] = m[4] * m[9] * m[15] -
1943  m[4] * m[11] * m[13] -
1944  m[8] * m[5] * m[15] +
1945  m[8] * m[7] * m[13] +
1946  m[12] * m[5] * m[11] -
1947  m[12] * m[7] * m[9];
1948 
1949  inv[12] = -m[4] * m[9] * m[14] +
1950  m[4] * m[10] * m[13] +
1951  m[8] * m[5] * m[14] -
1952  m[8] * m[6] * m[13] -
1953  m[12] * m[5] * m[10] +
1954  m[12] * m[6] * m[9];
1955 
1956  inv[1] = -m[1] * m[10] * m[15] +
1957  m[1] * m[11] * m[14] +
1958  m[9] * m[2] * m[15] -
1959  m[9] * m[3] * m[14] -
1960  m[13] * m[2] * m[11] +
1961  m[13] * m[3] * m[10];
1962 
1963  inv[5] = m[0] * m[10] * m[15] -
1964  m[0] * m[11] * m[14] -
1965  m[8] * m[2] * m[15] +
1966  m[8] * m[3] * m[14] +
1967  m[12] * m[2] * m[11] -
1968  m[12] * m[3] * m[10];
1969 
1970  inv[9] = -m[0] * m[9] * m[15] +
1971  m[0] * m[11] * m[13] +
1972  m[8] * m[1] * m[15] -
1973  m[8] * m[3] * m[13] -
1974  m[12] * m[1] * m[11] +
1975  m[12] * m[3] * m[9];
1976 
1977  inv[13] = m[0] * m[9] * m[14] -
1978  m[0] * m[10] * m[13] -
1979  m[8] * m[1] * m[14] +
1980  m[8] * m[2] * m[13] +
1981  m[12] * m[1] * m[10] -
1982  m[12] * m[2] * m[9];
1983 
1984  inv[2] = m[1] * m[6] * m[15] -
1985  m[1] * m[7] * m[14] -
1986  m[5] * m[2] * m[15] +
1987  m[5] * m[3] * m[14] +
1988  m[13] * m[2] * m[7] -
1989  m[13] * m[3] * m[6];
1990 
1991  inv[6] = -m[0] * m[6] * m[15] +
1992  m[0] * m[7] * m[14] +
1993  m[4] * m[2] * m[15] -
1994  m[4] * m[3] * m[14] -
1995  m[12] * m[2] * m[7] +
1996  m[12] * m[3] * m[6];
1997 
1998  inv[10] = m[0] * m[5] * m[15] -
1999  m[0] * m[7] * m[13] -
2000  m[4] * m[1] * m[15] +
2001  m[4] * m[3] * m[13] +
2002  m[12] * m[1] * m[7] -
2003  m[12] * m[3] * m[5];
2004 
2005  inv[14] = -m[0] * m[5] * m[14] +
2006  m[0] * m[6] * m[13] +
2007  m[4] * m[1] * m[14] -
2008  m[4] * m[2] * m[13] -
2009  m[12] * m[1] * m[6] +
2010  m[12] * m[2] * m[5];
2011 
2012  inv[3] = -m[1] * m[6] * m[11] +
2013  m[1] * m[7] * m[10] +
2014  m[5] * m[2] * m[11] -
2015  m[5] * m[3] * m[10] -
2016  m[9] * m[2] * m[7] +
2017  m[9] * m[3] * m[6];
2018 
2019  inv[7] = m[0] * m[6] * m[11] -
2020  m[0] * m[7] * m[10] -
2021  m[4] * m[2] * m[11] +
2022  m[4] * m[3] * m[10] +
2023  m[8] * m[2] * m[7] -
2024  m[8] * m[3] * m[6];
2025 
2026  inv[11] = -m[0] * m[5] * m[11] +
2027  m[0] * m[7] * m[9] +
2028  m[4] * m[1] * m[11] -
2029  m[4] * m[3] * m[9] -
2030  m[8] * m[1] * m[7] +
2031  m[8] * m[3] * m[5];
2032 
2033  inv[15] = m[0] * m[5] * m[10] -
2034  m[0] * m[6] * m[9] -
2035  m[4] * m[1] * m[10] +
2036  m[4] * m[2] * m[9] +
2037  m[8] * m[1] * m[6] -
2038  m[8] * m[2] * m[5];
2039 
2040  det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
2041 
2042  if (det == 0)
2043  return LW_FALSE;
2044 
2045  det = 1.0 / det;
2046 
2047  for (i = 0; i < 16; i++)
2048  invOut[i] = inv[i] * det;
2049 
2050  return LW_TRUE;
2051 }
2052 #endif
2053 
2057 void
2059 {
2060  uint32_t i;
2061  POINT4D p4d;
2062  LWDEBUG(3, "ptarray_scale start");
2063  for (i=0; i<pa->npoints; i++)
2064  {
2065  getPoint4d_p(pa, i, &p4d);
2066  p4d.x *= fact->x;
2067  p4d.y *= fact->y;
2068  p4d.z *= fact->z;
2069  p4d.m *= fact->m;
2070  ptarray_set_point4d(pa, i, &p4d);
2071  }
2072  LWDEBUG(3, "ptarray_scale end");
2073 }
2074 
2075 int
2077 {
2078  return getPoint4d_p(pa, 0, pt);
2079 }
2080 
2081 
2082 /*
2083  * Stick an array of points to the given gridspec.
2084  * Return "gridded" points in *outpts and their number in *outptsn.
2085  *
2086  * Two consecutive points falling on the same grid cell are collapsed
2087  * into one single point.
2088  *
2089  */
2090 void
2092 {
2093  uint32_t j = 0;
2094  POINT4D *p, *p_out = NULL;
2095  double x, y, z = 0, m = 0;
2096  uint32_t ndims = FLAGS_NDIMS(pa->flags);
2097  uint32_t has_z = FLAGS_GET_Z(pa->flags);
2098  uint32_t has_m = FLAGS_GET_M(pa->flags);
2099 
2100  for (uint32_t i = 0; i < pa->npoints; i++)
2101  {
2102  /* Look straight into the abyss */
2103  p = (POINT4D *)(getPoint_internal(pa, i));
2104  x = p->x;
2105  y = p->y;
2106  if (ndims > 2)
2107  z = p->z;
2108  if (ndims > 3)
2109  m = p->m;
2110 
2111  if (grid->xsize > 0)
2112  x = rint((x - grid->ipx) / grid->xsize) * grid->xsize + grid->ipx;
2113 
2114  if (grid->ysize > 0)
2115  y = rint((y - grid->ipy) / grid->ysize) * grid->ysize + grid->ipy;
2116 
2117  /* Read and round this point */
2118  /* Z is always in third position */
2119  if (has_z && grid->zsize > 0)
2120  z = rint((z - grid->ipz) / grid->zsize) * grid->zsize + grid->ipz;
2121 
2122  /* M might be in 3rd or 4th position */
2123  if (has_m && grid->msize > 0)
2124  {
2125  /* In POINT ZM, M is in 4th position, in POINT M, M is in 3rd position which is Z in POINT4D */
2126  if (has_z)
2127  m = rint((m - grid->ipm) / grid->msize) * grid->msize + grid->ipm;
2128  else
2129  z = rint((z - grid->ipm) / grid->msize) * grid->msize + grid->ipm;
2130  }
2131 
2132  /* Skip duplicates */
2133  if (p_out &&
2134  p_out->x == x &&
2135  p_out->y == y &&
2136  (ndims > 2 ? p_out->z == z : 1) &&
2137  (ndims > 3 ? p_out->m == m : 1))
2138  {
2139  continue;
2140  }
2141 
2142  /* Write rounded values into the next available point */
2143  p_out = (POINT4D *)(getPoint_internal(pa, j++));
2144  p_out->x = x;
2145  p_out->y = y;
2146  if (ndims > 2)
2147  p_out->z = z;
2148  if (ndims > 3)
2149  p_out->m = m;
2150  }
2151 
2152  /* Update output ptarray length */
2153  pa->npoints = j;
2154  return;
2155 }
2156 
2157 int
2158 ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox)
2159 {
2160  const POINT2D *pt;
2161  int n = 0;
2162  uint32_t i;
2163  for ( i = 0; i < pa->npoints; i++ )
2164  {
2165  pt = getPoint2d_cp(pa, i);
2166  if ( gbox_contains_point2d(gbox, pt) )
2167  n++;
2168  }
2169  return n;
2170 }
2171 
2172 
2173 /*
2174  * Reorder the vertices of a closed pointarray so that the
2175  * given point is the first/last one.
2176  *
2177  * Error out if pointarray is not closed or it does not
2178  * contain the given point.
2179  */
2180 int
2182 {
2183  POINTARRAY *tmp;
2184  int found;
2185  uint32_t it;
2186  int ptsize;
2187 
2188  if ( ! ptarray_is_closed_2d(pa) )
2189  {
2190  lwerror("ptarray_scroll_in_place: input POINTARRAY is not closed");
2191  return LW_FAILURE;
2192  }
2193 
2194  ptsize = ptarray_point_size(pa);
2195 
2196  /* Find the point in the array */
2197  found = 0;
2198  for ( it = 0; it < pa->npoints; ++it )
2199  {
2200  if ( ! memcmp(getPoint_internal(pa, it), pt, ptsize) )
2201  {
2202  found = 1;
2203  break;
2204  }
2205  }
2206 
2207  if ( ! found )
2208  {
2209  lwerror("ptarray_scroll_in_place: input POINTARRAY does not contain the given point");
2210  return LW_FAILURE;
2211  }
2212 
2213  if ( 0 == it )
2214  {
2215  /* Point is already the start/end point, just clone the input */
2216  return LW_SUCCESS;
2217  }
2218 
2219  /* TODO: reduce allocations */
2221 
2222  bzero(getPoint_internal(tmp, 0), ptsize * pa->npoints);
2223  /* Copy the block from found point to last point into the output array */
2224  memcpy(
2225  getPoint_internal(tmp, 0),
2226  getPoint_internal(pa, it),
2227  ptsize * ( pa->npoints - it )
2228  );
2229 
2230  /* Copy the block from second point to the found point into the last portion of the
2231  * return */
2232  memcpy(
2233  getPoint_internal(tmp, pa->npoints - it),
2234  getPoint_internal(pa, 1),
2235  ptsize * ( it )
2236  );
2237 
2238  /* Copy the resulting pointarray back to source one */
2239  memcpy(
2240  getPoint_internal(pa, 0),
2241  getPoint_internal(tmp, 0),
2242  ptsize * ( pa->npoints )
2243  );
2244 
2245  ptarray_free(tmp);
2246 
2247  return LW_SUCCESS;
2248 }
char * r
Definition: cu_in_wkt.c:24
int gbox_contains_point2d(const GBOX *g, const POINT2D *p)
Definition: gbox.c:350
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
Definition: gbox.c:453
#define LW_FALSE
Definition: liblwgeom.h:94
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:2398
#define LW_FAILURE
Definition: liblwgeom.h:96
void interpolate_point4d(const POINT4D *A, const POINT4D *B, POINT4D *I, double F)
Find interpolation point I between point A and point B so that the len(AI) == len(AB)*F and I falls o...
Definition: lwgeom_api.c:649
#define LW_SUCCESS
Definition: liblwgeom.h:97
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition: lwgeom_api.c:342
#define FLAGS_GET_READONLY(flags)
Definition: liblwgeom.h:169
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:165
int getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *point)
Definition: lwgeom_api.c:215
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:235
void lwfree(void *mem)
Definition: lwutil.c:242
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:179
#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:2408
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:180
void * lwalloc(size_t size)
Definition: lwutil.c:227
#define FLAGS_SET_READONLY(flags, value)
Definition: liblwgeom.h:176
lwflags_t lwflags(int hasz, int hasm, int geodetic)
Construct a new flags bitmask.
Definition: lwutil.c:471
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:369
enum LWORD_T LWORD
Ordinate names.
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
double lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns the length of a circular arc segment.
Definition: lwalgorithm.c:116
#define LW_ON_INTERRUPT(x)
#define FP_MAX(A, B)
#define FP_MIN(A, B)
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
Definition: lwalgorithm.c:226
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
Definition: lwalgorithm.c:176
#define FP_EQUALS(A, B)
int lw_pt_in_seg(const POINT2D *P, const POINT2D *A1, const POINT2D *A2)
Returns true if P is between A1/A2.
Definition: lwalgorithm.c:93
#define LW_OUTSIDE
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition: lwalgorithm.c:62
int lw_arc_is_pt(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if arc A is actually a point (all vertices are the same) .
Definition: lwalgorithm.c:103
int lw_pt_in_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if P is on the same side of the plane partition defined by A1/A3 as A2 is.
Definition: lwalgorithm.c:83
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:49
static double det(double m00, double m01, double m10, double m11)
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:177
#define INT32_MAX
Definition: lwin_wkt_lex.c:334
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:101
static double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: lwinline.h:35
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition: lwinline.h:58
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:77
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:759
POINTARRAY * ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm, double zval, double mval)
Definition: ptarray.c:1056
static uint32_t ptarray_dp_findsplit_in_place(const POINTARRAY *pts, uint32_t it_first, uint32_t it_last, double max_distance_sqr)
Definition: ptarray.c:1606
POINTARRAY * ptarray_construct_reference_data(char hasz, char hasm, uint32_t npoints, uint8_t *ptlist)
Build a new POINTARRAY, but on top of someone else's ordinate array.
Definition: ptarray.c:283
int ptarray_remove_point(POINTARRAY *pa, uint32_t where)
Remove a point from an existing POINTARRAY.
Definition: ptarray.c:251
void ptarray_longitude_shift(POINTARRAY *pa)
Longitude shift for a pointarray.
Definition: ptarray.c:1498
POINTARRAY * ptarray_construct_copy_data(char hasz, char hasm, uint32_t npoints, const uint8_t *ptlist)
Construct a new POINTARRAY, copying in the data from ptlist.
Definition: ptarray.c:297
int ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition: ptarray.c:1320
POINTARRAY * ptarray_clone(const POINTARRAY *in)
Clone a POINTARRAY object.
Definition: ptarray.c:678
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
Append a POINTARRAY, pa2 to the end of an existing POINTARRAY, pa1.
Definition: ptarray.c:177
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition: ptarray.c:331
int ptarray_closest_vertex_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition: ptarray.c:1353
int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt)
For POINTARRAYs representing CIRCULARSTRINGS.
Definition: ptarray.c:852
int ptarray_is_closed_2d(const POINTARRAY *in)
Definition: ptarray.c:714
int ptarray_is_closed_z(const POINTARRAY *in)
Definition: ptarray.c:740
double ptarray_length(const POINTARRAY *pts)
Find the 3d/2d length of the given POINTARRAY (depending on its dimensionality)
Definition: ptarray.c:1860
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:1016
POINTARRAY * ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where)
Add a point in a pointarray.
Definition: ptarray.c:522
void closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
Definition: ptarray.c:1276
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:2076
int ptarray_is_closed(const POINTARRAY *in)
Check for ring closure using whatever dimensionality is declared on the pointarray.
Definition: ptarray.c:700
POINTARRAY * ptarray_clone_deep(const POINTARRAY *in)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:647
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:51
void ptarray_grid_in_place(POINTARRAY *pa, const gridspec *grid)
Snap to grid.
Definition: ptarray.c:2091
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
Definition: ptarray.c:1832
char ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
Definition: ptarray.c:476
int ptarray_is_closed_3d(const POINTARRAY *in)
Definition: ptarray.c:727
void ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
Definition: ptarray.c:1535
POINTARRAY * ptarray_removePoint(POINTARRAY *pa, uint32_t which)
Remove a point from a pointarray.
Definition: ptarray.c:574
int ptarray_scroll_in_place(POINTARRAY *pa, const POINT4D *pt)
Definition: ptarray.c:2181
void ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
Definition: ptarray.c:1713
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, uint32_t where)
Insert a point into an existing POINTARRAY.
Definition: ptarray.c:85
double ptarray_arc_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY, using circular arc interpolation between each coordinate ...
Definition: ptarray.c:1805
POINTARRAY * ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
Definition: ptarray.c:1528
void ptarray_affine(POINTARRAY *pa, const AFFINE *a)
Affine transform a pointarray.
Definition: ptarray.c:1890
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return 1 if the point is inside the POINTARRAY, -1 if it is outside, and 0 if it is on the boundary.
Definition: ptarray.c:753
int ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:858
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:319
static void ptarray_simplify_in_place_tolerance0(POINTARRAY *pa)
Definition: ptarray.c:1671
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1047
int ptarray_has_z(const POINTARRAY *pa)
Definition: ptarray.c:37
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int repeated_points)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition: ptarray.c:147
void ptarray_scale(POINTARRAY *pa, const POINT4D *fact)
WARNING, make sure you send in only 16-member double arrays or obviously things will go pear-shaped f...
Definition: ptarray.c:2058
static POINTARRAY * ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
Definition: ptarray.c:1520
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2)
Swap ordinate values o1 and o2 on a given POINTARRAY.
Definition: ptarray.c:379
int ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox)
Definition: ptarray.c:2158
char ptarray_same2d(const POINTARRAY *pa1, const POINTARRAY *pa2)
Definition: ptarray.c:501
POINTARRAY * ptarray_substring(POINTARRAY *ipa, double from, double to, double tolerance)
@d1 start location (distance from start / total distance) @d2 end location (distance from start / tot...
Definition: ptarray.c:1079
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:616
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
Definition: ptarray.c:360
int ptarray_has_m(const POINTARRAY *pa)
Definition: ptarray.c:44
POINTARRAY * ptarray_segmentize2d(const POINTARRAY *ipa, double dist)
Returns a modified POINTARRAY so that no segment is longer than the given distance (computed using 2d...
Definition: ptarray.c:405
double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
Definition: ptarray.c:1386
double gfac
Definition: liblwgeom.h:332
double zoff
Definition: liblwgeom.h:332
double bfac
Definition: liblwgeom.h:332
double ifac
Definition: liblwgeom.h:332
double xoff
Definition: liblwgeom.h:332
double dfac
Definition: liblwgeom.h:332
double afac
Definition: liblwgeom.h:332
double ffac
Definition: liblwgeom.h:332
double cfac
Definition: liblwgeom.h:332
double hfac
Definition: liblwgeom.h:332
double efac
Definition: liblwgeom.h:332
double yoff
Definition: liblwgeom.h:332
double ymax
Definition: liblwgeom.h:357
double xmax
Definition: liblwgeom.h:355
double ymin
Definition: liblwgeom.h:356
double xmin
Definition: liblwgeom.h:354
double y
Definition: liblwgeom.h:390
double x
Definition: liblwgeom.h:390
double z
Definition: liblwgeom.h:396
double x
Definition: liblwgeom.h:396
double y
Definition: liblwgeom.h:396
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
lwflags_t flags
Definition: liblwgeom.h:431
uint32_t maxpoints
Definition: liblwgeom.h:428
uint32_t npoints
Definition: liblwgeom.h:427
uint8_t * serialized_pointlist
Definition: liblwgeom.h:434
double ipm
Definition: liblwgeom.h:1379
double zsize
Definition: liblwgeom.h:1382
double ysize
Definition: liblwgeom.h:1381
double xsize
Definition: liblwgeom.h:1380
double ipx
Definition: liblwgeom.h:1376
double msize
Definition: liblwgeom.h:1383
double ipy
Definition: liblwgeom.h:1377
double ipz
Definition: liblwgeom.h:1378
Snap-to-grid.
Definition: liblwgeom.h:1375