PostGIS  3.0.6dev-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 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 POINTARRAY *
501 ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where)
502 {
503  POINTARRAY *ret;
504  POINT4D pbuf;
505  size_t ptsize = ptarray_point_size(pa);
506 
507  LWDEBUGF(3, "pa %x p %x size %d where %d",
508  pa, p, pdims, where);
509 
510  if ( pdims < 2 || pdims > 4 )
511  {
512  lwerror("ptarray_addPoint: point dimension out of range (%d)",
513  pdims);
514  return NULL;
515  }
516 
517  if ( where > pa->npoints )
518  {
519  lwerror("ptarray_addPoint: offset out of range (%d)",
520  where);
521  return NULL;
522  }
523 
524  LWDEBUG(3, "called with a %dD point");
525 
526  pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0.0;
527  memcpy((uint8_t *)&pbuf, p, pdims*sizeof(double));
528 
529  LWDEBUG(3, "initialized point buffer");
530 
532  FLAGS_GET_M(pa->flags), pa->npoints+1);
533 
534 
535  if ( where )
536  {
537  memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*where);
538  }
539 
540  memcpy(getPoint_internal(ret, where), (uint8_t *)&pbuf, ptsize);
541 
542  if ( where+1 != ret->npoints )
543  {
544  memcpy(getPoint_internal(ret, where+1),
545  getPoint_internal(pa, where),
546  ptsize*(pa->npoints-where));
547  }
548 
549  return ret;
550 }
551 
552 POINTARRAY *
553 ptarray_removePoint(POINTARRAY *pa, uint32_t which)
554 {
555  POINTARRAY *ret;
556  size_t ptsize = ptarray_point_size(pa);
557 
558  LWDEBUGF(3, "pa %x which %d", pa, which);
559 
560 #if PARANOIA_LEVEL > 0
561  if ( which > pa->npoints-1 )
562  {
563  lwerror("%s [%d] offset (%d) out of range (%d..%d)", __FILE__, __LINE__,
564  which, 0, pa->npoints-1);
565  return NULL;
566  }
567 
568  if ( pa->npoints < 3 )
569  {
570  lwerror("%s [%d] can't remove a point from a 2-vertex POINTARRAY", __FILE__, __LINE__);
571  return NULL;
572  }
573 #endif
574 
576  FLAGS_GET_M(pa->flags), pa->npoints-1);
577 
578  /* copy initial part */
579  if ( which )
580  {
581  memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which);
582  }
583 
584  /* copy final part */
585  if ( which < pa->npoints-1 )
586  {
587  memcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1),
588  ptsize*(pa->npoints-which-1));
589  }
590 
591  return ret;
592 }
593 
594 POINTARRAY *
596 {
597  POINTARRAY *pa;
598  size_t ptsize = ptarray_point_size(pa1);
599 
600  if (FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags))
601  lwerror("ptarray_cat: Mixed dimension");
602 
603  pa = ptarray_construct( FLAGS_GET_Z(pa1->flags),
604  FLAGS_GET_M(pa1->flags),
605  pa1->npoints + pa2->npoints);
606 
607  memcpy( getPoint_internal(pa, 0),
608  getPoint_internal(pa1, 0),
609  ptsize*(pa1->npoints));
610 
611  memcpy( getPoint_internal(pa, pa1->npoints),
612  getPoint_internal(pa2, 0),
613  ptsize*(pa2->npoints));
614 
615  ptarray_free(pa1);
616  ptarray_free(pa2);
617 
618  return pa;
619 }
620 
621 
625 POINTARRAY *
627 {
628  POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
629 
630  LWDEBUG(3, "ptarray_clone_deep called.");
631 
632  out->flags = in->flags;
633  out->npoints = in->npoints;
634  out->maxpoints = in->npoints;
635 
636  FLAGS_SET_READONLY(out->flags, 0);
637 
638  if (!in->npoints)
639  {
640  // Avoid calling lwalloc of 0 bytes
641  out->serialized_pointlist = NULL;
642  }
643  else
644  {
645  size_t size = in->npoints * ptarray_point_size(in);
646  out->serialized_pointlist = lwalloc(size);
647  memcpy(out->serialized_pointlist, in->serialized_pointlist, size);
648  }
649 
650  return out;
651 }
652 
656 POINTARRAY *
658 {
659  POINTARRAY *out = lwalloc(sizeof(POINTARRAY));
660 
661  LWDEBUG(3, "ptarray_clone called.");
662 
663  out->flags = in->flags;
664  out->npoints = in->npoints;
665  out->maxpoints = in->maxpoints;
666 
667  FLAGS_SET_READONLY(out->flags, 1);
668 
670 
671  return out;
672 }
673 
678 int
680 {
681  if (!in)
682  {
683  lwerror("ptarray_is_closed: called with null point array");
684  return 0;
685  }
686  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
687 
688  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), ptarray_point_size(in));
689 }
690 
691 
692 int
694 {
695  if (!in)
696  {
697  lwerror("ptarray_is_closed_2d: called with null point array");
698  return 0;
699  }
700  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
701 
702  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT2D) );
703 }
704 
705 int
707 {
708  if (!in)
709  {
710  lwerror("ptarray_is_closed_3d: called with null point array");
711  return 0;
712  }
713  if (in->npoints <= 1 ) return in->npoints; /* single-point are closed, empty not closed */
714 
715  return 0 == memcmp(getPoint_internal(in, 0), getPoint_internal(in, in->npoints-1), sizeof(POINT3D) );
716 }
717 
718 int
720 {
721  if ( FLAGS_GET_Z(in->flags) )
722  return ptarray_is_closed_3d(in);
723  else
724  return ptarray_is_closed_2d(in);
725 }
726 
731 int
733 {
734  return ptarray_contains_point_partial(pa, pt, LW_TRUE, NULL);
735 }
736 
737 int
738 ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
739 {
740  int wn = 0;
741  uint32_t i;
742  double side;
743  const POINT2D *seg1;
744  const POINT2D *seg2;
745  double ymin, ymax;
746 
747  seg1 = getPoint2d_cp(pa, 0);
748  seg2 = getPoint2d_cp(pa, pa->npoints-1);
749  if ( check_closed && ! p2d_same(seg1, seg2) )
750  lwerror("ptarray_contains_point called on unclosed ring");
751 
752  for ( i=1; i < pa->npoints; i++ )
753  {
754  seg2 = getPoint2d_cp(pa, i);
755 
756  /* Zero length segments are ignored. */
757  if ( seg1->x == seg2->x && seg1->y == seg2->y )
758  {
759  seg1 = seg2;
760  continue;
761  }
762 
763  ymin = FP_MIN(seg1->y, seg2->y);
764  ymax = FP_MAX(seg1->y, seg2->y);
765 
766  /* Only test segments in our vertical range */
767  if ( pt->y > ymax || pt->y < ymin )
768  {
769  seg1 = seg2;
770  continue;
771  }
772 
773  side = lw_segment_side(seg1, seg2, pt);
774 
775  /*
776  * A point on the boundary of a ring is not contained.
777  * WAS: if (fabs(side) < 1e-12), see #852
778  */
779  if ( (side == 0) && lw_pt_in_seg(pt, seg1, seg2) )
780  {
781  return LW_BOUNDARY;
782  }
783 
784  /*
785  * If the point is to the left of the line, and it's rising,
786  * then the line is to the right of the point and
787  * circling counter-clockwise, so increment.
788  */
789  if ( (side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y) )
790  {
791  wn++;
792  }
793 
794  /*
795  * If the point is to the right of the line, and it's falling,
796  * then the line is to the right of the point and circling
797  * clockwise, so decrement.
798  */
799  else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) )
800  {
801  wn--;
802  }
803 
804  seg1 = seg2;
805  }
806 
807  /* Sent out the winding number for calls that are building on this as a primitive */
808  if ( winding_number )
809  *winding_number = wn;
810 
811  /* Outside */
812  if (wn == 0)
813  {
814  return LW_OUTSIDE;
815  }
816 
817  /* Inside */
818  return LW_INSIDE;
819 }
820 
830 int
832 {
833  return ptarrayarc_contains_point_partial(pa, pt, LW_TRUE /* Check closed*/, NULL);
834 }
835 
836 int
837 ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
838 {
839  int wn = 0;
840  uint32_t i;
841  int side;
842  const POINT2D *seg1;
843  const POINT2D *seg2;
844  const POINT2D *seg3;
845  GBOX gbox;
846 
847  /* Check for not an arc ring (always have odd # of points) */
848  if ( (pa->npoints % 2) == 0 )
849  {
850  lwerror("ptarrayarc_contains_point called with even number of points");
851  return LW_OUTSIDE;
852  }
853 
854  /* Check for not an arc ring (always have >= 3 points) */
855  if ( pa->npoints < 3 )
856  {
857  lwerror("ptarrayarc_contains_point called too-short pointarray");
858  return LW_OUTSIDE;
859  }
860 
861  /* Check for unclosed case */
862  seg1 = getPoint2d_cp(pa, 0);
863  seg3 = getPoint2d_cp(pa, pa->npoints-1);
864  if ( check_closed && ! p2d_same(seg1, seg3) )
865  {
866  lwerror("ptarrayarc_contains_point called on unclosed ring");
867  return LW_OUTSIDE;
868  }
869  /* OK, it's closed. Is it just one circle? */
870  else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
871  {
872  double radius, d;
873  POINT2D c;
874  seg2 = getPoint2d_cp(pa, 1);
875 
876  /* Wait, it's just a point, so it can't contain anything */
877  if ( lw_arc_is_pt(seg1, seg2, seg3) )
878  return LW_OUTSIDE;
879 
880  /* See if the point is within the circle radius */
881  radius = lw_arc_center(seg1, seg2, seg3, &c);
882  d = distance2d_pt_pt(pt, &c);
883  if ( FP_EQUALS(d, radius) )
884  return LW_BOUNDARY; /* Boundary of circle */
885  else if ( d < radius )
886  return LW_INSIDE; /* Inside circle */
887  else
888  return LW_OUTSIDE; /* Outside circle */
889  }
890  else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
891  {
892  return LW_BOUNDARY; /* Boundary case */
893  }
894 
895  /* Start on the ring */
896  seg1 = getPoint2d_cp(pa, 0);
897  for ( i=1; i < pa->npoints; i += 2 )
898  {
899  seg2 = getPoint2d_cp(pa, i);
900  seg3 = getPoint2d_cp(pa, i+1);
901 
902  /* Catch an easy boundary case */
903  if( p2d_same(seg3, pt) )
904  return LW_BOUNDARY;
905 
906  /* Skip arcs that have no size */
907  if ( lw_arc_is_pt(seg1, seg2, seg3) )
908  {
909  seg1 = seg3;
910  continue;
911  }
912 
913  /* Only test segments in our vertical range */
914  lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
915  if ( pt->y > gbox.ymax || pt->y < gbox.ymin )
916  {
917  seg1 = seg3;
918  continue;
919  }
920 
921  /* Outside of horizontal range, and not between end points we also skip */
922  if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) &&
923  (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) )
924  {
925  seg1 = seg3;
926  continue;
927  }
928 
929  side = lw_arc_side(seg1, seg2, seg3, pt);
930 
931  /* On the boundary */
932  if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
933  {
934  return LW_BOUNDARY;
935  }
936 
937  /* Going "up"! Point to left of arc. */
938  if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
939  {
940  wn++;
941  }
942 
943  /* Going "down"! */
944  if ( side > 0 && (seg3->y <= pt->y) && (pt->y < seg1->y) )
945  {
946  wn--;
947  }
948 
949  /* Inside the arc! */
950  if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin )
951  {
952  POINT2D C;
953  double radius = lw_arc_center(seg1, seg2, seg3, &C);
954  double d = distance2d_pt_pt(pt, &C);
955 
956  /* On the boundary! */
957  if ( d == radius )
958  return LW_BOUNDARY;
959 
960  /* Within the arc! */
961  if ( d < radius )
962  {
963  /* Left side, increment winding number */
964  if ( side < 0 )
965  wn++;
966  /* Right side, decrement winding number */
967  if ( side > 0 )
968  wn--;
969  }
970  }
971 
972  seg1 = seg3;
973  }
974 
975  /* Sent out the winding number for calls that are building on this as a primitive */
976  if ( winding_number )
977  *winding_number = wn;
978 
979  /* Outside */
980  if (wn == 0)
981  {
982  return LW_OUTSIDE;
983  }
984 
985  /* Inside */
986  return LW_INSIDE;
987 }
988 
994 double
996 {
997  const POINT2D *P1;
998  const POINT2D *P2;
999  const POINT2D *P3;
1000  double sum = 0.0;
1001  double x0, x, y1, y2;
1002  uint32_t i;
1003 
1004  if (! pa || pa->npoints < 3 )
1005  return 0.0;
1006 
1007  P1 = getPoint2d_cp(pa, 0);
1008  P2 = getPoint2d_cp(pa, 1);
1009  x0 = P1->x;
1010  for ( i = 2; i < pa->npoints; i++ )
1011  {
1012  P3 = getPoint2d_cp(pa, i);
1013  x = P2->x - x0;
1014  y1 = P3->y;
1015  y2 = P1->y;
1016  sum += x * (y2-y1);
1017 
1018  /* Move forwards! */
1019  P1 = P2;
1020  P2 = P3;
1021  }
1022  return sum / 2.0;
1023 }
1024 
1025 int
1027 {
1028  double area = 0;
1029  area = ptarray_signed_area(pa);
1030  if ( area > 0 ) return LW_FALSE;
1031  else return LW_TRUE;
1032 }
1033 
1034 POINTARRAY*
1035 ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm)
1036 {
1037  /* TODO handle zero-length point arrays */
1038  uint32_t i;
1039  int in_hasz = FLAGS_GET_Z(pa->flags);
1040  int in_hasm = FLAGS_GET_M(pa->flags);
1041  POINT4D pt;
1042  POINTARRAY *pa_out = ptarray_construct_empty(hasz, hasm, pa->npoints);
1043 
1044  for( i = 0; i < pa->npoints; i++ )
1045  {
1046  getPoint4d_p(pa, i, &pt);
1047  if( hasz && ! in_hasz )
1048  pt.z = 0.0;
1049  if( hasm && ! in_hasm )
1050  pt.m = 0.0;
1051  ptarray_append_point(pa_out, &pt, LW_TRUE);
1052  }
1053 
1054  return pa_out;
1055 }
1056 
1057 POINTARRAY *
1058 ptarray_substring(POINTARRAY *ipa, double from, double to, double tolerance)
1059 {
1060  POINTARRAY *dpa;
1061  POINT4D pt;
1062  POINT4D p1, p2;
1063  POINT4D *p1ptr=&p1; /* don't break strict-aliasing rule */
1064  POINT4D *p2ptr=&p2;
1065  int nsegs, i;
1066  double length, slength, tlength;
1067  int state = 0; /* 0=before, 1=inside */
1068 
1069  /*
1070  * Create a dynamic pointarray with an initial capacity
1071  * equal to full copy of input points
1072  */
1074 
1075  /* Compute total line length */
1076  length = ptarray_length_2d(ipa);
1077 
1078 
1079  LWDEBUGF(3, "Total length: %g", length);
1080 
1081 
1082  /* Get 'from' and 'to' lengths */
1083  from = length*from;
1084  to = length*to;
1085 
1086 
1087  LWDEBUGF(3, "From/To: %g/%g", from, to);
1088 
1089 
1090  tlength = 0;
1091  getPoint4d_p(ipa, 0, &p1);
1092  nsegs = ipa->npoints - 1;
1093  for ( i = 0; i < nsegs; i++ )
1094  {
1095  double dseg;
1096 
1097  getPoint4d_p(ipa, i+1, &p2);
1098 
1099 
1100  LWDEBUGF(3 ,"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)",
1101  i, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m);
1102 
1103 
1104  /* Find the length of this segment */
1105  slength = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
1106 
1107  /*
1108  * We are before requested start.
1109  */
1110  if ( state == 0 ) /* before */
1111  {
1112 
1113  LWDEBUG(3, " Before start");
1114 
1115  if ( fabs ( from - ( tlength + slength ) ) <= tolerance )
1116  {
1117 
1118  LWDEBUG(3, " Second point is our start");
1119 
1120  /*
1121  * Second point is our start
1122  */
1123  ptarray_append_point(dpa, &p2, LW_FALSE);
1124  state=1; /* we're inside now */
1125  goto END;
1126  }
1127 
1128  else if ( fabs(from - tlength) <= tolerance )
1129  {
1130 
1131  LWDEBUG(3, " First point is our start");
1132 
1133  /*
1134  * First point is our start
1135  */
1136  ptarray_append_point(dpa, &p1, LW_FALSE);
1137 
1138  /*
1139  * We're inside now, but will check
1140  * 'to' point as well
1141  */
1142  state=1;
1143  }
1144 
1145  /*
1146  * Didn't reach the 'from' point,
1147  * nothing to do
1148  */
1149  else if ( from > tlength + slength ) goto END;
1150 
1151  else /* tlength < from < tlength+slength */
1152  {
1153 
1154  LWDEBUG(3, " Seg contains first point");
1155 
1156  /*
1157  * Our start is between first and
1158  * second point
1159  */
1160  dseg = (from - tlength) / slength;
1161 
1162  interpolate_point4d(&p1, &p2, &pt, dseg);
1163 
1164  ptarray_append_point(dpa, &pt, LW_FALSE);
1165 
1166  /*
1167  * We're inside now, but will check
1168  * 'to' point as well
1169  */
1170  state=1;
1171  }
1172  }
1173 
1174  if ( state == 1 ) /* inside */
1175  {
1176 
1177  LWDEBUG(3, " Inside");
1178 
1179  /*
1180  * 'to' point is our second point.
1181  */
1182  if ( fabs(to - ( tlength + slength ) ) <= tolerance )
1183  {
1184 
1185  LWDEBUG(3, " Second point is our end");
1186 
1187  ptarray_append_point(dpa, &p2, LW_FALSE);
1188  break; /* substring complete */
1189  }
1190 
1191  /*
1192  * 'to' point is our first point.
1193  * (should only happen if 'to' is 0)
1194  */
1195  else if ( fabs(to - tlength) <= tolerance )
1196  {
1197 
1198  LWDEBUG(3, " First point is our end");
1199 
1200  ptarray_append_point(dpa, &p1, LW_FALSE);
1201 
1202  break; /* substring complete */
1203  }
1204 
1205  /*
1206  * Didn't reach the 'end' point,
1207  * just copy second point
1208  */
1209  else if ( to > tlength + slength )
1210  {
1211  ptarray_append_point(dpa, &p2, LW_FALSE);
1212  goto END;
1213  }
1214 
1215  /*
1216  * 'to' point falls on this segment
1217  * Interpolate and break.
1218  */
1219  else if ( to < tlength + slength )
1220  {
1221 
1222  LWDEBUG(3, " Seg contains our end");
1223 
1224  dseg = (to - tlength) / slength;
1225  interpolate_point4d(&p1, &p2, &pt, dseg);
1226 
1227  ptarray_append_point(dpa, &pt, LW_FALSE);
1228 
1229  break;
1230  }
1231 
1232  else
1233  {
1234  LWDEBUG(3, "Unhandled case");
1235  }
1236  }
1237 
1238 
1239 END:
1240 
1241  tlength += slength;
1242  memcpy(&p1, &p2, sizeof(POINT4D));
1243  }
1244 
1245  LWDEBUGF(3, "Out of loop, ptarray has %d points", dpa->npoints);
1246 
1247  return dpa;
1248 }
1249 
1250 /*
1251  * Write into the *ret argument coordinates of the closes point on
1252  * the given segment to the reference input point.
1253  */
1254 void
1255 closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
1256 {
1257  double r;
1258 
1259  if ( FP_EQUALS(A->x, B->x) && FP_EQUALS(A->y, B->y) )
1260  {
1261  *ret = *A;
1262  return;
1263  }
1264 
1265  /*
1266  * We use comp.graphics.algorithms Frequently Asked Questions method
1267  *
1268  * (1) AC dot AB
1269  * r = ----------
1270  * ||AB||^2
1271  * r has the following meaning:
1272  * r=0 P = A
1273  * r=1 P = B
1274  * r<0 P is on the backward extension of AB
1275  * r>1 P is on the forward extension of AB
1276  * 0<r<1 P is interior to AB
1277  *
1278  */
1279  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) );
1280 
1281  if (r<0)
1282  {
1283  *ret = *A;
1284  return;
1285  }
1286  if (r>1)
1287  {
1288  *ret = *B;
1289  return;
1290  }
1291 
1292  ret->x = A->x + ( (B->x - A->x) * r );
1293  ret->y = A->y + ( (B->y - A->y) * r );
1294  ret->z = A->z + ( (B->z - A->z) * r );
1295  ret->m = A->m + ( (B->m - A->m) * r );
1296 }
1297 
1298 /*
1299  * Given a point, returns the location of closest point on pointarray
1300  * and, optionally, it's actual distance from the point array.
1301  */
1302 double
1303 ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
1304 {
1305  double mindist=DBL_MAX;
1306  double tlen, plen;
1307  uint32_t t, seg=0;
1308  POINT4D start4d, end4d, projtmp;
1309  POINT2D proj, p;
1310  const POINT2D *start = NULL, *end = NULL;
1311 
1312  /* Initialize our 2D copy of the input parameter */
1313  p.x = p4d->x;
1314  p.y = p4d->y;
1315 
1316  if ( ! proj4d ) proj4d = &projtmp;
1317 
1318  /* Check for special cases (length 0 and 1) */
1319  if ( pa->npoints <= 1 )
1320  {
1321  if ( pa->npoints == 1 )
1322  {
1323  getPoint4d_p(pa, 0, proj4d);
1324  if ( mindistout )
1325  *mindistout = distance2d_pt_pt(&p, getPoint2d_cp(pa, 0));
1326  }
1327  return 0.0;
1328  }
1329 
1330  start = getPoint2d_cp(pa, 0);
1331  /* Loop through pointarray looking for nearest segment */
1332  for (t=1; t<pa->npoints; t++)
1333  {
1334  double dist_sqr;
1335  end = getPoint2d_cp(pa, t);
1336  dist_sqr = distance2d_sqr_pt_seg(&p, start, end);
1337 
1338  if (dist_sqr < mindist)
1339  {
1340  mindist = dist_sqr;
1341  seg=t-1;
1342  if ( mindist == 0 )
1343  {
1344  LWDEBUG(3, "Breaking on mindist=0");
1345  break;
1346  }
1347  }
1348 
1349  start = end;
1350  }
1351  mindist = sqrt(mindist);
1352 
1353  if ( mindistout ) *mindistout = mindist;
1354 
1355  LWDEBUGF(3, "Closest segment: %d", seg);
1356  LWDEBUGF(3, "mindist: %g", mindist);
1357 
1358  /*
1359  * We need to project the
1360  * point on the closest segment.
1361  */
1362  getPoint4d_p(pa, seg, &start4d);
1363  getPoint4d_p(pa, seg+1, &end4d);
1364  closest_point_on_segment(p4d, &start4d, &end4d, proj4d);
1365 
1366  /* Copy 4D values into 2D holder */
1367  proj.x = proj4d->x;
1368  proj.y = proj4d->y;
1369 
1370  LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints);
1371 
1372  /* For robustness, force 1 when closest point == endpoint */
1373  if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, end) )
1374  {
1375  return 1.0;
1376  }
1377 
1378  LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);
1379 
1380  tlen = ptarray_length_2d(pa);
1381 
1382  LWDEBUGF(3, "tlen %g", tlen);
1383 
1384  /* Location of any point on a zero-length line is 0 */
1385  /* See http://trac.osgeo.org/postgis/ticket/1772#comment:2 */
1386  if ( tlen == 0 ) return 0;
1387 
1388  plen=0;
1389  start = getPoint2d_cp(pa, 0);
1390  for (t=0; t<seg; t++, start=end)
1391  {
1392  end = getPoint2d_cp(pa, t+1);
1393  plen += distance2d_pt_pt(start, end);
1394 
1395  LWDEBUGF(4, "Segment %d made plen %g", t, plen);
1396  }
1397 
1398  plen+=distance2d_pt_pt(&proj, start);
1399 
1400  LWDEBUGF(3, "plen %g, tlen %g", plen, tlen);
1401 
1402  return plen/tlen;
1403 }
1404 
1414 void
1416 {
1417  uint32_t i;
1418  double x;
1419 
1420  for (i=0; i<pa->npoints; i++)
1421  {
1422  memcpy(&x, getPoint_internal(pa, i), sizeof(double));
1423  if ( x < 0 ) x+= 360;
1424  else if ( x > 180 ) x -= 360;
1425  memcpy(getPoint_internal(pa, i), &x, sizeof(double));
1426  }
1427 }
1428 
1429 
1430 /*
1431  * Returns a POINTARRAY with consecutive equal points
1432  * removed. Equality test on all dimensions of input.
1433  *
1434  * Always returns a newly allocated object.
1435  */
1436 static POINTARRAY *
1437 ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
1438 {
1439  POINTARRAY *out = ptarray_clone_deep(in);
1440  ptarray_remove_repeated_points_in_place(out, tolerance, minpoints);
1441  return out;
1442 }
1443 
1444 POINTARRAY *
1445 ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
1446 {
1447  return ptarray_remove_repeated_points_minpoints(in, tolerance, 2);
1448 }
1449 
1450 
1451 void
1452 ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
1453 {
1454  uint32_t i;
1455  double tolsq = tolerance * tolerance;
1456  const POINT2D *last = NULL;
1457  const POINT2D *pt;
1458  uint32_t n_points = pa->npoints;
1459  uint32_t n_points_out = 1;
1460  size_t pt_size = ptarray_point_size(pa);
1461 
1462  double dsq = FLT_MAX;
1463 
1464  /* No-op on short inputs */
1465  if ( n_points <= min_points ) return;
1466 
1467  last = getPoint2d_cp(pa, 0);
1468  void *p_to = ((char *)last) + pt_size;
1469  for (i = 1; i < n_points; i++)
1470  {
1471  int last_point = (i == n_points - 1);
1472 
1473  /* Look straight into the abyss */
1474  pt = getPoint2d_cp(pa, i);
1475 
1476  /* Don't drop points if we are running short of points */
1477  if (n_points + n_points_out > min_points + i)
1478  {
1479  if (tolerance > 0.0)
1480  {
1481  /* Only drop points that are within our tolerance */
1482  dsq = distance2d_sqr_pt_pt(last, pt);
1483  /* Allow any point but the last one to be dropped */
1484  if (!last_point && dsq <= tolsq)
1485  {
1486  continue;
1487  }
1488  }
1489  else
1490  {
1491  /* At tolerance zero, only skip exact dupes */
1492  if (memcmp((char*)pt, (char*)last, pt_size) == 0)
1493  continue;
1494  }
1495 
1496  /* Got to last point, and it's not very different from */
1497  /* the point that preceded it. We want to keep the last */
1498  /* point, not the second-to-last one, so we pull our write */
1499  /* index back one value */
1500  if (last_point && n_points_out > 1 && tolerance > 0.0 && dsq <= tolsq)
1501  {
1502  n_points_out--;
1503  p_to -= pt_size;
1504  }
1505  }
1506 
1507  /* Compact all remaining values to front of array */
1508  memcpy(p_to, pt, pt_size);
1509  n_points_out++;
1510  p_to += pt_size;
1511  last = pt;
1512  }
1513  /* Adjust array length */
1514  pa->npoints = n_points_out;
1515  return;
1516 }
1517 
1518 /* Out of the points in pa [itfist .. itlast], finds the one that's farthest away from
1519  * the segment determined by pts[itfist] and pts[itlast].
1520  * Returns itfirst if no point was found futher away than max_distance_sqr
1521  */
1522 static uint32_t
1523 ptarray_dp_findsplit_in_place(const POINTARRAY *pts, uint32_t it_first, uint32_t it_last, double max_distance_sqr)
1524 {
1525  uint32_t split = it_first;
1526  if ((it_first - it_last) < 2)
1527  return it_first;
1528 
1529  const POINT2D *A = getPoint2d_cp(pts, it_first);
1530  const POINT2D *B = getPoint2d_cp(pts, it_last);
1531 
1532  if (distance2d_sqr_pt_pt(A, B) < DBL_EPSILON)
1533  {
1534  /* If p1 == p2, we can just calculate the distance from each point to A */
1535  for (uint32_t itk = it_first + 1; itk < it_last; itk++)
1536  {
1537  const POINT2D *pk = getPoint2d_cp(pts, itk);
1538  double distance_sqr = distance2d_sqr_pt_pt(pk, A);
1539  if (distance_sqr > max_distance_sqr)
1540  {
1541  split = itk;
1542  max_distance_sqr = distance_sqr;
1543  }
1544  }
1545  return split;
1546  }
1547 
1548  /* This is based on distance2d_sqr_pt_seg, but heavily inlined here to avoid recalculations */
1549  double ba_x = (B->x - A->x);
1550  double ba_y = (B->y - A->y);
1551  double ab_length_sqr = (ba_x * ba_x + ba_y * ba_y);
1552  /* To avoid the division by ab_length_sqr in the 3rd path, we normalize here
1553  * and multiply in the first two paths [(dot_ac_ab < 0) and (> ab_length_sqr)] */
1554  max_distance_sqr *= ab_length_sqr;
1555  for (uint32_t itk = it_first + 1; itk < it_last; itk++)
1556  {
1557  const POINT2D *C = getPoint2d_cp(pts, itk);
1558  double distance_sqr;
1559  double ca_x = (C->x - A->x);
1560  double ca_y = (C->y - A->y);
1561  double dot_ac_ab = (ca_x * ba_x + ca_y * ba_y);
1562 
1563  if (dot_ac_ab <= 0.0)
1564  {
1565  distance_sqr = distance2d_sqr_pt_pt(C, A) * ab_length_sqr;
1566  }
1567  else if (dot_ac_ab >= ab_length_sqr)
1568  {
1569  distance_sqr = distance2d_sqr_pt_pt(C, B) * ab_length_sqr;
1570  }
1571  else
1572  {
1573  double s_numerator = ca_x * ba_y - ca_y * ba_x;
1574  distance_sqr = s_numerator * s_numerator; /* Missing division by ab_length_sqr on purpose */
1575  }
1576 
1577  if (distance_sqr > max_distance_sqr)
1578  {
1579  split = itk;
1580  max_distance_sqr = distance_sqr;
1581  }
1582  }
1583  return split;
1584 }
1585 
1586 void
1587 ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
1588 {
1589  /* Do not try to simplify really short things */
1590  if (pa->npoints < 3 || pa->npoints <= minpts)
1591  return;
1592 
1593  /* We use this array to keep track of the points we are keeping, so
1594  * we store just TRUE / FALSE in their position */
1595  uint8_t *kept_points = lwalloc(sizeof(uint8_t) * pa->npoints);
1596  memset(kept_points, LW_FALSE, sizeof(uint8_t) * pa->npoints);
1597  kept_points[0] = LW_TRUE;
1598  kept_points[pa->npoints - 1] = LW_TRUE;
1599  uint32_t keptn = 2;
1600 
1601  /* We use this array as a stack to store the iterators that we are going to need
1602  * in the following steps.
1603  * This is ~10% faster than iterating over @kept_points looking for them
1604  */
1605  uint32_t *iterator_stack = lwalloc(sizeof(uint32_t) * pa->npoints);
1606  iterator_stack[0] = 0;
1607  uint32_t iterator_stack_size = 1;
1608 
1609  uint32_t it_first = 0;
1610  uint32_t it_last = pa->npoints - 1;
1611 
1612  const double tolerance_sqr = tolerance * tolerance;
1613  /* For the first @minpts points we ignore the tolerance */
1614  double it_tol = keptn >= minpts ? tolerance_sqr : -1.0;
1615 
1616  while (iterator_stack_size)
1617  {
1618  uint32_t split = ptarray_dp_findsplit_in_place(pa, it_first, it_last, it_tol);
1619  if (split == it_first)
1620  {
1621  it_first = it_last;
1622  it_last = iterator_stack[--iterator_stack_size];
1623  }
1624  else
1625  {
1626  kept_points[split] = LW_TRUE;
1627  keptn++;
1628 
1629  iterator_stack[iterator_stack_size++] = it_last;
1630  it_last = split;
1631  it_tol = keptn >= minpts ? tolerance_sqr : -1.0;
1632  }
1633  }
1634 
1635  const size_t pt_size = ptarray_point_size(pa);
1636  /* The first point is already in place, so we don't need to copy it */
1637  size_t kept_it = 1;
1638  if (keptn == 2)
1639  {
1640  /* If there are 2 points remaining, it has to be first and last as
1641  * we added those at the start */
1642  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1643  pa->serialized_pointlist + pt_size * (pa->npoints - 1),
1644  pt_size);
1645  }
1646  else
1647  {
1648  for (uint32_t i = 1; i < pa->npoints; i++)
1649  {
1650  if (kept_points[i])
1651  {
1652  memcpy(pa->serialized_pointlist + pt_size * kept_it,
1653  pa->serialized_pointlist + pt_size * i,
1654  pt_size);
1655  kept_it++;
1656  }
1657  }
1658  }
1659  pa->npoints = keptn;
1660 
1661  lwfree(kept_points);
1662  lwfree(iterator_stack);
1663 }
1664 
1665 /************************************************************************/
1666 
1672 double
1674 {
1675  double dist = 0.0;
1676  uint32_t i;
1677  const POINT2D *a1;
1678  const POINT2D *a2;
1679  const POINT2D *a3;
1680 
1681  if ( pts->npoints % 2 != 1 )
1682  lwerror("arc point array with even number of points");
1683 
1684  a1 = getPoint2d_cp(pts, 0);
1685 
1686  for ( i=2; i < pts->npoints; i += 2 )
1687  {
1688  a2 = getPoint2d_cp(pts, i-1);
1689  a3 = getPoint2d_cp(pts, i);
1690  dist += lw_arc_length(a1, a2, a3);
1691  a1 = a3;
1692  }
1693  return dist;
1694 }
1695 
1699 double
1701 {
1702  double dist = 0.0;
1703  uint32_t i;
1704  const POINT2D *frm;
1705  const POINT2D *to;
1706 
1707  if ( pts->npoints < 2 ) return 0.0;
1708 
1709  frm = getPoint2d_cp(pts, 0);
1710 
1711  for ( i=1; i < pts->npoints; i++ )
1712  {
1713  to = getPoint2d_cp(pts, i);
1714 
1715  dist += sqrt( ((frm->x - to->x)*(frm->x - to->x)) +
1716  ((frm->y - to->y)*(frm->y - to->y)) );
1717 
1718  frm = to;
1719  }
1720  return dist;
1721 }
1722 
1727 double
1729 {
1730  double dist = 0.0;
1731  uint32_t i;
1732  POINT3DZ frm;
1733  POINT3DZ to;
1734 
1735  if ( pts->npoints < 2 ) return 0.0;
1736 
1737  /* compute 2d length if 3d is not available */
1738  if ( ! FLAGS_GET_Z(pts->flags) ) return ptarray_length_2d(pts);
1739 
1740  getPoint3dz_p(pts, 0, &frm);
1741  for ( i=1; i < pts->npoints; i++ )
1742  {
1743  getPoint3dz_p(pts, i, &to);
1744  dist += sqrt( ((frm.x - to.x)*(frm.x - to.x)) +
1745  ((frm.y - to.y)*(frm.y - to.y)) +
1746  ((frm.z - to.z)*(frm.z - to.z)) );
1747  frm = to;
1748  }
1749  return dist;
1750 }
1751 
1752 
1753 
1757 void
1759 {
1760  uint32_t i;
1761  double x,y,z;
1762  POINT4D p4d;
1763 
1764  LWDEBUG(2, "lwgeom_affine_ptarray start");
1765 
1766  if ( FLAGS_GET_Z(pa->flags) )
1767  {
1768  LWDEBUG(3, " has z");
1769 
1770  for (i=0; i<pa->npoints; i++)
1771  {
1772  getPoint4d_p(pa, i, &p4d);
1773  x = p4d.x;
1774  y = p4d.y;
1775  z = p4d.z;
1776  p4d.x = a->afac * x + a->bfac * y + a->cfac * z + a->xoff;
1777  p4d.y = a->dfac * x + a->efac * y + a->ffac * z + a->yoff;
1778  p4d.z = a->gfac * x + a->hfac * y + a->ifac * z + a->zoff;
1779  ptarray_set_point4d(pa, i, &p4d);
1780 
1781  LWDEBUGF(3, " POINT %g %g %g => %g %g %g", x, y, z, p4d.x, p4d.y, p4d.z);
1782  }
1783  }
1784  else
1785  {
1786  LWDEBUG(3, " doesn't have z");
1787 
1788  for (i=0; i<pa->npoints; i++)
1789  {
1790  getPoint4d_p(pa, i, &p4d);
1791  x = p4d.x;
1792  y = p4d.y;
1793  p4d.x = a->afac * x + a->bfac * y + a->xoff;
1794  p4d.y = a->dfac * x + a->efac * y + a->yoff;
1795  ptarray_set_point4d(pa, i, &p4d);
1796 
1797  LWDEBUGF(3, " POINT %g %g => %g %g", x, y, p4d.x, p4d.y);
1798  }
1799  }
1800 
1801  LWDEBUG(3, "lwgeom_affine_ptarray end");
1802 
1803 }
1804 
1809 #if 0
1810 static int gluInvertMatrix(const double *m, double *invOut)
1811 {
1812  double inv[16], det;
1813  int i;
1814 
1815  inv[0] = m[5] * m[10] * m[15] -
1816  m[5] * m[11] * m[14] -
1817  m[9] * m[6] * m[15] +
1818  m[9] * m[7] * m[14] +
1819  m[13] * m[6] * m[11] -
1820  m[13] * m[7] * m[10];
1821 
1822  inv[4] = -m[4] * m[10] * m[15] +
1823  m[4] * m[11] * m[14] +
1824  m[8] * m[6] * m[15] -
1825  m[8] * m[7] * m[14] -
1826  m[12] * m[6] * m[11] +
1827  m[12] * m[7] * m[10];
1828 
1829  inv[8] = m[4] * m[9] * m[15] -
1830  m[4] * m[11] * m[13] -
1831  m[8] * m[5] * m[15] +
1832  m[8] * m[7] * m[13] +
1833  m[12] * m[5] * m[11] -
1834  m[12] * m[7] * m[9];
1835 
1836  inv[12] = -m[4] * m[9] * m[14] +
1837  m[4] * m[10] * m[13] +
1838  m[8] * m[5] * m[14] -
1839  m[8] * m[6] * m[13] -
1840  m[12] * m[5] * m[10] +
1841  m[12] * m[6] * m[9];
1842 
1843  inv[1] = -m[1] * m[10] * m[15] +
1844  m[1] * m[11] * m[14] +
1845  m[9] * m[2] * m[15] -
1846  m[9] * m[3] * m[14] -
1847  m[13] * m[2] * m[11] +
1848  m[13] * m[3] * m[10];
1849 
1850  inv[5] = m[0] * m[10] * m[15] -
1851  m[0] * m[11] * m[14] -
1852  m[8] * m[2] * m[15] +
1853  m[8] * m[3] * m[14] +
1854  m[12] * m[2] * m[11] -
1855  m[12] * m[3] * m[10];
1856 
1857  inv[9] = -m[0] * m[9] * m[15] +
1858  m[0] * m[11] * m[13] +
1859  m[8] * m[1] * m[15] -
1860  m[8] * m[3] * m[13] -
1861  m[12] * m[1] * m[11] +
1862  m[12] * m[3] * m[9];
1863 
1864  inv[13] = m[0] * m[9] * m[14] -
1865  m[0] * m[10] * m[13] -
1866  m[8] * m[1] * m[14] +
1867  m[8] * m[2] * m[13] +
1868  m[12] * m[1] * m[10] -
1869  m[12] * m[2] * m[9];
1870 
1871  inv[2] = m[1] * m[6] * m[15] -
1872  m[1] * m[7] * m[14] -
1873  m[5] * m[2] * m[15] +
1874  m[5] * m[3] * m[14] +
1875  m[13] * m[2] * m[7] -
1876  m[13] * m[3] * m[6];
1877 
1878  inv[6] = -m[0] * m[6] * m[15] +
1879  m[0] * m[7] * m[14] +
1880  m[4] * m[2] * m[15] -
1881  m[4] * m[3] * m[14] -
1882  m[12] * m[2] * m[7] +
1883  m[12] * m[3] * m[6];
1884 
1885  inv[10] = m[0] * m[5] * m[15] -
1886  m[0] * m[7] * m[13] -
1887  m[4] * m[1] * m[15] +
1888  m[4] * m[3] * m[13] +
1889  m[12] * m[1] * m[7] -
1890  m[12] * m[3] * m[5];
1891 
1892  inv[14] = -m[0] * m[5] * m[14] +
1893  m[0] * m[6] * m[13] +
1894  m[4] * m[1] * m[14] -
1895  m[4] * m[2] * m[13] -
1896  m[12] * m[1] * m[6] +
1897  m[12] * m[2] * m[5];
1898 
1899  inv[3] = -m[1] * m[6] * m[11] +
1900  m[1] * m[7] * m[10] +
1901  m[5] * m[2] * m[11] -
1902  m[5] * m[3] * m[10] -
1903  m[9] * m[2] * m[7] +
1904  m[9] * m[3] * m[6];
1905 
1906  inv[7] = m[0] * m[6] * m[11] -
1907  m[0] * m[7] * m[10] -
1908  m[4] * m[2] * m[11] +
1909  m[4] * m[3] * m[10] +
1910  m[8] * m[2] * m[7] -
1911  m[8] * m[3] * m[6];
1912 
1913  inv[11] = -m[0] * m[5] * m[11] +
1914  m[0] * m[7] * m[9] +
1915  m[4] * m[1] * m[11] -
1916  m[4] * m[3] * m[9] -
1917  m[8] * m[1] * m[7] +
1918  m[8] * m[3] * m[5];
1919 
1920  inv[15] = m[0] * m[5] * m[10] -
1921  m[0] * m[6] * m[9] -
1922  m[4] * m[1] * m[10] +
1923  m[4] * m[2] * m[9] +
1924  m[8] * m[1] * m[6] -
1925  m[8] * m[2] * m[5];
1926 
1927  det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
1928 
1929  if (det == 0)
1930  return LW_FALSE;
1931 
1932  det = 1.0 / det;
1933 
1934  for (i = 0; i < 16; i++)
1935  invOut[i] = inv[i] * det;
1936 
1937  return LW_TRUE;
1938 }
1939 #endif
1940 
1944 void
1946 {
1947  uint32_t i;
1948  POINT4D p4d;
1949  LWDEBUG(3, "ptarray_scale start");
1950  for (i=0; i<pa->npoints; i++)
1951  {
1952  getPoint4d_p(pa, i, &p4d);
1953  p4d.x *= fact->x;
1954  p4d.y *= fact->y;
1955  p4d.z *= fact->z;
1956  p4d.m *= fact->m;
1957  ptarray_set_point4d(pa, i, &p4d);
1958  }
1959  LWDEBUG(3, "ptarray_scale end");
1960 }
1961 
1962 int
1964 {
1965  return getPoint4d_p(pa, 0, pt);
1966 }
1967 
1968 
1969 /*
1970  * Stick an array of points to the given gridspec.
1971  * Return "gridded" points in *outpts and their number in *outptsn.
1972  *
1973  * Two consecutive points falling on the same grid cell are collapsed
1974  * into one single point.
1975  *
1976  */
1977 void
1979 {
1980  uint32_t i, j = 0;
1981  POINT4D *p, *p_out = NULL;
1982  int ndims = FLAGS_NDIMS(pa->flags);
1983  int has_z = FLAGS_GET_Z(pa->flags);
1984  int has_m = FLAGS_GET_M(pa->flags);
1985 
1986  LWDEBUGF(2, "%s called on %p", __func__, pa);
1987 
1988  for (i = 0; i < pa->npoints; i++)
1989  {
1990  /* Look straight into the abyss */
1991  p = (POINT4D*)(getPoint_internal(pa, i));
1992 
1993  if (grid->xsize > 0)
1994  {
1995  p->x = rint((p->x - grid->ipx)/grid->xsize) * grid->xsize + grid->ipx;
1996  }
1997 
1998  if (grid->ysize > 0)
1999  {
2000  p->y = rint((p->y - grid->ipy)/grid->ysize) * grid->ysize + grid->ipy;
2001  }
2002 
2003  /* Read and round this point */
2004  /* Z is always in third position */
2005  if (has_z)
2006  {
2007  if (grid->zsize > 0)
2008  p->z = rint((p->z - grid->ipz)/grid->zsize) * grid->zsize + grid->ipz;
2009  }
2010  /* M might be in 3rd or 4th position */
2011  if (has_m)
2012  {
2013  /* In POINT M, M is in 3rd position */
2014  if (grid->msize > 0 && !has_z)
2015  p->z = rint((p->z - grid->ipm)/grid->msize) * grid->msize + grid->ipm;
2016  /* In POINT ZM, M is in 4th position */
2017  if (grid->msize > 0 && has_z)
2018  p->m = rint((p->m - grid->ipm)/grid->msize) * grid->msize + grid->ipm;
2019  }
2020 
2021  /* Skip duplicates */
2022  if ( p_out && FP_EQUALS(p_out->x, p->x) && FP_EQUALS(p_out->y, p->y)
2023  && (ndims > 2 ? FP_EQUALS(p_out->z, p->z) : 1)
2024  && (ndims > 3 ? FP_EQUALS(p_out->m, p->m) : 1) )
2025  {
2026  continue;
2027  }
2028 
2029  /* Write rounded values into the next available point */
2030  p_out = (POINT4D*)(getPoint_internal(pa, j++));
2031  p_out->x = p->x;
2032  p_out->y = p->y;
2033  if (ndims > 2)
2034  p_out->z = p->z;
2035  if (ndims > 3)
2036  p_out->m = p->m;
2037  }
2038 
2039  /* Update output ptarray length */
2040  pa->npoints = j;
2041  return;
2042 }
2043 
2044 
2045 int
2046 ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox)
2047 {
2048  const POINT2D *pt;
2049  int n = 0;
2050  uint32_t i;
2051  for ( i = 0; i < pa->npoints; i++ )
2052  {
2053  pt = getPoint2d_cp(pa, i);
2054  if ( gbox_contains_point2d(gbox, pt) )
2055  n++;
2056  }
2057  return n;
2058 }
2059 
2060 
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:108
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:2397
#define LW_FAILURE
Definition: liblwgeom.h:110
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:656
#define LW_SUCCESS
Definition: liblwgeom.h:111
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition: lwgeom_api.c:349
#define FLAGS_GET_READONLY(flags)
Definition: liblwgeom.h:183
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:179
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:193
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:180
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:2407
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:194
void * lwalloc(size_t size)
Definition: lwutil.c:227
#define FLAGS_SET_READONLY(flags, value)
Definition: liblwgeom.h:190
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:107
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:376
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:119
#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:229
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
Definition: lwalgorithm.c:179
#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:96
#define LW_OUTSIDE
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition: lwalgorithm.c:65
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:106
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:86
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:50
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:91
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:48
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:67
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:738
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:1523
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:1415
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
POINTARRAY * ptarray_clone(const POINTARRAY *in)
Clone a POINTARRAY object.
Definition: ptarray.c:657
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 ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt)
For POINTARRAYs representing CIRCULARSTRINGS.
Definition: ptarray.c:831
int ptarray_is_closed_2d(const POINTARRAY *in)
Definition: ptarray.c:693
int ptarray_is_closed_z(const POINTARRAY *in)
Definition: ptarray.c:719
double ptarray_length(const POINTARRAY *pts)
Find the 3d/2d length of the given POINTARRAY (depending on its dimensionality)
Definition: ptarray.c:1728
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:995
POINTARRAY * ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where)
Add a point in a pointarray.
Definition: ptarray.c:501
void closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
Definition: ptarray.c:1255
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
Definition: ptarray.c:1963
int ptarray_is_closed(const POINTARRAY *in)
Check for ring closure using whatever dimensionality is declared on the pointarray.
Definition: ptarray.c:679
POINTARRAY * ptarray_clone_deep(const POINTARRAY *in)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:626
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:1978
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
Definition: ptarray.c:1700
char ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
Definition: ptarray.c:476
int ptarray_is_closed_3d(const POINTARRAY *in)
Definition: ptarray.c:706
void ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
Definition: ptarray.c:1452
POINTARRAY * ptarray_removePoint(POINTARRAY *pa, uint32_t which)
Remove a point from a pointarray.
Definition: ptarray.c:553
void ptarray_simplify_in_place(POINTARRAY *pa, double tolerance, uint32_t minpts)
Definition: ptarray.c:1587
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:1673
POINTARRAY * ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
Definition: ptarray.c:1445
void ptarray_affine(POINTARRAY *pa, const AFFINE *a)
Affine transform a pointarray.
Definition: ptarray.c:1758
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:732
int ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:837
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
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1026
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:1945
static POINTARRAY * ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
Definition: ptarray.c:1437
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:2046
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:1058
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:595
POINTARRAY * ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm)
Definition: ptarray.c:1035
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:1303
double gfac
Definition: liblwgeom.h:318
double zoff
Definition: liblwgeom.h:318
double bfac
Definition: liblwgeom.h:318
double ifac
Definition: liblwgeom.h:318
double xoff
Definition: liblwgeom.h:318
double dfac
Definition: liblwgeom.h:318
double afac
Definition: liblwgeom.h:318
double ffac
Definition: liblwgeom.h:318
double cfac
Definition: liblwgeom.h:318
double hfac
Definition: liblwgeom.h:318
double efac
Definition: liblwgeom.h:318
double yoff
Definition: liblwgeom.h:318
double ymax
Definition: liblwgeom.h:343
double xmax
Definition: liblwgeom.h:341
double ymin
Definition: liblwgeom.h:342
double xmin
Definition: liblwgeom.h:340
double y
Definition: liblwgeom.h:376
double x
Definition: liblwgeom.h:376
double z
Definition: liblwgeom.h:382
double x
Definition: liblwgeom.h:382
double y
Definition: liblwgeom.h:382
double m
Definition: liblwgeom.h:400
double x
Definition: liblwgeom.h:400
double z
Definition: liblwgeom.h:400
double y
Definition: liblwgeom.h:400
lwflags_t flags
Definition: liblwgeom.h:417
uint32_t maxpoints
Definition: liblwgeom.h:414
uint32_t npoints
Definition: liblwgeom.h:413
uint8_t * serialized_pointlist
Definition: liblwgeom.h:420
double ipm
Definition: liblwgeom.h:1345
double zsize
Definition: liblwgeom.h:1348
double ysize
Definition: liblwgeom.h:1347
double xsize
Definition: liblwgeom.h:1346
double ipx
Definition: liblwgeom.h:1342
double msize
Definition: liblwgeom.h:1349
double ipy
Definition: liblwgeom.h:1343
double ipz
Definition: liblwgeom.h:1344
Snap-to-grid.
Definition: liblwgeom.h:1341