PostGIS  3.7.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 %zu 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 %zu", point_size);
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("%s: null input", __func__);
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("%s: target pointarray is read-only", __func__);
198  return LW_FAILURE;
199  }
200 
201  if( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) )
202  {
203  lwerror("%s: appending mixed dimensionality is not allowed", __func__);
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  const POINT2D *tmp1, *tmp2;
213  tmp1 = getPoint2d_cp(pa1, pa1->npoints-1);
214  tmp2 = getPoint2d_cp(pa2, 0);
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) ||
222  (gap_tolerance > 0 && 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  if ( pa1->maxpoints )
234  {
235  pa1->maxpoints = ncap > pa1->maxpoints*2 ?
236  ncap : pa1->maxpoints*2;
237  pa1->serialized_pointlist = lwrealloc(pa1->serialized_pointlist, (size_t)ptsize * pa1->maxpoints);
238  }
239  else
240  {
241  pa1->maxpoints = ncap;
242  pa1->serialized_pointlist = lwalloc((size_t)ptsize * pa1->maxpoints);
243  }
244  }
245 
246  memcpy(getPoint_internal(pa1, pa1->npoints),
247  getPoint_internal(pa2, poff), (size_t)ptsize * npoints);
248 
249  pa1->npoints = ncap;
250 
251  return LW_SUCCESS;
252 }
253 
254 /*
255 * Add a point into a pointarray. Only adds as many dimensions as the
256 * pointarray supports.
257 */
258 int
259 ptarray_remove_point(POINTARRAY *pa, uint32_t where)
260 {
261  /* Check for pathology */
262  if( ! pa )
263  {
264  lwerror("ptarray_remove_point: null input");
265  return LW_FAILURE;
266  }
267 
268  /* Error on invalid offset value */
269  if ( where >= pa->npoints )
270  {
271  lwerror("ptarray_remove_point: offset out of range (%d)", where);
272  return LW_FAILURE;
273  }
274 
275  /* If the point is any but the last, we need to copy the data back one point */
276  if (where < pa->npoints - 1)
277  memmove(getPoint_internal(pa, where),
278  getPoint_internal(pa, where + 1),
279  ptarray_point_size(pa) * (pa->npoints - where - 1));
280 
281  /* We have one less point */
282  pa->npoints--;
283 
284  return LW_SUCCESS;
285 }
286 
291 POINTARRAY* ptarray_construct_reference_data(char hasz, char hasm, uint32_t npoints, uint8_t *ptlist)
292 {
293  POINTARRAY *pa = lwalloc(sizeof(POINTARRAY));
294  LWDEBUGF(5, "hasz = %d, hasm = %d, npoints = %d, ptlist = %p", hasz, hasm, npoints, ptlist);
295  pa->flags = lwflags(hasz, hasm, 0);
296  FLAGS_SET_READONLY(pa->flags, 1); /* We don't own this memory, so we can't alter or free it. */
297  pa->npoints = npoints;
298  pa->maxpoints = npoints;
299  pa->serialized_pointlist = ptlist;
300  return pa;
301 }
302 
303 
304 POINTARRAY*
305 ptarray_construct_copy_data(char hasz, char hasm, uint32_t npoints, const uint8_t *ptlist)
306 {
307  POINTARRAY *pa = lwalloc(sizeof(POINTARRAY));
308 
309  pa->flags = lwflags(hasz, hasm, 0);
310  pa->npoints = npoints;
311  pa->maxpoints = npoints;
312 
313  if ( npoints > 0 )
314  {
315  pa->serialized_pointlist = lwalloc(ptarray_point_size(pa) * npoints);
316  memcpy(pa->serialized_pointlist, ptlist, ptarray_point_size(pa) * npoints);
317  }
318  else
319  {
320  pa->serialized_pointlist = NULL;
321  }
322 
323  return pa;
324 }
325 
326 void
328 {
329  if (pa)
330  {
331  if (pa->serialized_pointlist && (!FLAGS_GET_READONLY(pa->flags)))
333  lwfree(pa);
334  }
335 }
336 
337 
338 void
340 {
341  if (!pa->npoints)
342  return;
343  uint32_t i;
344  uint32_t last = pa->npoints - 1;
345  uint32_t mid = pa->npoints / 2;
346 
347  double *d = (double*)(pa->serialized_pointlist);
348  int j;
349  int ndims = FLAGS_NDIMS(pa->flags);
350  for (i = 0; i < mid; i++)
351  {
352  for (j = 0; j < ndims; j++)
353  {
354  double buf;
355  buf = d[i*ndims+j];
356  d[i*ndims+j] = d[(last-i)*ndims+j];
357  d[(last-i)*ndims+j] = buf;
358  }
359  }
360  return;
361 }
362 
363 
367 POINTARRAY*
369 {
370  uint32_t i;
371  double d;
372  POINT4D p;
373 
374  for (i=0 ; i < pa->npoints ; i++)
375  {
376  getPoint4d_p(pa, i, &p);
377  d = p.y;
378  p.y = p.x;
379  p.x = d;
380  ptarray_set_point4d(pa, i, &p);
381  }
382 
383  return pa;
384 }
385 
386 void
388 {
389  uint32_t i;
390  double d, *dp1, *dp2;
391  POINT4D p;
392 
393  dp1 = ((double*)&p)+(unsigned)o1;
394  dp2 = ((double*)&p)+(unsigned)o2;
395  for (i=0 ; i < pa->npoints ; i++)
396  {
397  getPoint4d_p(pa, i, &p);
398  d = *dp2;
399  *dp2 = *dp1;
400  *dp1 = d;
401  ptarray_set_point4d(pa, i, &p);
402  }
403 }
404 
412 POINTARRAY *
413 ptarray_segmentize2d(const POINTARRAY *ipa, double dist)
414 {
415  double segdist;
416  POINT4D p1, p2;
417  POINT4D pbuf;
418  POINTARRAY *opa;
419  uint32_t i, j, nseg;
420  int hasz = FLAGS_GET_Z(ipa->flags);
421  int hasm = FLAGS_GET_M(ipa->flags);
422 
423  pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;
424 
425  /* Initial storage */
426  opa = ptarray_construct_empty(hasz, hasm, ipa->npoints);
427 
428  /* Add first point */
429  getPoint4d_p(ipa, 0, &p1);
430  ptarray_append_point(opa, &p1, LW_FALSE);
431 
432  /* Loop on all other input points */
433  for (i = 1; i < ipa->npoints; i++)
434  {
435  /*
436  * We use these pointers to avoid
437  * "strict-aliasing rules break" warning raised
438  * by gcc (3.3 and up).
439  *
440  * It looks that casting a variable address (also
441  * referred to as "type-punned pointer")
442  * breaks those "strict" rules.
443  */
444  POINT4D *p1ptr=&p1, *p2ptr=&p2;
445  double segments;
446 
447  getPoint4d_p(ipa, i, &p2);
448 
449  segdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
450  /* Split input segment into shorter even chunks */
451  segments = ceil(segdist / dist);
452 
453  /* Uses INT32_MAX instead of UINT32_MAX to be safe that it fits */
454  if (segments >= INT32_MAX)
455  {
456  lwnotice("%s:%d - %s: Too many segments required (%e)",
457  __FILE__, __LINE__,__func__, segments);
458  ptarray_free(opa);
459  return NULL;
460  }
461  nseg = segments;
462 
463  for (j = 1; j < nseg; j++)
464  {
465  pbuf.x = p1.x + (p2.x - p1.x) * j / nseg;
466  pbuf.y = p1.y + (p2.y - p1.y) * j / nseg;
467  if (hasz)
468  pbuf.z = p1.z + (p2.z - p1.z) * j / nseg;
469  if (hasm)
470  pbuf.m = p1.m + (p2.m - p1.m) * j / nseg;
471  ptarray_append_point(opa, &pbuf, LW_FALSE);
472  LW_ON_INTERRUPT(ptarray_free(opa); return NULL);
473  }
474 
475  ptarray_append_point(opa, &p2, (ipa->npoints == 2) ? LW_TRUE : LW_FALSE);
476  p1 = p2;
477  LW_ON_INTERRUPT(ptarray_free(opa); return NULL);
478  }
479 
480  return opa;
481 }
482 
483 char
484 ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
485 {
486  uint32_t i;
487  size_t ptsize;
488 
489  if ( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) ) return LW_FALSE;
490  LWDEBUG(5,"dimensions are the same");
491 
492  if ( pa1->npoints != pa2->npoints ) return LW_FALSE;
493  LWDEBUG(5,"npoints are the same");
494 
495  ptsize = ptarray_point_size(pa1);
496  LWDEBUGF(5, "ptsize = %zu", ptsize);
497 
498  for (i=0; i<pa1->npoints; i++)
499  {
500  if ( memcmp(getPoint_internal(pa1, i), getPoint_internal(pa2, i), ptsize) )
501  return LW_FALSE;
502  LWDEBUGF(5,"point #%d is the same",i);
503  }
504 
505  return LW_TRUE;
506 }
507 
508 char
509 ptarray_same2d(const POINTARRAY *pa1, const POINTARRAY *pa2)
510 {
511  uint32_t i;
512 
513  if ( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) ) return LW_FALSE;
514  LWDEBUG(5,"dimensions are the same");
515 
516  if ( pa1->npoints != pa2->npoints ) return LW_FALSE;
517  LWDEBUG(5,"npoints are the same");
518 
519  for (i=0; i<pa1->npoints; i++)
520  {
521  if ( memcmp(getPoint_internal(pa1, i), getPoint_internal(pa2, i), sizeof(POINT2D)) )
522  return LW_FALSE;
523  LWDEBUGF(5,"point #%d is the same",i);
524  }
525 
526  return LW_TRUE;
527 }
528 
529 POINTARRAY *
530 ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where)
531 {
532  POINTARRAY *ret;
533  POINT4D pbuf;
534  size_t ptsize = ptarray_point_size(pa);
535 
536  LWDEBUGF(3, "pa %p p %p size %zu where %u",
537  pa, p, pdims, where);
538 
539  if ( pdims < 2 || pdims > 4 )
540  {
541  lwerror("ptarray_addPoint: point dimension out of range (%zu)",
542  pdims);
543  return NULL;
544  }
545 
546  if ( where > pa->npoints )
547  {
548  lwerror("ptarray_addPoint: offset out of range (%d)",
549  where);
550  return NULL;
551  }
552 
553  LWDEBUG(3, "called with a point");
554 
555  pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0.0;
556  memcpy((uint8_t *)&pbuf, p, pdims*sizeof(double));
557 
558  LWDEBUG(3, "initialized point buffer");
559 
561  FLAGS_GET_M(pa->flags), pa->npoints+1);
562 
563 
564  if ( where )
565  {
566  memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*where);
567  }
568 
569  memcpy(getPoint_internal(ret, where), (uint8_t *)&pbuf, ptsize);
570 
571  if ( where+1 != ret->npoints )
572  {
573  memcpy(getPoint_internal(ret, where+1),
574  getPoint_internal(pa, where),
575  ptsize*(pa->npoints-where));
576  }
577 
578  return ret;
579 }
580 
581 POINTARRAY *
582 ptarray_removePoint(POINTARRAY *pa, uint32_t which)
583 {
584  POINTARRAY *ret;
585  size_t ptsize = ptarray_point_size(pa);
586 
587  LWDEBUGF(3, "pa %p which %u", pa, which);
588 
589  assert(which <= pa->npoints-1);
590  assert(pa->npoints >= 3);
591 
593  FLAGS_GET_M(pa->flags), pa->npoints-1);
594 
595  /* copy initial part */
596  if ( which )
597  {
598  memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which);
599  }
600 
601  /* copy final part */
602  if ( which < pa->npoints-1 )
603  {
604  memcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1),
605  ptsize*(pa->npoints-which-1));
606  }
607 
608  return ret;
609 }
610 
611 POINTARRAY *
613 {
614  POINTARRAY *pa;
615  size_t ptsize = ptarray_point_size(pa1);
616 
617  if (FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags))
618  lwerror("ptarray_cat: Mixed dimension");
619 
620  pa = ptarray_construct( FLAGS_GET_Z(pa1->flags),
621  FLAGS_GET_M(pa1->flags),
622  pa1->npoints + pa2->npoints);
623 
624  memcpy( getPoint_internal(pa, 0),
625  getPoint_internal(pa1, 0),
626  ptsize*(pa1->npoints));
627 
628  memcpy( getPoint_internal(pa, pa1->npoints),
629  getPoint_internal(pa2, 0),
630  ptsize*(pa2->npoints));
631 
632  ptarray_free(pa1);
633  ptarray_free(pa2);
634 
635  return pa;
636 }
637 
638 
642 POINTARRAY *
644 {
645  POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
646 
647  LWDEBUG(3, "ptarray_clone_deep called.");
648 
649  out->flags = in->flags;
650  out->npoints = in->npoints;
651  out->maxpoints = in->npoints;
652 
653  FLAGS_SET_READONLY(out->flags, 0);
654 
655  if (!in->npoints)
656  {
657  // Avoid calling lwalloc of 0 bytes
658  out->serialized_pointlist = NULL;
659  }
660  else
661  {
662  size_t size = in->npoints * ptarray_point_size(in);
663  out->serialized_pointlist = lwalloc(size);
664  memcpy(out->serialized_pointlist, in->serialized_pointlist, size);
665  }
666 
667  return out;
668 }
669 
673 POINTARRAY *
675 {
676  POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
677 
678  LWDEBUG(3, "ptarray_clone called.");
679 
680  out->flags = in->flags;
681  out->npoints = in->npoints;
682  out->maxpoints = in->maxpoints;
683 
684  FLAGS_SET_READONLY(out->flags, 1);
685 
687 
688  return out;
689 }
690 
695 int
697 {
698  if (!in)
699  {
700  lwerror("ptarray_is_closed: called with null point array");
701  return 0;
702  }
703  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
704 
705  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), ptarray_point_size(in));
706 }
707 
708 
709 int
711 {
712  if (!in)
713  {
714  lwerror("ptarray_is_closed_2d: called with null point array");
715  return 0;
716  }
717  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
718 
719  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT2D) );
720 }
721 
722 int
724 {
725  if (!in)
726  {
727  lwerror("ptarray_is_closed_3d: called with null point array");
728  return 0;
729  }
730  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
731 
732  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT3D) );
733 }
734 
735 int
737 {
738  if ( FLAGS_GET_Z(in->flags) )
739  return ptarray_is_closed_3d(in);
740  else
741  return ptarray_is_closed_2d(in);
742 }
743 
754 int
756 {
757  const POINT2D *seg1, *seg2;
758  int wn = 0;
759 
760  seg1 = getPoint2d_cp(pa, 0);
761  seg2 = getPoint2d_cp(pa, pa->npoints-1);
762  if (!p2d_same(seg1, seg2))
763  lwerror("ptarray_contains_point called on unclosed ring");
764 
765  for (uint32_t i = 1; i < pa->npoints; i++)
766  {
767  double side, ymin, ymax;
768 
769  seg2 = getPoint2d_cp(pa, i);
770 
771  /* Zero length segments are ignored. */
772  if (p2d_same(seg1, seg2))
773  {
774  seg1 = seg2;
775  continue;
776  }
777 
778  ymin = FP_MIN(seg1->y, seg2->y);
779  ymax = FP_MAX(seg1->y, seg2->y);
780 
781  /* Only test segments in our vertical range */
782  if (pt->y > ymax || pt->y < ymin)
783  {
784  seg1 = seg2;
785  continue;
786  }
787 
788  side = lw_segment_side(seg1, seg2, pt);
789 
790  /*
791  * A point on the boundary of a ring is not contained.
792  * WAS: if (fabs(side) < 1e-12), see #852
793  */
794  if ((side == 0) && lw_pt_in_seg(pt, seg1, seg2))
795  {
796  return LW_BOUNDARY;
797  }
798 
799  /*
800  * If the point is to the left of the line, and it's rising,
801  * then the line is to the right of the point and
802  * circling counter-clockwise, so increment.
803  */
804  if ((side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y))
805  {
806  wn++;
807  }
808 
809  /*
810  * If the point is to the right of the line, and it's falling,
811  * then the line is to the right of the point and circling
812  * clockwise, so decrement.
813  */
814  else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) )
815  {
816  wn--;
817  }
818 
819  seg1 = seg2;
820  }
821 
822  /* wn == 0 => Outside, wn != 0 => Inside */
823  return wn == 0 ? LW_OUTSIDE : LW_INSIDE;
824 }
825 
826 int
827 ptarray_raycast_intersections(const POINTARRAY *pa, const POINT2D *p, int *on_boundary)
828 {
829  // A valid linestring must have at least 2 point
830  if (pa->npoints < 2)
831  lwerror("%s called on invalid linestring", __func__);
832 
833  int intersections = 0;
834  double px = p->x;
835  double py = p->y;
836 
837  // Iterate through each edge of the polygon
838  for (uint32_t i = 0; i < pa->npoints-1; ++i)
839  {
840  const POINT2D* p1 = getPoint2d_cp(pa, i);
841  const POINT2D* p2 = getPoint2d_cp(pa, i+1);
842 
843  /* Skip zero-length edges */
844  if (p2d_same(p1, p2))
845  continue;
846 
847  /* --- Step 1: Check if the point is ON the boundary edge --- */
848  if (lw_pt_on_segment(p1, p2, p))
849  {
850  *on_boundary = LW_TRUE;
851  return 0;
852  }
853 
854  /* --- Step 2: Perform the Ray Casting intersection test --- */
855 
856  /*
857  * Check if the horizontal ray from p intersects the edge (p1, p2).
858  * This is the core condition for handling vertices correctly:
859  * - One vertex must be strictly above the ray (py < vertex.y)
860  * - The other must be on or below the ray (py >= vertex.y)
861  */
862  if (((p1->y <= py) && (py < p2->y)) || ((p2->y <= py) && (py < p1->y)))
863  {
864  /*
865  * Calculate the x-coordinate where the edge intersects the ray's horizontal line.
866  * Formula: x = x1 + (y - y1) * (x2 - x1) / (y2 - y1)
867  */
868  double x_intersection = p1->x + (py - p1->y) * (p2->x - p1->x) / (p2->y - p1->y);
869 
870  /*
871  * If the intersection point is to the right of our test point,
872  * it's a valid "crossing".
873  */
874  if (x_intersection > px)
875  {
876  intersections++;
877  }
878  }
879  }
880 
881  return intersections;
882 }
883 
884 
902 static int
903 circle_raycast_intersections(const POINT2D *center, double radius, double ray, POINT2D *i0, POINT2D *i1)
904 {
905  // Calculate the vertical distance from the circle's center to the horizontal line.
906  double dy = ray - center->y;
907 
908  // If the absolute vertical distance is greater than the radius, there are no intersections.
909  if (fabs(dy) > radius)
910  return 0;
911 
912  // Use the Pythagorean theorem to find the horizontal distance (dx) from the
913  // center's x-coordinate to the intersection points.
914  // dx^2 + dy^2 = radius^2 => dx^2 = radius^2 - dy^2
915  double dx_squared = radius * radius - dy * dy;
916 
917  // Case 1: One intersection (tangent)
918  // This occurs when the line just touches the top or bottom of the circle.
919  // dx_squared will be zero. We check against a small epsilon for floating-point safety.
920  if (FP_EQUALS(dx_squared, 0.0))
921  {
922  i0->x = center->x;
923  i0->y = ray;
924  return 1;
925  }
926 
927  // Case 2: Two intersections
928  // The line cuts through the circle.
929  double dx = sqrt(dx_squared);
930 
931  // The first intersection point has the smaller x-value.
932  i0->x = center->x - dx;
933  i0->y = ray;
934 
935  // The second intersection point has the larger x-value.
936  i1->x = center->x + dx;
937  i1->y = ray;
938 
939  return 2;
940 }
941 
942 
943 int
944 ptarrayarc_raycast_intersections(const POINTARRAY *pa, const POINT2D *p, int *on_boundary)
945 {
946  int intersections = 0;
947  double px = p->x;
948  double py = p->y;
949 
950  assert(on_boundary);
951 
952  // A valid circular arc must have at least 3 vertices (circle).
953  if (pa->npoints < 3)
954  lwerror("%s called on invalid circularstring", __func__);
955 
956  if (pa->npoints % 2 == 0)
957  lwerror("%s called with even number of points", __func__);
958 
959  // Iterate through each arc of the circularstring
960  for (uint32_t i = 1; i < pa->npoints-1; i +=2)
961  {
962  const POINT2D* p0 = getPoint2d_cp(pa, i-1);
963  const POINT2D* p1 = getPoint2d_cp(pa, i);
964  const POINT2D* p2 = getPoint2d_cp(pa, i+1);
965  POINT2D center = {0,0};
966  double radius, d;
967  GBOX gbox;
968 
969  // Skip zero-length arc
970  if (lw_arc_is_pt(p0, p1, p2))
971  continue;
972 
973  // --- Step 1: Check if the point is ON the boundary edge ---
974  if (p2d_same(p0, p) || p2d_same(p1, p) || p2d_same(p2, p))
975  {
976  *on_boundary = LW_TRUE;
977  return 0;
978  }
979 
980  // Calculate some important pieces
981  radius = lw_arc_center(p0, p1, p2, &center);
982 
983  d = distance2d_pt_pt(p, &center);
984  if (FP_EQUALS(d, radius) && lw_pt_in_arc(p, p0, p1, p2))
985  {
986  *on_boundary = LW_TRUE;
987  return 0;
988  }
989 
990  // --- Step 2: Perform the Ray Casting intersection test ---
991 
992  // Only process arcs that our ray crosses
993  lw_arc_calculate_gbox_cartesian_2d(p0, p1, p2, &gbox);
994  if ((gbox.ymin <= py) && (py < gbox.ymax))
995  {
996  // Point of intersection on the circle that defines the arc
997  POINT2D i0, i1;
998 
999  // How many points of intersection are there
1000  int iCount = circle_raycast_intersections(&center, radius, py, &i0, &i1);
1001 
1002  // Nothing to see here
1003  if (iCount == 0)
1004  continue;
1005 
1006  // Cannot think of a case where a grazing is not a
1007  // no-op
1008  if (iCount == 1)
1009  continue;
1010 
1011  // So we must have 2 intersections
1012  // Only increment the counter for intersections to the right
1013  // of the test point
1014  if (i0.x > px && lw_pt_in_arc(&i0, p0, p1, p2))
1015  intersections++;
1016 
1017  if (i1.x > px && lw_pt_in_arc(&i1, p0, p1, p2))
1018  intersections++;
1019  }
1020  }
1021 
1022  return intersections;
1023 }
1024 
1025 /*
1026  * The following is based on the "Fast Winding Number Inclusion of a Point
1027  * in a Polygon" algorithm by Dan Sunday.
1028  * http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm#Winding%20Number
1029  */
1030 int
1031 ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
1032 {
1033  int wn = 0;
1034  uint32_t i;
1035  double side;
1036  const POINT2D *seg1, *seg2;
1037  double ymin, ymax;
1038 
1039  seg1 = getPoint2d_cp(pa, 0);
1040  seg2 = getPoint2d_cp(pa, pa->npoints-1);
1041  if ( check_closed && ! p2d_same(seg1, seg2) )
1042  lwerror("ptarray_contains_point called on unclosed ring");
1043 
1044  for ( i=1; i < pa->npoints; i++ )
1045  {
1046  seg2 = getPoint2d_cp(pa, i);
1047 
1048  /* Zero length segments are ignored. */
1049  if ( seg1->x == seg2->x && seg1->y == seg2->y )
1050  {
1051  seg1 = seg2;
1052  continue;
1053  }
1054 
1055  ymin = FP_MIN(seg1->y, seg2->y);
1056  ymax = FP_MAX(seg1->y, seg2->y);
1057 
1058  /* Only test segments in our vertical range */
1059  if ( pt->y > ymax || pt->y < ymin )
1060  {
1061  seg1 = seg2;
1062  continue;
1063  }
1064 
1065  side = lw_segment_side(seg1, seg2, pt);
1066 
1067  /*
1068  * A point on the boundary of a ring is not contained.
1069  * WAS: if (fabs(side) < 1e-12), see #852
1070  */
1071  if ( (side == 0) && lw_pt_in_seg(pt, seg1, seg2) )
1072  {
1073  return LW_BOUNDARY;
1074  }
1075 
1076  /*
1077  * If the point is to the left of the line, and it's rising,
1078  * then the line is to the right of the point and
1079  * circling counter-clockwise, so increment.
1080  */
1081  if ( (side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y) )
1082  {
1083  wn++;
1084  }
1085 
1086  /*
1087  * If the point is to the right of the line, and it's falling,
1088  * then the line is to the right of the point and circling
1089  * clockwise, so decrement.
1090  */
1091  else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) )
1092  {
1093  wn--;
1094  }
1095 
1096  seg1 = seg2;
1097  }
1098 
1099  /* Sent out the winding number for calls that are building on this as a primitive */
1100  if ( winding_number )
1101  *winding_number = wn;
1102 
1103  /* Outside */
1104  if (wn == 0)
1105  {
1106  return LW_OUTSIDE;
1107  }
1108 
1109  /* Inside */
1110  return LW_INSIDE;
1111 }
1112 
1122 int
1124 {
1125  int on_boundary = LW_FALSE;
1126  int intersections;
1127  if (!ptarray_is_closed_2d(pa))
1128  lwerror("%s called on unclosed ring", __func__);
1129 
1130  intersections = ptarrayarc_raycast_intersections(pa, pt, &on_boundary);
1131  if (on_boundary)
1132  return LW_BOUNDARY;
1133  else
1134  return (intersections % 2) ? LW_INSIDE : LW_OUTSIDE;
1135 }
1136 
1142 double
1144 {
1145  const POINT2D *P1;
1146  const POINT2D *P2;
1147  const POINT2D *P3;
1148  double sum = 0.0;
1149  double x0, x, y1, y2;
1150  uint32_t i;
1151 
1152  if (! pa || pa->npoints < 3 )
1153  return 0.0;
1154 
1155  P1 = getPoint2d_cp(pa, 0);
1156  P2 = getPoint2d_cp(pa, 1);
1157  x0 = P1->x;
1158  for ( i = 2; i < pa->npoints; i++ )
1159  {
1160  P3 = getPoint2d_cp(pa, i);
1161  x = P2->x - x0;
1162  y1 = P3->y;
1163  y2 = P1->y;
1164  sum += x * (y2-y1);
1165 
1166  /* Move forwards! */
1167  P1 = P2;
1168  P2 = P3;
1169  }
1170  return sum / 2.0;
1171 }
1172 
1173 int
1174 ptarray_has_orientation(const POINTARRAY *pa, int orientation)
1175 {
1176  if (ptarray_signed_area(pa) > 0)
1177  return orientation == LW_CLOCKWISE;
1178  else
1179  return orientation == LW_COUNTERCLOCKWISE;
1180 }
1181 
1183 {
1185 }
1186 
1187 POINTARRAY*
1188 ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm, double zval, double mval)
1189 {
1190  /* TODO handle zero-length point arrays */
1191  uint32_t i;
1192  int in_hasz = FLAGS_GET_Z(pa->flags);
1193  int in_hasm = FLAGS_GET_M(pa->flags);
1194  POINT4D pt;
1195  POINTARRAY *pa_out = ptarray_construct_empty(hasz, hasm, pa->npoints);
1196 
1197  for( i = 0; i < pa->npoints; i++ )
1198  {
1199  getPoint4d_p(pa, i, &pt);
1200  if( hasz && ! in_hasz )
1201  pt.z = zval;
1202  if( hasm && ! in_hasm )
1203  pt.m = mval;
1204  ptarray_append_point(pa_out, &pt, LW_TRUE);
1205  }
1206 
1207  return pa_out;
1208 }
1209 
1210 POINTARRAY *
1211 ptarray_substring(POINTARRAY *ipa, double from, double to, double tolerance)
1212 {
1213  POINTARRAY *dpa;
1214  POINT4D pt;
1215  POINT4D p1, p2;
1216  POINT4D *p1ptr=&p1; /* don't break strict-aliasing rule */
1217  POINT4D *p2ptr=&p2;
1218  int nsegs, i;
1219  double length, slength, tlength;
1220  int state = 0; /* 0=before, 1=inside */
1221 
1222  /*
1223  * Create a dynamic pointarray with an initial capacity
1224  * equal to full copy of input points
1225  */
1227 
1228  /* Compute total line length */
1229  length = ptarray_length_2d(ipa);
1230 
1231 
1232  LWDEBUGF(3, "Total length: %g", length);
1233 
1234 
1235  /* Get 'from' and 'to' lengths */
1236  from = length*from;
1237  to = length*to;
1238 
1239 
1240  LWDEBUGF(3, "From/To: %g/%g", from, to);
1241 
1242 
1243  tlength = 0;
1244  getPoint4d_p(ipa, 0, &p1);
1245  nsegs = ipa->npoints - 1;
1246  for ( i = 0; i < nsegs; i++ )
1247  {
1248  double dseg;
1249 
1250  getPoint4d_p(ipa, i+1, &p2);
1251 
1252 
1253  LWDEBUGF(3 ,"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)",
1254  i, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m);
1255 
1256 
1257  /* Find the length of this segment */
1258  slength = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
1259 
1260  /*
1261  * We are before requested start.
1262  */
1263  if ( state == 0 ) /* before */
1264  {
1265 
1266  LWDEBUG(3, " Before start");
1267 
1268  if ( fabs ( from - ( tlength + slength ) ) <= tolerance )
1269  {
1270 
1271  LWDEBUG(3, " Second point is our start");
1272 
1273  /*
1274  * Second point is our start
1275  */
1276  ptarray_append_point(dpa, &p2, LW_FALSE);
1277  state=1; /* we're inside now */
1278  goto END;
1279  }
1280 
1281  else if ( fabs(from - tlength) <= tolerance )
1282  {
1283 
1284  LWDEBUG(3, " First point is our start");
1285 
1286  /*
1287  * First point is our start
1288  */
1289  ptarray_append_point(dpa, &p1, LW_FALSE);
1290 
1291  /*
1292  * We're inside now, but will check
1293  * 'to' point as well
1294  */
1295  state=1;
1296  }
1297 
1298  /*
1299  * Didn't reach the 'from' point,
1300  * nothing to do
1301  */
1302  else if ( from > tlength + slength ) goto END;
1303 
1304  else /* tlength < from < tlength+slength */
1305  {
1306 
1307  LWDEBUG(3, " Seg contains first point");
1308 
1309  /*
1310  * Our start is between first and
1311  * second point
1312  */
1313  dseg = (from - tlength) / slength;
1314 
1315  interpolate_point4d(&p1, &p2, &pt, dseg);
1316 
1317  ptarray_append_point(dpa, &pt, LW_FALSE);
1318 
1319  /*
1320  * We're inside now, but will check
1321  * 'to' point as well
1322  */
1323  state=1;
1324  }
1325  }
1326 
1327  if ( state == 1 ) /* inside */
1328  {
1329 
1330  LWDEBUG(3, " Inside");
1331 
1332  /*
1333  * 'to' point is our second point.
1334  */
1335  if ( fabs(to - ( tlength + slength ) ) <= tolerance )
1336  {
1337 
1338  LWDEBUG(3, " Second point is our end");
1339 
1340  ptarray_append_point(dpa, &p2, LW_FALSE);
1341  break; /* substring complete */
1342  }
1343 
1344  /*
1345  * 'to' point is our first point.
1346  * (should only happen if 'to' is 0)
1347  */
1348  else if ( fabs(to - tlength) <= tolerance )
1349  {
1350 
1351  LWDEBUG(3, " First point is our end");
1352 
1353  ptarray_append_point(dpa, &p1, LW_FALSE);
1354 
1355  break; /* substring complete */
1356  }
1357 
1358  /*
1359  * Didn't reach the 'end' point,
1360  * just copy second point
1361  */
1362  else if ( to > tlength + slength )
1363  {
1364  ptarray_append_point(dpa, &p2, LW_FALSE);
1365  goto END;
1366  }
1367 
1368  /*
1369  * 'to' point falls on this segment
1370  * Interpolate and break.
1371  */
1372  else if ( to < tlength + slength )
1373  {
1374 
1375  LWDEBUG(3, " Seg contains our end");
1376 
1377  dseg = (to - tlength) / slength;
1378  interpolate_point4d(&p1, &p2, &pt, dseg);
1379 
1380  ptarray_append_point(dpa, &pt, LW_FALSE);
1381 
1382  break;
1383  }
1384 
1385  else
1386  {
1387  LWDEBUG(3, "Unhandled case");
1388  }
1389  }
1390 
1391 
1392 END:
1393 
1394  tlength += slength;
1395  memcpy(&p1, &p2, sizeof(POINT4D));
1396  }
1397 
1398  LWDEBUGF(3, "Out of loop, ptarray has %d points", dpa->npoints);
1399 
1400  return dpa;
1401 }
1402 
1403 /*
1404  * Write into the *ret argument coordinates of the closes point on
1405  * the given segment to the reference input point.
1406  */
1407 void
1408 closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
1409 {
1410  double r;
1411 
1412  if ( FP_EQUALS(A->x, B->x) && FP_EQUALS(A->y, B->y) )
1413  {
1414  *ret = *A;
1415  return;
1416  }
1417 
1418  /*
1419  * We use comp.graphics.algorithms Frequently Asked Questions method
1420  *
1421  * (1) AC dot AB
1422  * r = ----------
1423  * ||AB||^2
1424  * r has the following meaning:
1425  * r=0 P = A
1426  * r=1 P = B
1427  * r<0 P is on the backward extension of AB
1428  * r>1 P is on the forward extension of AB
1429  * 0<r<1 P is interior to AB
1430  *
1431  */
1432  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) );
1433 
1434  if (r<=0)
1435  {
1436  *ret = *A;
1437  return;
1438  }
1439  if (r>=1)
1440  {
1441  *ret = *B;
1442  return;
1443  }
1444 
1445  ret->x = A->x + ( (B->x - A->x) * r );
1446  ret->y = A->y + ( (B->y - A->y) * r );
1447  ret->z = A->z + ( (B->z - A->z) * r );
1448  ret->m = A->m + ( (B->m - A->m) * r );
1449 }
1450 
1451 int
1452 ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
1453 {
1454  const POINT2D *start = getPoint2d_cp(pa, 0), *end = NULL;
1455  uint32_t t, seg=0;
1456  double mindist=DBL_MAX;
1457 
1458  /* Loop through pointarray looking for nearest segment */
1459  for (t=1; t<pa->npoints; t++)
1460  {
1461  double dist_sqr;
1462  end = getPoint2d_cp(pa, t);
1463  dist_sqr = distance2d_sqr_pt_seg(qp, start, end);
1464 
1465  if (dist_sqr < mindist)
1466  {
1467  mindist = dist_sqr;
1468  seg=t-1;
1469  if ( mindist == 0 )
1470  {
1471  LWDEBUG(3, "Breaking on mindist=0");
1472  break;
1473  }
1474  }
1475 
1476  start = end;
1477  }
1478 
1479  if ( dist ) *dist = sqrt(mindist);
1480  return seg;
1481 }
1482 
1483 
1484 int
1485 ptarray_closest_vertex_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
1486 {
1487  uint32_t t, pn=0;
1488  const POINT2D *p;
1489  double mindist = DBL_MAX;
1490 
1491  /* Loop through pointarray looking for nearest segment */
1492  for (t=0; t<pa->npoints; t++)
1493  {
1494  double dist_sqr;
1495  p = getPoint2d_cp(pa, t);
1496  dist_sqr = distance2d_sqr_pt_pt(p, qp);
1497 
1498  if (dist_sqr < mindist)
1499  {
1500  mindist = dist_sqr;
1501  pn = t;
1502  if ( mindist == 0 )
1503  {
1504  LWDEBUG(3, "Breaking on mindist=0");
1505  break;
1506  }
1507  }
1508  }
1509  if ( dist ) *dist = sqrt(mindist);
1510  return pn;
1511 }
1512 
1513 /*
1514  * Given a point, returns the location of closest point on pointarray
1515  * and, optionally, it's actual distance from the point array.
1516  */
1517 double
1518 ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
1519 {
1520  double mindist=DBL_MAX;
1521  double tlen, plen;
1522  uint32_t t, seg=0;
1523  POINT4D start4d, end4d, projtmp;
1524  POINT2D proj, p;
1525  const POINT2D *start = NULL, *end = NULL;
1526 
1527  /* Initialize our 2D copy of the input parameter */
1528  p.x = p4d->x;
1529  p.y = p4d->y;
1530 
1531  if ( ! proj4d ) proj4d = &projtmp;
1532 
1533  /* Check for special cases (length 0 and 1) */
1534  if ( pa->npoints <= 1 )
1535  {
1536  if ( pa->npoints == 1 )
1537  {
1538  getPoint4d_p(pa, 0, proj4d);
1539  if ( mindistout )
1540  *mindistout = distance2d_pt_pt(&p, getPoint2d_cp(pa, 0));
1541  }
1542  return 0.0;
1543  }
1544 
1545  start = getPoint2d_cp(pa, 0);
1546  /* Loop through pointarray looking for nearest segment */
1547  for (t=1; t<pa->npoints; t++)
1548  {
1549  double dist_sqr;
1550  end = getPoint2d_cp(pa, t);
1551  dist_sqr = distance2d_sqr_pt_seg(&p, start, end);
1552 
1553  if (dist_sqr < mindist)
1554  {
1555  mindist = dist_sqr;
1556  seg=t-1;
1557  if ( mindist == 0 )
1558  {
1559  LWDEBUG(3, "Breaking on mindist=0");
1560  break;
1561  }
1562  }
1563 
1564  start = end;
1565  }
1566  mindist = sqrt(mindist);
1567 
1568  if ( mindistout ) *mindistout = mindist;
1569 
1570  LWDEBUGF(3, "Closest segment: %d", seg);
1571  LWDEBUGF(3, "mindist: %g", mindist);
1572 
1573  /*
1574  * We need to project the
1575  * point on the closest segment.
1576  */
1577  getPoint4d_p(pa, seg, &start4d);
1578  getPoint4d_p(pa, seg+1, &end4d);
1579  closest_point_on_segment(p4d, &start4d, &end4d, proj4d);
1580 
1581  /* Copy 4D values into 2D holder */
1582  proj.x = proj4d->x;
1583  proj.y = proj4d->y;
1584 
1585  LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints);
1586 
1587  /* For robustness, force 1 when closest point == endpoint */
1588  if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, end) )
1589  {
1590  return 1.0;
1591  }
1592 
1593  LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);
1594 
1595  tlen = ptarray_length_2d(pa);
1596 
1597  LWDEBUGF(3, "tlen %g", tlen);
1598 
1599  /* Location of any point on a zero-length line is 0 */
1600  /* See http://trac.osgeo.org/postgis/ticket/1772#comment:2 */
1601  if ( tlen == 0 ) return 0;
1602 
1603  plen=0;
1604  start = getPoint2d_cp(pa, 0);
1605  for (t=0; t<seg; t++, start=end)
1606  {
1607  end = getPoint2d_cp(pa, t+1);
1608  plen += distance2d_pt_pt(start, end);
1609 
1610  LWDEBUGF(4, "Segment %d made plen %g", t, plen);
1611  }
1612 
1613  plen+=distance2d_pt_pt(&proj, start);
1614 
1615  LWDEBUGF(3, "plen %g, tlen %g", plen, tlen);
1616 
1617  /* Floating point arithmetic is not reliable, make sure we return values [0,1] */
1618  double result = plen / tlen;
1619  if ( result < 0.0 ) {
1620  result = 0.0;
1621  } else if ( result > 1.0 ) {
1622  result = 1.0;
1623  }
1624  return result;
1625 }
1626 
1636 void
1638 {
1639  uint32_t i;
1640  double x;
1641 
1642  for (i=0; i<pa->npoints; i++)
1643  {
1644  memcpy(&x, getPoint_internal(pa, i), sizeof(double));
1645  if ( x < 0 ) x+= 360;
1646  else if ( x > 180 ) x -= 360;
1647  memcpy(getPoint_internal(pa, i), &x, sizeof(double));
1648  }
1649 }
1650 
1651 
1652 /*
1653  * Returns a POINTARRAY with consecutive equal points
1654  * removed. Equality test on all dimensions of input.
1655  *
1656  * Always returns a newly allocated object.
1657  */
1658 static POINTARRAY *
1659 ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
1660 {
1661  POINTARRAY *out = ptarray_clone_deep(in);
1662  ptarray_remove_repeated_points_in_place(out, tolerance, minpoints);
1663  return out;
1664 }
1665 
1666 POINTARRAY *
1667 ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
1668 {
1669  return ptarray_remove_repeated_points_minpoints(in, tolerance, 2);
1670 }
1671 
1672 
1673 void
1674 ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
1675 {
1676  uint32_t i;
1677  double tolsq = tolerance * tolerance;
1678  const POINT2D *last = NULL;
1679  const POINT2D *pt;
1680  uint32_t n_points = pa->npoints;
1681  uint32_t n_points_out = 1;
1682  size_t pt_size = ptarray_point_size(pa);
1683 
1684  double dsq = FLT_MAX;
1685 
1686  /* No-op on short inputs */
1687  if ( n_points <= min_points ) return;
1688 
1689  last = getPoint2d_cp(pa, 0);
1690  void *p_to = ((char *)last) + pt_size;
1691  for (i = 1; i < n_points; i++)
1692  {
1693  int last_point = (i == n_points - 1);
1694 
1695  /* Look straight into the abyss */
1696  pt = getPoint2d_cp(pa, i);
1697 
1698  /* Don't drop points if we are running short of points */
1699  if (n_points + n_points_out > min_points + i)
1700  {
1701  if (tolerance > 0.0)
1702  {
1703  /* Only drop points that are within our tolerance */
1704  dsq = distance2d_sqr_pt_pt(last, pt);
1705  /* Allow any point but the last one to be dropped */
1706  if (!last_point && dsq <= tolsq)
1707  {
1708  continue;
1709  }
1710  }
1711  else
1712  {
1713  /* At tolerance zero, only skip exact dupes */
1714  if (memcmp((char*)pt, (char*)last, pt_size) == 0)
1715  continue;
1716  }
1717 
1718  /* Got to last point, and it's not very different from */
1719  /* the point that preceded it. We want to keep the last */
1720  /* point, not the second-to-last one, so we pull our write */
1721  /* index back one value */
1722  if (last_point && n_points_out > 1 && tolerance > 0.0 && dsq <= tolsq)
1723  {
1724  n_points_out--;
1725  p_to = (char*)p_to - pt_size;
1726  }
1727  }
1728 
1729  /* Compact all remaining values to front of array */
1730  memcpy(p_to, pt, pt_size);
1731  n_points_out++;
1732  p_to = (char*)p_to + pt_size;
1733  last = pt;
1734  }
1735  /* Adjust array length */
1736  pa->npoints = n_points_out;
1737  return;
1738 }
1739 
1740 /* Out of the points in pa [itfist .. itlast], finds the one that's farthest away from
1741  * the segment determined by pts[itfist] and pts[itlast].
1742  * Returns itfirst if no point was found further away than max_distance_sqr
1743  */
1744 static uint32_t
1745 ptarray_dp_findsplit_in_place(const POINTARRAY *pts, uint32_t it_first, uint32_t it_last, double max_distance_sqr)
1746 {
1747  uint32_t split = it_first;
1748  if ((it_first - it_last) < 2)
1749  return it_first;
1750 
1751  const POINT2D *A = getPoint2d_cp(pts, it_first);
1752  const POINT2D *B = getPoint2d_cp(pts, it_last);
1753 
1754  if (distance2d_sqr_pt_pt(A, B) < DBL_EPSILON)
1755  {
1756  /* If p1 == p2, we can just calculate the distance from each point to A */
1757  for (uint32_t itk = it_first + 1; itk < it_last; itk++)
1758  {
1759  const POINT2D *pk = getPoint2d_cp(pts, itk);
1760  double distance_sqr = distance2d_sqr_pt_pt(pk, A);
1761  if (distance_sqr > max_distance_sqr)
1762  {
1763  split = itk;
1764  max_distance_sqr = distance_sqr;
1765  }
1766  }
1767  return split;
1768  }
1769 
1770  /* This is based on distance2d_sqr_pt_seg, but heavily inlined here to avoid recalculations */
1771  double ba_x = (B->x - A->x);
1772  double ba_y = (B->y - A->y);
1773  double ab_length_sqr = (ba_x * ba_x + ba_y * ba_y);
1774  /* To avoid the division by ab_length_sqr in the 3rd path, we normalize here
1775  * and multiply in the first two paths [(dot_ac_ab < 0) and (> ab_length_sqr)] */
1776  max_distance_sqr *= ab_length_sqr;
1777  for (uint32_t itk = it_first + 1; itk < it_last; itk++)
1778  {
1779  const POINT2D *C = getPoint2d_cp(pts, itk);
1780  double distance_sqr;
1781  double ca_x = (C->x - A->x);
1782  double ca_y = (C->y - A->y);
1783  double dot_ac_ab = (ca_x * ba_x + ca_y * ba_y);
1784 
1785  if (dot_ac_ab <= 0.0)
1786  {
1787  distance_sqr = distance2d_sqr_pt_pt(C, A) * ab_length_sqr;
1788  }
1789  else if (dot_ac_ab >= ab_length_sqr)
1790  {
1791  distance_sqr = distance2d_sqr_pt_pt(C, B) * ab_length_sqr;
1792  }
1793  else
1794  {
1795  double s_numerator = ca_x * ba_y - ca_y * ba_x;
1796  distance_sqr = s_numerator * s_numerator; /* Missing division by ab_length_sqr on purpose */
1797  }
1798 
1799  if (distance_sqr > max_distance_sqr)
1800  {
1801  split = itk;
1802  max_distance_sqr = distance_sqr;
1803  }
1804  }
1805  return split;
1806 }
1807 
1808 /* O(N) simplification for tolerance = 0 */
1809 static void
1811 {
1812  uint32_t kept_it = 0;
1813  uint32_t last_it = pa->npoints - 1;
1814  const POINT2D *kept_pt = getPoint2d_cp(pa, 0);
1815  const size_t pt_size = ptarray_point_size(pa);
1816 
1817  for (uint32_t i = 1; i < last_it; i++)
1818  {
1819  const POINT2D *curr_pt = getPoint2d_cp(pa, i);
1820  const POINT2D *next_pt = getPoint2d_cp(pa, i + 1);
1821 
1822  double ba_x = next_pt->x - kept_pt->x;
1823  double ba_y = next_pt->y - kept_pt->y;
1824  double ab_length_sqr = ba_x * ba_x + ba_y * ba_y;
1825 
1826  double ca_x = curr_pt->x - kept_pt->x;
1827  double ca_y = curr_pt->y - kept_pt->y;
1828  double dot_ac_ab = ca_x * ba_x + ca_y * ba_y;
1829  double s_numerator = ca_x * ba_y - ca_y * ba_x;
1830 
1831  if (p2d_same(kept_pt, next_pt) ||
1832  dot_ac_ab < 0.0 ||
1833  dot_ac_ab > ab_length_sqr ||
1834  s_numerator != 0)
1835 
1836  {
1837  kept_it++;
1838  kept_pt = curr_pt;
1839  if (kept_it != i)
1840  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1841  pa->serialized_pointlist + pt_size * i,
1842  pt_size);
1843  }
1844  }
1845 
1846  /* Append last point */
1847  kept_it++;
1848  if (kept_it != last_it)
1849  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1850  pa->serialized_pointlist + pt_size * last_it,
1851  pt_size);
1852  pa->npoints = kept_it + 1;
1853 }
1854 
1855 void
1856 ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
1857 {
1858  /* Do not try to simplify really short things */
1859  if (pa->npoints < 3 || pa->npoints <= minpts)
1860  return;
1861 
1862  if (tolerance == 0 && minpts <= 2)
1863  {
1865  return;
1866  }
1867 
1868  /* We use this array to keep track of the points we are keeping, so
1869  * we store just TRUE / FALSE in their position */
1870  uint8_t *kept_points = lwalloc(sizeof(uint8_t) * pa->npoints);
1871  memset(kept_points, LW_FALSE, sizeof(uint8_t) * pa->npoints);
1872  kept_points[0] = LW_TRUE;
1873  kept_points[pa->npoints - 1] = LW_TRUE;
1874  uint32_t keptn = 2;
1875 
1876  /* We use this array as a stack to store the iterators that we are going to need
1877  * in the following steps.
1878  * This is ~10% faster than iterating over @kept_points looking for them
1879  */
1880  uint32_t *iterator_stack = lwalloc(sizeof(uint32_t) * pa->npoints);
1881  iterator_stack[0] = 0;
1882  uint32_t iterator_stack_size = 1;
1883 
1884  uint32_t it_first = 0;
1885  uint32_t it_last = pa->npoints - 1;
1886 
1887  const double tolerance_sqr = tolerance * tolerance;
1888  /* For the first @minpts points we ignore the tolerance */
1889  double it_tol = keptn >= minpts ? tolerance_sqr : -1.0;
1890 
1891  while (iterator_stack_size)
1892  {
1893  uint32_t split = ptarray_dp_findsplit_in_place(pa, it_first, it_last, it_tol);
1894  if (split == it_first)
1895  {
1896  it_first = it_last;
1897  it_last = iterator_stack[--iterator_stack_size];
1898  }
1899  else
1900  {
1901  kept_points[split] = LW_TRUE;
1902  keptn++;
1903 
1904  iterator_stack[iterator_stack_size++] = it_last;
1905  it_last = split;
1906  it_tol = keptn >= minpts ? tolerance_sqr : -1.0;
1907  }
1908  }
1909 
1910  const size_t pt_size = ptarray_point_size(pa);
1911  /* The first point is already in place, so we don't need to copy it */
1912  size_t kept_it = 1;
1913  if (keptn == 2)
1914  {
1915  /* If there are 2 points remaining, it has to be first and last as
1916  * we added those at the start */
1917  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1918  pa->serialized_pointlist + pt_size * (pa->npoints - 1),
1919  pt_size);
1920  }
1921  else if (pa->npoints != keptn) /* We don't need to move any points if we are keeping them all */
1922  {
1923  for (uint32_t i = 1; i < pa->npoints; i++)
1924  {
1925  if (kept_points[i])
1926  {
1927  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1928  pa->serialized_pointlist + pt_size * i,
1929  pt_size);
1930  kept_it++;
1931  }
1932  }
1933  }
1934  pa->npoints = keptn;
1935 
1936  lwfree(kept_points);
1937  lwfree(iterator_stack);
1938 }
1939 
1940 /************************************************************************/
1941 
1947 double
1949 {
1950  double dist = 0.0;
1951  uint32_t i;
1952  const POINT2D *a1;
1953  const POINT2D *a2;
1954  const POINT2D *a3;
1955 
1956  if ( pts->npoints % 2 != 1 )
1957  lwerror("arc point array with even number of points");
1958 
1959  a1 = getPoint2d_cp(pts, 0);
1960 
1961  for ( i=2; i < pts->npoints; i += 2 )
1962  {
1963  a2 = getPoint2d_cp(pts, i-1);
1964  a3 = getPoint2d_cp(pts, i);
1965  dist += lw_arc_length(a1, a2, a3);
1966  a1 = a3;
1967  }
1968  return dist;
1969 }
1970 
1974 double
1976 {
1977  double dist = 0.0;
1978  uint32_t i;
1979  const POINT2D *frm;
1980  const POINT2D *to;
1981 
1982  if ( pts->npoints < 2 ) return 0.0;
1983 
1984  frm = getPoint2d_cp(pts, 0);
1985 
1986  for ( i=1; i < pts->npoints; i++ )
1987  {
1988  to = getPoint2d_cp(pts, i);
1989 
1990  dist += sqrt( ((frm->x - to->x)*(frm->x - to->x)) +
1991  ((frm->y - to->y)*(frm->y - to->y)) );
1992 
1993  frm = to;
1994  }
1995  return dist;
1996 }
1997 
2002 double
2004 {
2005  double dist = 0.0;
2006  uint32_t i;
2007  POINT3DZ frm;
2008  POINT3DZ to;
2009 
2010  if ( pts->npoints < 2 ) return 0.0;
2011 
2012  /* compute 2d length if 3d is not available */
2013  if ( ! FLAGS_GET_Z(pts->flags) ) return ptarray_length_2d(pts);
2014 
2015  getPoint3dz_p(pts, 0, &frm);
2016  for ( i=1; i < pts->npoints; i++ )
2017  {
2018  getPoint3dz_p(pts, i, &to);
2019  dist += sqrt( ((frm.x - to.x)*(frm.x - to.x)) +
2020  ((frm.y - to.y)*(frm.y - to.y)) +
2021  ((frm.z - to.z)*(frm.z - to.z)) );
2022  frm = to;
2023  }
2024  return dist;
2025 }
2026 
2027 
2028 
2032 void
2034 {
2035  if (FLAGS_GET_Z(pa->flags))
2036  {
2037  for (uint32_t i = 0; i < pa->npoints; i++)
2038  {
2039  POINT4D *p4d = (POINT4D *)(getPoint_internal(pa, i));
2040  double x = p4d->x;
2041  double y = p4d->y;
2042  double z = p4d->z;
2043  p4d->x = a->afac * x + a->bfac * y + a->cfac * z + a->xoff;
2044  p4d->y = a->dfac * x + a->efac * y + a->ffac * z + a->yoff;
2045  p4d->z = a->gfac * x + a->hfac * y + a->ifac * z + a->zoff;
2046  }
2047  }
2048  else
2049  {
2050  for (uint32_t i = 0; i < pa->npoints; i++)
2051  {
2052  POINT2D *pt = (POINT2D *)(getPoint_internal(pa, i));
2053  double x = pt->x;
2054  double y = pt->y;
2055  pt->x = a->afac * x + a->bfac * y + a->xoff;
2056  pt->y = a->dfac * x + a->efac * y + a->yoff;
2057  }
2058  }
2059 }
2060 
2065 #if 0
2066 static int gluInvertMatrix(const double *m, double *invOut)
2067 {
2068  double inv[16], det;
2069  int i;
2070 
2071  inv[0] = m[5] * m[10] * m[15] -
2072  m[5] * m[11] * m[14] -
2073  m[9] * m[6] * m[15] +
2074  m[9] * m[7] * m[14] +
2075  m[13] * m[6] * m[11] -
2076  m[13] * m[7] * m[10];
2077 
2078  inv[4] = -m[4] * m[10] * m[15] +
2079  m[4] * m[11] * m[14] +
2080  m[8] * m[6] * m[15] -
2081  m[8] * m[7] * m[14] -
2082  m[12] * m[6] * m[11] +
2083  m[12] * m[7] * m[10];
2084 
2085  inv[8] = m[4] * m[9] * m[15] -
2086  m[4] * m[11] * m[13] -
2087  m[8] * m[5] * m[15] +
2088  m[8] * m[7] * m[13] +
2089  m[12] * m[5] * m[11] -
2090  m[12] * m[7] * m[9];
2091 
2092  inv[12] = -m[4] * m[9] * m[14] +
2093  m[4] * m[10] * m[13] +
2094  m[8] * m[5] * m[14] -
2095  m[8] * m[6] * m[13] -
2096  m[12] * m[5] * m[10] +
2097  m[12] * m[6] * m[9];
2098 
2099  inv[1] = -m[1] * m[10] * m[15] +
2100  m[1] * m[11] * m[14] +
2101  m[9] * m[2] * m[15] -
2102  m[9] * m[3] * m[14] -
2103  m[13] * m[2] * m[11] +
2104  m[13] * m[3] * m[10];
2105 
2106  inv[5] = m[0] * m[10] * m[15] -
2107  m[0] * m[11] * m[14] -
2108  m[8] * m[2] * m[15] +
2109  m[8] * m[3] * m[14] +
2110  m[12] * m[2] * m[11] -
2111  m[12] * m[3] * m[10];
2112 
2113  inv[9] = -m[0] * m[9] * m[15] +
2114  m[0] * m[11] * m[13] +
2115  m[8] * m[1] * m[15] -
2116  m[8] * m[3] * m[13] -
2117  m[12] * m[1] * m[11] +
2118  m[12] * m[3] * m[9];
2119 
2120  inv[13] = m[0] * m[9] * m[14] -
2121  m[0] * m[10] * m[13] -
2122  m[8] * m[1] * m[14] +
2123  m[8] * m[2] * m[13] +
2124  m[12] * m[1] * m[10] -
2125  m[12] * m[2] * m[9];
2126 
2127  inv[2] = m[1] * m[6] * m[15] -
2128  m[1] * m[7] * m[14] -
2129  m[5] * m[2] * m[15] +
2130  m[5] * m[3] * m[14] +
2131  m[13] * m[2] * m[7] -
2132  m[13] * m[3] * m[6];
2133 
2134  inv[6] = -m[0] * m[6] * m[15] +
2135  m[0] * m[7] * m[14] +
2136  m[4] * m[2] * m[15] -
2137  m[4] * m[3] * m[14] -
2138  m[12] * m[2] * m[7] +
2139  m[12] * m[3] * m[6];
2140 
2141  inv[10] = m[0] * m[5] * m[15] -
2142  m[0] * m[7] * m[13] -
2143  m[4] * m[1] * m[15] +
2144  m[4] * m[3] * m[13] +
2145  m[12] * m[1] * m[7] -
2146  m[12] * m[3] * m[5];
2147 
2148  inv[14] = -m[0] * m[5] * m[14] +
2149  m[0] * m[6] * m[13] +
2150  m[4] * m[1] * m[14] -
2151  m[4] * m[2] * m[13] -
2152  m[12] * m[1] * m[6] +
2153  m[12] * m[2] * m[5];
2154 
2155  inv[3] = -m[1] * m[6] * m[11] +
2156  m[1] * m[7] * m[10] +
2157  m[5] * m[2] * m[11] -
2158  m[5] * m[3] * m[10] -
2159  m[9] * m[2] * m[7] +
2160  m[9] * m[3] * m[6];
2161 
2162  inv[7] = m[0] * m[6] * m[11] -
2163  m[0] * m[7] * m[10] -
2164  m[4] * m[2] * m[11] +
2165  m[4] * m[3] * m[10] +
2166  m[8] * m[2] * m[7] -
2167  m[8] * m[3] * m[6];
2168 
2169  inv[11] = -m[0] * m[5] * m[11] +
2170  m[0] * m[7] * m[9] +
2171  m[4] * m[1] * m[11] -
2172  m[4] * m[3] * m[9] -
2173  m[8] * m[1] * m[7] +
2174  m[8] * m[3] * m[5];
2175 
2176  inv[15] = m[0] * m[5] * m[10] -
2177  m[0] * m[6] * m[9] -
2178  m[4] * m[1] * m[10] +
2179  m[4] * m[2] * m[9] +
2180  m[8] * m[1] * m[6] -
2181  m[8] * m[2] * m[5];
2182 
2183  det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
2184 
2185  if (det == 0)
2186  return LW_FALSE;
2187 
2188  det = 1.0 / det;
2189 
2190  for (i = 0; i < 16; i++)
2191  invOut[i] = inv[i] * det;
2192 
2193  return LW_TRUE;
2194 }
2195 #endif
2196 
2200 void
2202 {
2203  uint32_t i;
2204  POINT4D p4d;
2205  LWDEBUG(3, "ptarray_scale start");
2206  for (i=0; i<pa->npoints; i++)
2207  {
2208  getPoint4d_p(pa, i, &p4d);
2209  p4d.x *= fact->x;
2210  p4d.y *= fact->y;
2211  p4d.z *= fact->z;
2212  p4d.m *= fact->m;
2213  ptarray_set_point4d(pa, i, &p4d);
2214  }
2215  LWDEBUG(3, "ptarray_scale end");
2216 }
2217 
2218 int
2220 {
2221  return getPoint4d_p(pa, 0, pt);
2222 }
2223 
2224 
2225 /*
2226  * Stick an array of points to the given gridspec.
2227  * Return "gridded" points in *outpts and their number in *outptsn.
2228  *
2229  * Two consecutive points falling on the same grid cell are collapsed
2230  * into one single point.
2231  *
2232  */
2233 void
2235 {
2236  uint32_t j = 0;
2237  POINT4D *p, *p_out = NULL;
2238  double x, y, z = 0, m = 0;
2239  uint32_t ndims = FLAGS_NDIMS(pa->flags);
2240  uint32_t has_z = FLAGS_GET_Z(pa->flags);
2241  uint32_t has_m = FLAGS_GET_M(pa->flags);
2242 
2243  for (uint32_t i = 0; i < pa->npoints; i++)
2244  {
2245  /* Look straight into the abyss */
2246  p = (POINT4D *)(getPoint_internal(pa, i));
2247  x = p->x;
2248  y = p->y;
2249  if (ndims > 2)
2250  z = p->z;
2251  if (ndims > 3)
2252  m = p->m;
2253 
2254  /*
2255  * See https://github.com/libgeos/geos/pull/956
2256  * We use scale for rounding when gridsize is < 1 and
2257  * gridsize for rounding when scale < 1.
2258  */
2259  if (grid->xsize > 0) {
2260  if (grid->xsize < 1)
2261  x = rint((x - grid->ipx) * grid->xscale) / grid->xscale + grid->ipx;
2262  else
2263  x = rint((x - grid->ipx) / grid->xsize) * grid->xsize + grid->ipx;
2264  }
2265 
2266  if (grid->ysize > 0) {
2267  if (grid->ysize < 1)
2268  y = rint((y - grid->ipy) * grid->yscale) / grid->yscale + grid->ipy;
2269  else
2270  y = rint((y - grid->ipy) / grid->ysize) * grid->ysize + grid->ipy;
2271  }
2272 
2273  /* Read and round this point */
2274  /* Z is always in third position */
2275  if (has_z && grid->zsize > 0)
2276  z = rint((z - grid->ipz) / grid->zsize) * grid->zsize + grid->ipz;
2277 
2278  /* M might be in 3rd or 4th position */
2279  if (has_m && grid->msize > 0)
2280  {
2281  /* In POINT ZM, M is in 4th position, in POINT M, M is in 3rd position which is Z in POINT4D */
2282  if (has_z)
2283  m = rint((m - grid->ipm) / grid->msize) * grid->msize + grid->ipm;
2284  else
2285  z = rint((z - grid->ipm) / grid->msize) * grid->msize + grid->ipm;
2286  }
2287 
2288  /* Skip duplicates */
2289  if (p_out &&
2290  p_out->x == x &&
2291  p_out->y == y &&
2292  (ndims > 2 ? p_out->z == z : 1) &&
2293  (ndims > 3 ? p_out->m == m : 1))
2294  {
2295  continue;
2296  }
2297 
2298  /* Write rounded values into the next available point */
2299  p_out = (POINT4D *)(getPoint_internal(pa, j++));
2300  p_out->x = x;
2301  p_out->y = y;
2302  if (ndims > 2)
2303  p_out->z = z;
2304  if (ndims > 3)
2305  p_out->m = m;
2306  }
2307 
2308  /* Update output ptarray length */
2309  pa->npoints = j;
2310  return;
2311 }
2312 
2313 int
2314 ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox)
2315 {
2316  const POINT2D *pt;
2317  int n = 0;
2318  uint32_t i;
2319  for ( i = 0; i < pa->npoints; i++ )
2320  {
2321  pt = getPoint2d_cp(pa, i);
2322  if ( gbox_contains_point2d(gbox, pt) )
2323  n++;
2324  }
2325  return n;
2326 }
2327 
2328 
2329 /*
2330  * Reorder the vertices of a closed pointarray so that the
2331  * given point is the first/last one.
2332  *
2333  * Error out if pointarray is not closed or it does not
2334  * contain the given point.
2335  */
2336 int
2338 {
2339  POINTARRAY *tmp;
2340  int found;
2341  uint32_t it;
2342  int ptsize;
2343 
2344  if ( ! ptarray_is_closed_2d(pa) )
2345  {
2346  lwerror("ptarray_scroll_in_place: input POINTARRAY is not closed");
2347  return LW_FAILURE;
2348  }
2349 
2350  ptsize = ptarray_point_size(pa);
2351 
2352  /* Find the point in the array */
2353  found = 0;
2354  for ( it = 0; it < pa->npoints; ++it )
2355  {
2356  if ( ! memcmp(getPoint_internal(pa, it), pt, ptsize) )
2357  {
2358  found = 1;
2359  break;
2360  }
2361  }
2362 
2363  if ( ! found )
2364  {
2365  lwerror("ptarray_scroll_in_place: input POINTARRAY does not contain the given point");
2366  return LW_FAILURE;
2367  }
2368 
2369  if ( 0 == it )
2370  {
2371  /* Point is already the start/end point, just clone the input */
2372  return LW_SUCCESS;
2373  }
2374 
2375  /* TODO: reduce allocations */
2377 
2378  memset(getPoint_internal(tmp, 0), 0, (size_t)ptsize * pa->npoints);
2379  /* Copy the block from found point to last point into the output array */
2380  memcpy(
2381  getPoint_internal(tmp, 0),
2382  getPoint_internal(pa, it),
2383  (size_t)ptsize * ( pa->npoints - it )
2384  );
2385 
2386  /* Copy the block from second point to the found point into the last portion of the
2387  * return */
2388  memcpy(
2389  getPoint_internal(tmp, pa->npoints - it),
2390  getPoint_internal(pa, 1),
2391  (size_t)ptsize * ( it )
2392  );
2393 
2394  /* Copy the resulting pointarray back to source one */
2395  memcpy(
2396  getPoint_internal(pa, 0),
2397  getPoint_internal(tmp, 0),
2398  (size_t)ptsize * ( pa->npoints )
2399  );
2400 
2401  ptarray_free(tmp);
2402 
2403  return LW_SUCCESS;
2404 }
char * r
Definition: cu_in_wkt.c:24
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
int gbox_contains_point2d(const GBOX *g, const POINT2D *p)
Definition: gbox.c:362
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
Definition: gbox.c:465
#define LW_FALSE
Definition: liblwgeom.h:94
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:2344
#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:646
#define LW_SUCCESS
Definition: liblwgeom.h:97
#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:242
void lwfree(void *mem)
Definition: lwutil.c:248
#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:2354
#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:477
#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_CLOCKWISE
Constants for orientation checking and forcing.
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
#define LW_COUNTERCLOCKWISE
double lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns the length of a circular arc segment.
Definition: lwalgorithm.c:134
#define LW_ON_INTERRUPT(x)
#define FP_MAX(A, B)
#define FP_MIN(A, B)
int lw_pt_on_segment(const POINT2D *p1, const POINT2D *p2, const POINT2D *p)
Definition: lwalgorithm.c:110
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:244
#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:103
#define LW_OUTSIDE
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition: lwalgorithm.c:70
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:121
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:91
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:57
static double det(double m00, double m01, double m10, double m11)
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
#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:97
static double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: lwinline.h:33
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition: lwinline.h:56
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:75
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:1031
POINTARRAY * ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm, double zval, double mval)
Definition: ptarray.c:1188
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:1745
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:291
int ptarray_remove_point(POINTARRAY *pa, uint32_t where)
Remove a point from an existing POINTARRAY.
Definition: ptarray.c:259
void ptarray_longitude_shift(POINTARRAY *pa)
Longitude shift for a pointarray.
Definition: ptarray.c:1637
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:305
int ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition: ptarray.c:1452
POINTARRAY * ptarray_clone(const POINTARRAY *in)
Clone a POINTARRAY object.
Definition: ptarray.c:674
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:339
int ptarray_closest_vertex_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition: ptarray.c:1485
int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt)
For POINTARRAYs representing CIRCULARSTRINGS.
Definition: ptarray.c:1123
int ptarray_is_closed_2d(const POINTARRAY *in)
Definition: ptarray.c:710
int ptarray_is_closed_z(const POINTARRAY *in)
Definition: ptarray.c:736
int ptarray_raycast_intersections(const POINTARRAY *pa, const POINT2D *p, int *on_boundary)
Definition: ptarray.c:827
double ptarray_length(const POINTARRAY *pts)
Find the 3d/2d length of the given POINTARRAY (depending on its dimensionality)
Definition: ptarray.c:2003
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:1143
POINTARRAY * ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where)
Add a point in a pointarray.
Definition: ptarray.c:530
void closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
Definition: ptarray.c:1408
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:2219
int ptarray_is_closed(const POINTARRAY *in)
Check for ring closure using whatever dimensionality is declared on the pointarray.
Definition: ptarray.c:696
POINTARRAY * ptarray_clone_deep(const POINTARRAY *in)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:643
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
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
Definition: ptarray.c:1975
char ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
Definition: ptarray.c:484
int ptarray_is_closed_3d(const POINTARRAY *in)
Definition: ptarray.c:723
void ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
Definition: ptarray.c:1674
int ptarrayarc_raycast_intersections(const POINTARRAY *pa, const POINT2D *p, int *on_boundary)
Definition: ptarray.c:944
POINTARRAY * ptarray_removePoint(POINTARRAY *pa, uint32_t which)
Remove a point from a pointarray.
Definition: ptarray.c:582
int ptarray_scroll_in_place(POINTARRAY *pa, const POINT4D *pt)
Definition: ptarray.c:2337
void ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
Definition: ptarray.c:1856
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, uint32_t where)
Insert a point into an existing POINTARRAY.
Definition: ptarray.c:85
void ptarray_grid_in_place(POINTARRAY *pa, gridspec *grid)
Snap to grid.
Definition: ptarray.c:2234
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:1948
POINTARRAY * ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
Definition: ptarray.c:1667
static int circle_raycast_intersections(const POINT2D *center, double radius, double ray, POINT2D *i0, POINT2D *i1)
Calculates the intersection points of a circle and a horizontal line.
Definition: ptarray.c:903
void ptarray_affine(POINTARRAY *pa, const AFFINE *a)
Affine transform a pointarray.
Definition: ptarray.c:2033
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
The following is based on the "Fast Winding Number Inclusion of a Point in a Polygon" algorithm by Da...
Definition: ptarray.c:755
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
int ptarray_has_orientation(const POINTARRAY *pa, int orientation)
Definition: ptarray.c:1174
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:327
static void ptarray_simplify_in_place_tolerance0(POINTARRAY *pa)
Definition: ptarray.c:1810
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1182
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:2201
static POINTARRAY * ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
Definition: ptarray.c:1659
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2)
Swap ordinate values o1 and o2 on a given POINTARRAY.
Definition: ptarray.c:387
int ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox)
Definition: ptarray.c:2314
char ptarray_same2d(const POINTARRAY *pa1, const POINTARRAY *pa2)
Definition: ptarray.c:509
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:1211
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:612
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
Definition: ptarray.c:368
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:413
double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
Definition: ptarray.c:1518
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 ymin
Definition: liblwgeom.h:356
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 xscale
Definition: liblwgeom.h:1409
double ipm
Definition: liblwgeom.h:1404
double zsize
Definition: liblwgeom.h:1407
double ysize
Definition: liblwgeom.h:1406
double xsize
Definition: liblwgeom.h:1405
double yscale
Definition: liblwgeom.h:1410
double ipx
Definition: liblwgeom.h:1401
double msize
Definition: liblwgeom.h:1408
double ipy
Definition: liblwgeom.h:1402
double ipz
Definition: liblwgeom.h:1403
Snap-to-grid.
Definition: liblwgeom.h:1400