PostGIS  3.3.9dev-r@@SVN_REVISION@@
measures.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 2001-2006 Refractions Research Inc.
22  * Copyright 2010 Nicklas Avén
23  * Copyright 2012 Paul Ramsey
24  * Copyright 2019 Darafei Praliaskouski
25  *
26  **********************************************************************/
27 
28 #include <string.h>
29 #include <stdlib.h>
30 
31 #include "../postgis_config.h"
32 //#define POSTGIS_DEBUG_LEVEL 5
33 
34 #include "measures.h"
35 #include "lwgeom_log.h"
36 
37 /*------------------------------------------------------------------------------------------------------------
38 Initializing functions
39 The functions starting the distance-calculation processses
40 --------------------------------------------------------------------------------------------------------------*/
41 
42 LWGEOM *
43 lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
44 {
45  return lw_dist2d_distanceline(lw1, lw2, lw1->srid, DIST_MIN);
46 }
47 
48 LWGEOM *
49 lwgeom_furthest_line(const LWGEOM *lw1, const LWGEOM *lw2)
50 {
51  return lw_dist2d_distanceline(lw1, lw2, lw1->srid, DIST_MAX);
52 }
53 
54 LWGEOM *
55 lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
56 {
57  return lw_dist2d_distancepoint(lw1, lw2, lw1->srid, DIST_MIN);
58 }
59 
60 LWGEOM *
61 lwgeom_furthest_point(const LWGEOM *lw1, const LWGEOM *lw2)
62 {
63  return lw_dist2d_distancepoint(lw1, lw2, lw1->srid, DIST_MAX);
64 }
65 
66 void
68 {
69  dl->twisted = -1;
70  dl->p1.x = dl->p1.y = 0.0;
71  dl->p2.x = dl->p2.y = 0.0;
72  dl->mode = mode;
73  dl->tolerance = 0.0;
74  if (mode == DIST_MIN)
75  dl->distance = FLT_MAX;
76  else
77  dl->distance = -1 * FLT_MAX;
78 }
79 
83 LWGEOM *
84 lw_dist2d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
85 {
86  double x1, x2, y1, y2;
87 
88  double initdistance = (mode == DIST_MIN ? FLT_MAX : -1.0);
89  DISTPTS thedl;
90  LWPOINT *lwpoints[2];
91  LWGEOM *result;
92 
93  thedl.mode = mode;
94  thedl.distance = initdistance;
95  thedl.tolerance = 0.0;
96 
97  LWDEBUG(2, "lw_dist2d_distanceline is called");
98 
99  if (!lw_dist2d_comp(lw1, lw2, &thedl))
100  {
101  /*should never get here. all cases ought to be error handled earlier*/
102  lwerror("Some unspecified error.");
104  }
105 
106  /*if thedl.distance is unchanged there where only empty geometries input*/
107  if (thedl.distance == initdistance)
108  {
109  LWDEBUG(3, "didn't find geometries to measure between, returning null");
111  }
112  else
113  {
114  x1 = thedl.p1.x;
115  y1 = thedl.p1.y;
116  x2 = thedl.p2.x;
117  y2 = thedl.p2.y;
118 
119  lwpoints[0] = lwpoint_make2d(srid, x1, y1);
120  lwpoints[1] = lwpoint_make2d(srid, x2, y2);
121 
122  result = (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);
123  }
124  return result;
125 }
126 
130 LWGEOM *
131 lw_dist2d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
132 {
133  double x, y;
134  DISTPTS thedl;
135  double initdistance = FLT_MAX;
136  LWGEOM *result;
137 
138  thedl.mode = mode;
139  thedl.distance = initdistance;
140  thedl.tolerance = 0;
141 
142  LWDEBUG(2, "lw_dist2d_distancepoint is called");
143 
144  if (!lw_dist2d_comp(lw1, lw2, &thedl))
145  {
146  /*should never get here. all cases ought to be error handled earlier*/
147  lwerror("Some unspecified error.");
149  }
150  if (thedl.distance == initdistance)
151  {
152  LWDEBUG(3, "didn't find geometries to measure between, returning null");
154  }
155  else
156  {
157  x = thedl.p1.x;
158  y = thedl.p1.y;
159  result = (LWGEOM *)lwpoint_make2d(srid, x, y);
160  }
161  return result;
162 }
163 
167 double
168 lwgeom_maxdistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
169 {
170  LWDEBUG(2, "lwgeom_maxdistance2d is called");
171 
172  return lwgeom_maxdistance2d_tolerance(lw1, lw2, 0.0);
173 }
174 
179 double
180 lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
181 {
182  /*double thedist;*/
183  DISTPTS thedl;
184  LWDEBUG(2, "lwgeom_maxdistance2d_tolerance is called");
185  thedl.mode = DIST_MAX;
186  thedl.distance = -1;
187  thedl.tolerance = tolerance;
188  if (lw_dist2d_comp(lw1, lw2, &thedl))
189  return thedl.distance;
190 
191  /*should never get here. all cases ought to be error handled earlier*/
192  lwerror("Some unspecified error.");
193  return -1;
194 }
195 
199 double
200 lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
201 {
202  return lwgeom_mindistance2d_tolerance(lw1, lw2, 0.0);
203 }
204 
209 double
210 lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
211 {
212  DISTPTS thedl;
213  LWDEBUG(2, "lwgeom_mindistance2d_tolerance is called");
214  thedl.mode = DIST_MIN;
215  thedl.distance = FLT_MAX;
216  thedl.tolerance = tolerance;
217  if (lw_dist2d_comp(lw1, lw2, &thedl))
218  return thedl.distance;
219  /*should never get here. all cases ought to be error handled earlier*/
220  lwerror("Some unspecified error.");
221  return FLT_MAX;
222 }
223 
224 /*------------------------------------------------------------------------------------------------------------
225 End of Initializing functions
226 --------------------------------------------------------------------------------------------------------------*/
227 
228 /*------------------------------------------------------------------------------------------------------------
229 Preprocessing functions
230 Functions preparing geometries for distance-calculations
231 --------------------------------------------------------------------------------------------------------------*/
232 
238 int
239 lw_dist2d_comp(const LWGEOM *lw1, const LWGEOM *lw2, DISTPTS *dl)
240 {
241  return lw_dist2d_recursive(lw1, lw2, dl);
242 }
243 
244 static int
246 {
247  /* Differs from lwgeom_is_collection by not treating CURVEPOLYGON as collection */
248  switch (g->type)
249  {
250  case TINTYPE:
251  case MULTIPOINTTYPE:
252  case MULTILINETYPE:
253  case MULTIPOLYGONTYPE:
254  case COLLECTIONTYPE:
255  case MULTICURVETYPE:
256  case MULTISURFACETYPE:
257  case COMPOUNDTYPE:
259  return LW_TRUE;
260  break;
261 
262  default:
263  return LW_FALSE;
264  }
265 }
266 
270 int
271 lw_dist2d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl)
272 {
273  int i, j;
274  int n1 = 1;
275  int n2 = 1;
276  LWGEOM *g1 = NULL;
277  LWGEOM *g2 = NULL;
278  LWCOLLECTION *c1 = NULL;
279  LWCOLLECTION *c2 = NULL;
280 
281  LWDEBUGF(2, "lw_dist2d_comp is called with type1=%d, type2=%d", lwg1->type, lwg2->type);
282 
283  if (lw_dist2d_is_collection(lwg1))
284  {
285  LWDEBUG(3, "First geometry is collection");
286  c1 = lwgeom_as_lwcollection(lwg1);
287  n1 = c1->ngeoms;
288  }
289  if (lw_dist2d_is_collection(lwg2))
290  {
291  LWDEBUG(3, "Second geometry is collection");
292  c2 = lwgeom_as_lwcollection(lwg2);
293  n2 = c2->ngeoms;
294  }
295 
296  for (i = 0; i < n1; i++)
297  {
298 
299  if (lw_dist2d_is_collection(lwg1))
300  g1 = c1->geoms[i];
301  else
302  g1 = (LWGEOM *)lwg1;
303 
304  if (lwgeom_is_empty(g1))
305  continue;
306 
307  if (lw_dist2d_is_collection(g1))
308  {
309  LWDEBUG(3, "Found collection inside first geometry collection, recursing");
310  if (!lw_dist2d_recursive(g1, lwg2, dl))
311  return LW_FALSE;
312  continue;
313  }
314  for (j = 0; j < n2; j++)
315  {
316  if (lw_dist2d_is_collection(lwg2))
317  g2 = c2->geoms[j];
318  else
319  g2 = (LWGEOM *)lwg2;
320 
321  if (lw_dist2d_is_collection(g2))
322  {
323  LWDEBUG(3, "Found collection inside second geometry collection, recursing");
324  if (!lw_dist2d_recursive(g1, g2, dl))
325  return LW_FALSE;
326  continue;
327  }
328 
329  if (!g1->bbox)
330  lwgeom_add_bbox(g1);
331 
332  if (!g2->bbox)
333  lwgeom_add_bbox(g2);
334 
335  /* If one of geometries is empty, skip */
336  if (lwgeom_is_empty(g1) || lwgeom_is_empty(g2))
337  continue;
338 
339  if ((dl->mode != DIST_MAX) && (!lw_dist2d_check_overlap(g1, g2)) &&
340  (g1->type == LINETYPE || g1->type == POLYGONTYPE || g1->type == TRIANGLETYPE) &&
341  (g2->type == LINETYPE || g2->type == POLYGONTYPE || g2->type == TRIANGLETYPE))
342  {
343  if (!lw_dist2d_distribute_fast(g1, g2, dl))
344  return LW_FALSE;
345  }
346  else
347  {
348  if (!lw_dist2d_distribute_bruteforce(g1, g2, dl))
349  return LW_FALSE;
350  LWDEBUGF(2, "Distance so far: %.15g (%.15g tolerated)", dl->distance, dl->tolerance);
351  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
352  return LW_TRUE; /*just a check if the answer is already given*/
353  LWDEBUG(2, "Not below tolerance yet");
354  }
355  }
356  }
357  return LW_TRUE;
358 }
359 
360 int
361 lw_dist2d_distribute_bruteforce(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl)
362 {
363 
364  int t1 = lwg1->type;
365  int t2 = lwg2->type;
366 
367  switch (t1)
368  {
369  case POINTTYPE:
370  {
371  dl->twisted = 1;
372  switch (t2)
373  {
374  case POINTTYPE:
375  return lw_dist2d_point_point((LWPOINT *)lwg1, (LWPOINT *)lwg2, dl);
376  case LINETYPE:
377  return lw_dist2d_point_line((LWPOINT *)lwg1, (LWLINE *)lwg2, dl);
378  case TRIANGLETYPE:
379  return lw_dist2d_point_tri((LWPOINT *)lwg1, (LWTRIANGLE *)lwg2, dl);
380  case POLYGONTYPE:
381  return lw_dist2d_point_poly((LWPOINT *)lwg1, (LWPOLY *)lwg2, dl);
382  case CIRCSTRINGTYPE:
383  return lw_dist2d_point_circstring((LWPOINT *)lwg1, (LWCIRCSTRING *)lwg2, dl);
384  case CURVEPOLYTYPE:
385  return lw_dist2d_point_curvepoly((LWPOINT *)lwg1, (LWCURVEPOLY *)lwg2, dl);
386  default:
387  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
388  return LW_FALSE;
389  }
390  }
391  case LINETYPE:
392  {
393  dl->twisted = 1;
394  switch (t2)
395  {
396  case POINTTYPE:
397  dl->twisted = -1;
398  return lw_dist2d_point_line((LWPOINT *)lwg2, (LWLINE *)lwg1, dl);
399  case LINETYPE:
400  return lw_dist2d_line_line((LWLINE *)lwg1, (LWLINE *)lwg2, dl);
401  case TRIANGLETYPE:
402  return lw_dist2d_line_tri((LWLINE *)lwg1, (LWTRIANGLE *)lwg2, dl);
403  case POLYGONTYPE:
404  return lw_dist2d_line_poly((LWLINE *)lwg1, (LWPOLY *)lwg2, dl);
405  case CIRCSTRINGTYPE:
406  return lw_dist2d_line_circstring((LWLINE *)lwg1, (LWCIRCSTRING *)lwg2, dl);
407  case CURVEPOLYTYPE:
408  return lw_dist2d_line_curvepoly((LWLINE *)lwg1, (LWCURVEPOLY *)lwg2, dl);
409  default:
410  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
411  return LW_FALSE;
412  }
413  }
414  case TRIANGLETYPE:
415  {
416  dl->twisted = 1;
417  switch (t2)
418  {
419  case POINTTYPE:
420  dl->twisted = -1;
421  return lw_dist2d_point_tri((LWPOINT *)lwg2, (LWTRIANGLE *)lwg1, dl);
422  case LINETYPE:
423  dl->twisted = -1;
424  return lw_dist2d_line_tri((LWLINE *)lwg2, (LWTRIANGLE *)lwg1, dl);
425  case TRIANGLETYPE:
426  return lw_dist2d_tri_tri((LWTRIANGLE *)lwg1, (LWTRIANGLE *)lwg2, dl);
427  case POLYGONTYPE:
428  return lw_dist2d_tri_poly((LWTRIANGLE *)lwg1, (LWPOLY *)lwg2, dl);
429  case CIRCSTRINGTYPE:
430  return lw_dist2d_tri_circstring((LWTRIANGLE *)lwg1, (LWCIRCSTRING *)lwg2, dl);
431  case CURVEPOLYTYPE:
432  return lw_dist2d_tri_curvepoly((LWTRIANGLE *)lwg1, (LWCURVEPOLY *)lwg2, dl);
433  default:
434  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
435  return LW_FALSE;
436  }
437  }
438  case CIRCSTRINGTYPE:
439  {
440  dl->twisted = 1;
441  switch (t2)
442  {
443  case POINTTYPE:
444  dl->twisted = -1;
445  return lw_dist2d_point_circstring((LWPOINT *)lwg2, (LWCIRCSTRING *)lwg1, dl);
446  case LINETYPE:
447  dl->twisted = -1;
448  return lw_dist2d_line_circstring((LWLINE *)lwg2, (LWCIRCSTRING *)lwg1, dl);
449  case TRIANGLETYPE:
450  dl->twisted = -1;
451  return lw_dist2d_tri_circstring((LWTRIANGLE *)lwg2, (LWCIRCSTRING *)lwg1, dl);
452  case POLYGONTYPE:
453  return lw_dist2d_circstring_poly((LWCIRCSTRING *)lwg1, (LWPOLY *)lwg2, dl);
454  case CIRCSTRINGTYPE:
455  return lw_dist2d_circstring_circstring((LWCIRCSTRING *)lwg1, (LWCIRCSTRING *)lwg2, dl);
456  case CURVEPOLYTYPE:
457  return lw_dist2d_circstring_curvepoly((LWCIRCSTRING *)lwg1, (LWCURVEPOLY *)lwg2, dl);
458  default:
459  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
460  return LW_FALSE;
461  }
462  }
463  case POLYGONTYPE:
464  {
465  dl->twisted = -1;
466  switch (t2)
467  {
468  case POINTTYPE:
469  return lw_dist2d_point_poly((LWPOINT *)lwg2, (LWPOLY *)lwg1, dl);
470  case LINETYPE:
471  return lw_dist2d_line_poly((LWLINE *)lwg2, (LWPOLY *)lwg1, dl);
472  case TRIANGLETYPE:
473  return lw_dist2d_tri_poly((LWTRIANGLE *)lwg2, (LWPOLY *)lwg1, dl);
474  case CIRCSTRINGTYPE:
475  return lw_dist2d_circstring_poly((LWCIRCSTRING *)lwg2, (LWPOLY *)lwg1, dl);
476  case POLYGONTYPE:
477  dl->twisted = 1;
478  return lw_dist2d_poly_poly((LWPOLY *)lwg1, (LWPOLY *)lwg2, dl);
479  case CURVEPOLYTYPE:
480  dl->twisted = 1;
481  return lw_dist2d_poly_curvepoly((LWPOLY *)lwg1, (LWCURVEPOLY *)lwg2, dl);
482  default:
483  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
484  return LW_FALSE;
485  }
486  }
487  case CURVEPOLYTYPE:
488  {
489  dl->twisted = -1;
490  switch (t2)
491  {
492  case POINTTYPE:
493  return lw_dist2d_point_curvepoly((LWPOINT *)lwg2, (LWCURVEPOLY *)lwg1, dl);
494  case LINETYPE:
495  return lw_dist2d_line_curvepoly((LWLINE *)lwg2, (LWCURVEPOLY *)lwg1, dl);
496  case TRIANGLETYPE:
497  return lw_dist2d_tri_curvepoly((LWTRIANGLE *)lwg2, (LWCURVEPOLY *)lwg1, dl);
498  case POLYGONTYPE:
499  return lw_dist2d_poly_curvepoly((LWPOLY *)lwg2, (LWCURVEPOLY *)lwg1, dl);
500  case CIRCSTRINGTYPE:
501  return lw_dist2d_circstring_curvepoly((LWCIRCSTRING *)lwg2, (LWCURVEPOLY *)lwg1, dl);
502  case CURVEPOLYTYPE:
503  dl->twisted = 1;
504  return lw_dist2d_curvepoly_curvepoly((LWCURVEPOLY *)lwg1, (LWCURVEPOLY *)lwg2, dl);
505  default:
506  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
507  return LW_FALSE;
508  }
509  }
510  default:
511  {
512  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t1));
513  return LW_FALSE;
514  }
515  }
516 
517  return LW_FALSE;
518 }
519 
520 /* Check for overlapping bboxes */
521 int
523 {
524  LWDEBUG(2, "lw_dist2d_check_overlap is called");
525  if (!lwg1->bbox)
526  lwgeom_calculate_gbox(lwg1, lwg1->bbox);
527  if (!lwg2->bbox)
528  lwgeom_calculate_gbox(lwg2, lwg2->bbox);
529 
530  /* Check if the geometries intersect. */
531  if ((lwg1->bbox->xmax < lwg2->bbox->xmin || lwg1->bbox->xmin > lwg2->bbox->xmax ||
532  lwg1->bbox->ymax < lwg2->bbox->ymin || lwg1->bbox->ymin > lwg2->bbox->ymax))
533  {
534  LWDEBUG(3, "geometries bboxes did not overlap");
535  return LW_FALSE;
536  }
537  LWDEBUG(3, "geometries bboxes overlap");
538  return LW_TRUE;
539 }
540 
542 int
544 {
545  POINTARRAY *pa1, *pa2;
546  int type1 = lwg1->type;
547  int type2 = lwg2->type;
548 
549  LWDEBUGF(2, "lw_dist2d_distribute_fast is called with typ1=%d, type2=%d", lwg1->type, lwg2->type);
550 
551  switch (type1)
552  {
553  case LINETYPE:
554  pa1 = ((LWLINE *)lwg1)->points;
555  break;
556  case POLYGONTYPE:
557  pa1 = ((LWPOLY *)lwg1)->rings[0];
558  break;
559  case TRIANGLETYPE:
560  pa1 = ((LWTRIANGLE *)lwg1)->points;
561  break;
562  default:
563  lwerror("Unsupported geometry1 type: %s", lwtype_name(type1));
564  return LW_FALSE;
565  }
566  switch (type2)
567  {
568  case LINETYPE:
569  pa2 = ((LWLINE *)lwg2)->points;
570  break;
571  case POLYGONTYPE:
572  pa2 = ((LWPOLY *)lwg2)->rings[0];
573  break;
574  case TRIANGLETYPE:
575  pa2 = ((LWTRIANGLE *)lwg2)->points;
576  break;
577  default:
578  lwerror("Unsupported geometry2 type: %s", lwtype_name(type1));
579  return LW_FALSE;
580  }
581  dl->twisted = 1;
582  return lw_dist2d_fast_ptarray_ptarray(pa1, pa2, dl, lwg1->bbox, lwg2->bbox);
583 }
584 
585 /*------------------------------------------------------------------------------------------------------------
586 End of Preprocessing functions
587 --------------------------------------------------------------------------------------------------------------*/
588 
589 /*------------------------------------------------------------------------------------------------------------
590 Brute force functions
591 The old way of calculating distances, now used for:
592 1) distances to points (because there shouldn't be anything to gain by the new way of doing it)
593 2) distances when subgeometries geometries bboxes overlaps
594 --------------------------------------------------------------------------------------------------------------*/
595 
599 int
601 {
602  const POINT2D *p1 = getPoint2d_cp(point1->point, 0);
603  const POINT2D *p2 = getPoint2d_cp(point2->point, 0);
604  return lw_dist2d_pt_pt(p1, p2, dl);
605 }
609 int
611 {
612  const POINT2D *p = getPoint2d_cp(point->point, 0);
613  return lw_dist2d_pt_ptarray(p, line->points, dl);
614 }
615 
616 int
618 {
619  const POINT2D *pt = getPoint2d_cp(point->point, 0);
620  /* Is point inside triangle? */
621  if (dl->mode == DIST_MIN && ptarray_contains_point(tri->points, pt) != LW_OUTSIDE)
622  {
623  dl->distance = 0.0;
624  dl->p1.x = dl->p2.x = pt->x;
625  dl->p1.y = dl->p2.y = pt->y;
626  return LW_TRUE;
627  }
628 
629  return lw_dist2d_pt_ptarray(pt, tri->points, dl);
630 }
631 
632 int
634 {
635  const POINT2D *p;
636  p = getPoint2d_cp(point->point, 0);
637  return lw_dist2d_pt_ptarrayarc(p, circ->points, dl);
638 }
639 
645 int
647 {
648  const POINT2D *p = getPoint2d_cp(point->point, 0);
649 
650  /* Max distance? Check only outer ring.*/
651  if (dl->mode == DIST_MAX)
652  return lw_dist2d_pt_ptarray(p, poly->rings[0], dl);
653 
654  /* Return distance to outer ring if not inside it */
655  if (ptarray_contains_point(poly->rings[0], p) == LW_OUTSIDE)
656  return lw_dist2d_pt_ptarray(p, poly->rings[0], dl);
657 
658  /*
659  * Inside the outer ring.
660  * Scan though each of the inner rings looking to
661  * see if its inside. If not, distance==0.
662  * Otherwise, distance = pt to ring distance
663  */
664  for (uint32_t i = 1; i < poly->nrings; i++)
665  if (ptarray_contains_point(poly->rings[i], p) != LW_OUTSIDE)
666  return lw_dist2d_pt_ptarray(p, poly->rings[i], dl);
667 
668  /* Is inside the polygon */
669  dl->distance = 0.0;
670  dl->p1.x = dl->p2.x = p->x;
671  dl->p1.y = dl->p2.y = p->y;
672  return LW_TRUE;
673 }
674 
675 int
677 {
678  const POINT2D *p = getPoint2d_cp(point->point, 0);
679 
680  if (dl->mode == DIST_MAX)
681  lwerror("lw_dist2d_point_curvepoly cannot calculate max distance");
682 
683  /* Return distance to outer ring if not inside it */
684  if (lwgeom_contains_point(poly->rings[0], p) == LW_OUTSIDE)
685  return lw_dist2d_recursive((LWGEOM *)point, poly->rings[0], dl);
686 
687  /* Inside the outer ring.
688  * Scan though each of the inner rings looking to see if its inside. If not, distance==0.
689  * Otherwise, distance = pt to ring distance.
690  */
691  for (uint32_t i = 1; i < poly->nrings; i++)
692  if (lwgeom_contains_point(poly->rings[i], p) == LW_INSIDE)
693  return lw_dist2d_recursive((LWGEOM *)point, poly->rings[i], dl);
694 
695  /* Is inside the polygon */
696  dl->distance = 0.0;
697  dl->p1.x = dl->p2.x = p->x;
698  dl->p1.y = dl->p2.y = p->y;
699  return LW_TRUE;
700 }
701 
702 int
704 {
705  POINTARRAY *pa1 = line1->points;
706  POINTARRAY *pa2 = line2->points;
707  return lw_dist2d_ptarray_ptarray(pa1, pa2, dl);
708 }
709 
710 int
712 {
713  const POINT2D *pt = getPoint2d_cp(line->points, 0);
714  /* Is there a point inside triangle? */
715  if (dl->mode == DIST_MIN && ptarray_contains_point(tri->points, pt) != LW_OUTSIDE)
716  {
717  dl->distance = 0.0;
718  dl->p1.x = dl->p2.x = pt->x;
719  dl->p1.y = dl->p2.y = pt->y;
720  return LW_TRUE;
721  }
722 
723  return lw_dist2d_ptarray_ptarray(line->points, tri->points, dl);
724 }
725 
726 int
728 {
729  return lw_dist2d_ptarray_ptarrayarc(line1->points, line2->points, dl);
730 }
731 
743 int
745 {
746  POINTARRAY *pa = line->points;
747  const POINT2D *pt = getPoint2d_cp(pa, 0);
748 
749  /* Line has a pount outside poly. Check distance to outer ring only. */
750  if (ptarray_contains_point(poly->rings[0], pt) == LW_OUTSIDE || dl->mode == DIST_MAX)
751  return lw_dist2d_ptarray_ptarray(pa, poly->rings[0], dl);
752 
753  for (uint32_t i = 1; i < poly->nrings; i++)
754  {
755  if (!lw_dist2d_ptarray_ptarray(pa, poly->rings[i], dl))
756  return LW_FALSE;
757 
758  /* just a check if the answer is already given */
759  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
760  return LW_TRUE;
761  }
762 
763  /* It's inside a hole, then the actual distance is the min ring distance */
764  for (uint32_t i = 1; i < poly->nrings; i++)
765  if (ptarray_contains_point(poly->rings[i], pt) != LW_OUTSIDE)
766  return LW_TRUE;
767 
768  /* Not in hole, so inside polygon */
769  if (dl->mode == DIST_MIN)
770  {
771  dl->distance = 0.0;
772  dl->p1.x = dl->p2.x = pt->x;
773  dl->p1.y = dl->p2.y = pt->y;
774  }
775  return LW_TRUE;
776 }
777 
778 int
780 {
781  const POINT2D *pt = getPoint2d_cp(line->points, 0);
782 
783  /* Line has a pount outside curvepoly. Check distance to outer ring only. */
784  if (lwgeom_contains_point(poly->rings[0], pt) == LW_OUTSIDE)
785  return lw_dist2d_recursive((LWGEOM *)line, poly->rings[0], dl);
786 
787  for (uint32_t i = 1; i < poly->nrings; i++)
788  {
789  if (!lw_dist2d_recursive((LWGEOM *)line, poly->rings[i], dl))
790  return LW_FALSE;
791 
792  /* just a check if the answer is already given */
793  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
794  return LW_TRUE;
795  }
796 
797  /* It's inside a hole, then distance is actual min distance */
798  for (uint32_t i = 1; i < poly->nrings; i++)
799  if (lwgeom_contains_point(poly->rings[i], pt) != LW_OUTSIDE)
800  return LW_TRUE;
801 
802  /* Not in hole, so inside polygon */
803  if (dl->mode == DIST_MIN)
804  {
805  dl->distance = 0.0;
806  dl->p1.x = dl->p2.x = pt->x;
807  dl->p1.y = dl->p2.y = pt->y;
808  }
809  return LW_TRUE;
810 }
811 
812 int
814 {
815  POINTARRAY *pa1 = tri1->points;
816  POINTARRAY *pa2 = tri2->points;
817  const POINT2D *pt = getPoint2d_cp(pa2, 0);
818  if (dl->mode == DIST_MIN && ptarray_contains_point(pa1, pt) != LW_OUTSIDE)
819  {
820  dl->distance = 0.0;
821  dl->p1.x = dl->p2.x = pt->x;
822  dl->p1.y = dl->p2.y = pt->y;
823  return LW_TRUE;
824  }
825 
826  pt = getPoint2d_cp(pa1, 0);
827  if (dl->mode == DIST_MIN && ptarray_contains_point(pa2, pt) != LW_OUTSIDE)
828  {
829  dl->distance = 0.0;
830  dl->p1.x = dl->p2.x = pt->x;
831  dl->p1.y = dl->p2.y = pt->y;
832  return LW_TRUE;
833  }
834 
835  return lw_dist2d_ptarray_ptarray(pa1, pa2, dl);
836 }
837 
838 int
840 {
841  POINTARRAY *pa = tri->points;
842  const POINT2D *pt = getPoint2d_cp(pa, 0);
843 
844  /* If we are looking for maxdistance, just check the outer rings.*/
845  if (dl->mode == DIST_MAX)
846  return lw_dist2d_ptarray_ptarray(pa, poly->rings[0], dl);
847 
848  /* Triangle has a point outside poly. Check distance to outer ring only. */
849  if (ptarray_contains_point(poly->rings[0], pt) == LW_OUTSIDE)
850  {
851  if (!lw_dist2d_ptarray_ptarray(pa, poly->rings[0], dl))
852  return LW_FALSE;
853 
854  /* just a check if the answer is already given */
855  if (dl->distance <= dl->tolerance)
856  return LW_TRUE;
857 
858  /* Maybe poly is inside triangle? */
859  const POINT2D *pt2 = getPoint2d_cp(poly->rings[0], 0);
860  if (ptarray_contains_point(pa, pt2) != LW_OUTSIDE)
861  {
862  dl->distance = 0.0;
863  dl->p1.x = dl->p2.x = pt2->x;
864  dl->p1.y = dl->p2.y = pt2->y;
865  return LW_TRUE;
866  }
867  }
868 
869  for (uint32_t i = 1; i < poly->nrings; i++)
870  {
871  if (!lw_dist2d_ptarray_ptarray(pa, poly->rings[i], dl))
872  return LW_FALSE;
873 
874  /* just a check if the answer is already given */
875  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
876  return LW_TRUE;
877  }
878 
879  /* It's inside a hole, then the actual distance is the min ring distance */
880  for (uint32_t i = 1; i < poly->nrings; i++)
881  if (ptarray_contains_point(poly->rings[i], pt) != LW_OUTSIDE)
882  return LW_TRUE;
883 
884  /* Not in hole, so inside polygon */
885  dl->distance = 0.0;
886  dl->p1.x = dl->p2.x = pt->x;
887  dl->p1.y = dl->p2.y = pt->y;
888  return LW_TRUE;
889 }
890 static const POINT2D *
892 {
893  switch (geom->type)
894  {
895  case LINETYPE:
896  return getPoint2d_cp(((LWLINE *)geom)->points, 0);
897  case CIRCSTRINGTYPE:
898  return getPoint2d_cp(((LWCIRCSTRING *)geom)->points, 0);
899  case COMPOUNDTYPE:
900  {
901  LWCOMPOUND *comp = (LWCOMPOUND *)geom;
902  LWLINE *line = (LWLINE *)(comp->geoms[0]);
903  return getPoint2d_cp(line->points, 0);
904  }
905  default:
906  lwerror("lw_curvering_getfirstpoint2d_cp: unknown type");
907  }
908  return NULL;
909 }
910 
911 int
913 {
914  const POINT2D *pt = getPoint2d_cp(tri->points, 0);
915 
916  /* If we are looking for maxdistance, just check the outer rings.*/
917  if (dl->mode == DIST_MAX)
918  return lw_dist2d_recursive((LWGEOM *)tri, poly->rings[0], dl);
919 
920  /* Line has a pount outside curvepoly. Check distance to outer ring only. */
921  if (lwgeom_contains_point(poly->rings[0], pt) == LW_OUTSIDE)
922  {
923  if (lw_dist2d_recursive((LWGEOM *)tri, poly->rings[0], dl))
924  return LW_TRUE;
925  /* Maybe poly is inside triangle? */
927  {
928  dl->distance = 0.0;
929  dl->p1.x = dl->p2.x = pt->x;
930  dl->p1.y = dl->p2.y = pt->y;
931  return LW_TRUE;
932  }
933  }
934 
935  for (uint32_t i = 1; i < poly->nrings; i++)
936  {
937  if (!lw_dist2d_recursive((LWGEOM *)tri, poly->rings[i], dl))
938  return LW_FALSE;
939 
940  /* just a check if the answer is already given */
941  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
942  return LW_TRUE;
943  }
944 
945  /* It's inside a hole, then distance is actual min distance */
946  for (uint32_t i = 1; i < poly->nrings; i++)
947  if (lwgeom_contains_point(poly->rings[i], pt) != LW_OUTSIDE)
948  return LW_TRUE;
949 
950  /* Not in hole, so inside polygon */
951  dl->distance = 0.0;
952  dl->p1.x = dl->p2.x = pt->x;
953  dl->p1.y = dl->p2.y = pt->y;
954  return LW_TRUE;
955 }
956 
957 int
959 {
960  const POINT2D *pt = lw_curvering_getfirstpoint2d_cp((LWGEOM *)line);
961  if (ptarray_contains_point(tri->points, pt) != LW_OUTSIDE && dl->mode == DIST_MIN)
962  {
963  dl->distance = 0.0;
964  dl->p1.x = dl->p2.x = pt->x;
965  dl->p1.y = dl->p2.y = pt->y;
966  return LW_TRUE;
967  }
968 
969  return lw_dist2d_ptarray_ptarrayarc(tri->points, line->points, dl);
970 }
971 
981 int
983 {
984  const POINT2D *pt;
985 
986  LWDEBUG(2, "lw_dist2d_poly_poly called");
987 
988  /*1 if we are looking for maxdistance, just check the outer rings.*/
989  if (dl->mode == DIST_MAX)
990  return lw_dist2d_ptarray_ptarray(poly1->rings[0], poly2->rings[0], dl);
991 
992  /* 2 check if poly1 has first point outside poly2 and vice versa, if so, just check outer rings
993  here it would be possible to handle the information about which one is inside which one and only search for the
994  smaller ones in the bigger ones holes.*/
995  pt = getPoint2d_cp(poly1->rings[0], 0);
996  if (ptarray_contains_point(poly2->rings[0], pt) == LW_OUTSIDE)
997  {
998  pt = getPoint2d_cp(poly2->rings[0], 0);
999  if (ptarray_contains_point(poly1->rings[0], pt) == LW_OUTSIDE)
1000  return lw_dist2d_ptarray_ptarray(poly1->rings[0], poly2->rings[0], dl);
1001  }
1002 
1003  /*3 check if first point of poly2 is in a hole of poly1. If so check outer ring of poly2 against that hole
1004  * of poly1*/
1005  pt = getPoint2d_cp(poly2->rings[0], 0);
1006  for (uint32_t i = 1; i < poly1->nrings; i++)
1007  if (ptarray_contains_point(poly1->rings[i], pt) != LW_OUTSIDE)
1008  return lw_dist2d_ptarray_ptarray(poly1->rings[i], poly2->rings[0], dl);
1009 
1010  /*4 check if first point of poly1 is in a hole of poly2. If so check outer ring of poly1 against that hole
1011  * of poly2*/
1012  pt = getPoint2d_cp(poly1->rings[0], 0);
1013  for (uint32_t i = 1; i < poly2->nrings; i++)
1014  if (ptarray_contains_point(poly2->rings[i], pt) != LW_OUTSIDE)
1015  return lw_dist2d_ptarray_ptarray(poly1->rings[0], poly2->rings[i], dl);
1016 
1017  /*5 If we have come all the way here we know that the first point of one of them is inside the other ones
1018  * outer ring and not in holes so we check wich one is inside.*/
1019  pt = getPoint2d_cp(poly1->rings[0], 0);
1020  if (ptarray_contains_point(poly2->rings[0], pt) != LW_OUTSIDE)
1021  {
1022  dl->distance = 0.0;
1023  dl->p1.x = dl->p2.x = pt->x;
1024  dl->p1.y = dl->p2.y = pt->y;
1025  return LW_TRUE;
1026  }
1027 
1028  pt = getPoint2d_cp(poly2->rings[0], 0);
1029  if (ptarray_contains_point(poly1->rings[0], pt) != LW_OUTSIDE)
1030  {
1031  dl->distance = 0.0;
1032  dl->p1.x = dl->p2.x = pt->x;
1033  dl->p1.y = dl->p2.y = pt->y;
1034  return LW_TRUE;
1035  }
1036 
1037  lwerror("Unspecified error in function lw_dist2d_poly_poly");
1038  return LW_FALSE;
1039 }
1040 
1041 int
1043 {
1044  LWCURVEPOLY *curvepoly1 = lwcurvepoly_construct_from_lwpoly(poly1);
1045  int rv = lw_dist2d_curvepoly_curvepoly(curvepoly1, curvepoly2, dl);
1046  lwgeom_free((LWGEOM *)curvepoly1);
1047  return rv;
1048 }
1049 
1050 int
1052 {
1054  int rv = lw_dist2d_line_curvepoly((LWLINE *)circ, curvepoly, dl);
1055  lwgeom_free((LWGEOM *)curvepoly);
1056  return rv;
1057 }
1058 
1059 int
1061 {
1062  return lw_dist2d_line_curvepoly((LWLINE *)circ, poly, dl);
1063 }
1064 
1065 int
1067 {
1068  return lw_dist2d_ptarrayarc_ptarrayarc(line1->points, line2->points, dl);
1069 }
1070 
1071 int
1073 {
1074  const POINT2D *pt;
1075 
1076  /*1 if we are looking for maxdistance, just check the outer rings.*/
1077  if (dl->mode == DIST_MAX)
1078  return lw_dist2d_recursive(poly1->rings[0], poly2->rings[0], dl);
1079 
1080  /* 2 check if poly1 has first point outside poly2 and vice versa, if so, just check outer rings
1081  here it would be possible to handle the information about which one is inside which one and only search for the
1082  smaller ones in the bigger ones holes.*/
1083  pt = lw_curvering_getfirstpoint2d_cp(poly1->rings[0]);
1084  if (lwgeom_contains_point(poly2->rings[0], pt) == LW_OUTSIDE)
1085  {
1086  pt = lw_curvering_getfirstpoint2d_cp(poly2->rings[0]);
1087  if (lwgeom_contains_point(poly1->rings[0], pt) == LW_OUTSIDE)
1088  return lw_dist2d_recursive(poly1->rings[0], poly2->rings[0], dl);
1089  }
1090 
1091  /*3 check if first point of poly2 is in a hole of poly1. If so check outer ring of poly2 against that hole
1092  * of poly1*/
1093  pt = lw_curvering_getfirstpoint2d_cp(poly2->rings[0]);
1094  for (uint32_t i = 1; i < poly1->nrings; i++)
1095  if (lwgeom_contains_point(poly1->rings[i], pt) != LW_OUTSIDE)
1096  return lw_dist2d_recursive(poly1->rings[i], poly2->rings[0], dl);
1097 
1098  /*4 check if first point of poly1 is in a hole of poly2. If so check outer ring of poly1 against that hole
1099  * of poly2*/
1100  pt = lw_curvering_getfirstpoint2d_cp(poly1->rings[0]);
1101  for (uint32_t i = 1; i < poly2->nrings; i++)
1102  if (lwgeom_contains_point(poly2->rings[i], pt) != LW_OUTSIDE)
1103  return lw_dist2d_recursive(poly1->rings[0], poly2->rings[i], dl);
1104 
1105  /*5 If we have come all the way here we know that the first point of one of them is inside the other ones
1106  * outer ring and not in holes so we check which one is inside.*/
1107  pt = lw_curvering_getfirstpoint2d_cp(poly1->rings[0]);
1108  if (lwgeom_contains_point(poly2->rings[0], pt) != LW_OUTSIDE)
1109  {
1110  dl->distance = 0.0;
1111  dl->p1.x = dl->p2.x = pt->x;
1112  dl->p1.y = dl->p2.y = pt->y;
1113  return LW_TRUE;
1114  }
1115 
1116  pt = lw_curvering_getfirstpoint2d_cp(poly2->rings[0]);
1117  if (lwgeom_contains_point(poly1->rings[0], pt) != LW_OUTSIDE)
1118  {
1119  dl->distance = 0.0;
1120  dl->p1.x = dl->p2.x = pt->x;
1121  dl->p1.y = dl->p2.y = pt->y;
1122  return LW_TRUE;
1123  }
1124 
1125  lwerror("Unspecified error in function lw_dist2d_curvepoly_curvepoly");
1126  return LW_FALSE;
1127 }
1128 
1133 int
1135 {
1136  const POINT2D *start, *end;
1137  int twist = dl->twisted;
1138 
1139  start = getPoint2d_cp(pa, 0);
1140 
1141  LWDEBUG(2, "lw_dist2d_pt_ptarray enter");
1142 
1143  if (!lw_dist2d_pt_pt(p, start, dl))
1144  return LW_FALSE;
1145 
1146  LWDEBUGF(2, "lw_dist2d_pt_ptarray: distance from first point ? : %.15g", dl->distance);
1147 
1148  for (uint32_t t = 1; t < pa->npoints; t++)
1149  {
1150  dl->twisted = twist;
1151  end = getPoint2d_cp(pa, t);
1152  if (!lw_dist2d_pt_seg(p, start, end, dl))
1153  return LW_FALSE;
1154 
1155  LWDEBUGF(2, "lw_dist2d_pt_ptarray: distance from seg %lu ? : %.15g", t, dl->distance);
1156 
1157  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
1158  return LW_TRUE; /*just a check if the answer is already given*/
1159  start = end;
1160  }
1161 
1162  return LW_TRUE;
1163 }
1164 
1169 int
1171 {
1172  uint32_t t;
1173  const POINT2D *A1;
1174  const POINT2D *A2;
1175  const POINT2D *A3;
1176  int twist = dl->twisted;
1177 
1178  LWDEBUG(2, "lw_dist2d_pt_ptarrayarc is called");
1179 
1180  if (pa->npoints % 2 == 0 || pa->npoints < 3)
1181  {
1182  lwerror("lw_dist2d_pt_ptarrayarc called with non-arc input");
1183  return LW_FALSE;
1184  }
1185 
1186  if (dl->mode == DIST_MAX)
1187  {
1188  lwerror("lw_dist2d_pt_ptarrayarc does not currently support DIST_MAX mode");
1189  return LW_FALSE;
1190  }
1191 
1192  A1 = getPoint2d_cp(pa, 0);
1193 
1194  if (!lw_dist2d_pt_pt(p, A1, dl))
1195  return LW_FALSE;
1196 
1197  for (t = 1; t < pa->npoints; t += 2)
1198  {
1199  dl->twisted = twist;
1200  A2 = getPoint2d_cp(pa, t);
1201  A3 = getPoint2d_cp(pa, t + 1);
1202 
1203  if (lw_dist2d_pt_arc(p, A1, A2, A3, dl) == LW_FALSE)
1204  return LW_FALSE;
1205 
1206  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
1207  return LW_TRUE; /*just a check if the answer is already given*/
1208 
1209  A1 = A3;
1210  }
1211 
1212  return LW_TRUE;
1213 }
1214 
1218 int
1220 {
1221  uint32_t t, u;
1222  const POINT2D *start, *end;
1223  const POINT2D *start2, *end2;
1224  int twist = dl->twisted;
1225 
1226  LWDEBUGF(2, "lw_dist2d_ptarray_ptarray called (points: %d-%d)", l1->npoints, l2->npoints);
1227 
1228  /* If we are searching for maxdistance we go straight to point-point calculation since the maxdistance have
1229  * to be between two vertexes*/
1230  if (dl->mode == DIST_MAX)
1231  {
1232  for (t = 0; t < l1->npoints; t++) /*for each segment in L1 */
1233  {
1234  start = getPoint2d_cp(l1, t);
1235  for (u = 0; u < l2->npoints; u++) /*for each segment in L2 */
1236  {
1237  start2 = getPoint2d_cp(l2, u);
1238  lw_dist2d_pt_pt(start, start2, dl);
1239  }
1240  }
1241  }
1242  else
1243  {
1244  start = getPoint2d_cp(l1, 0);
1245  for (t = 1; t < l1->npoints; t++) /*for each segment in L1 */
1246  {
1247  end = getPoint2d_cp(l1, t);
1248  start2 = getPoint2d_cp(l2, 0);
1249  for (u = 1; u < l2->npoints; u++) /*for each segment in L2 */
1250  {
1251  end2 = getPoint2d_cp(l2, u);
1252  dl->twisted = twist;
1253  lw_dist2d_seg_seg(start, end, start2, end2, dl);
1254  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
1255  return LW_TRUE; /*just a check if the answer is already given*/
1256  start2 = end2;
1257  }
1258  start = end;
1259  }
1260  }
1261  return LW_TRUE;
1262 }
1263 
1267 int
1269 {
1270  uint32_t t, u;
1271  const POINT2D *A1;
1272  const POINT2D *A2;
1273  const POINT2D *B1;
1274  const POINT2D *B2;
1275  const POINT2D *B3;
1276  int twist = dl->twisted;
1277 
1278  LWDEBUGF(2, "lw_dist2d_ptarray_ptarrayarc called (points: %d-%d)", pa->npoints, pb->npoints);
1279 
1280  if (pb->npoints % 2 == 0 || pb->npoints < 3)
1281  {
1282  lwerror("lw_dist2d_ptarray_ptarrayarc called with non-arc input");
1283  return LW_FALSE;
1284  }
1285 
1286  if (dl->mode == DIST_MAX)
1287  {
1288  lwerror("lw_dist2d_ptarray_ptarrayarc does not currently support DIST_MAX mode");
1289  return LW_FALSE;
1290  }
1291  else
1292  {
1293  A1 = getPoint2d_cp(pa, 0);
1294  for (t = 1; t < pa->npoints; t++) /* For each segment in pa */
1295  {
1296  A2 = getPoint2d_cp(pa, t);
1297  B1 = getPoint2d_cp(pb, 0);
1298  for (u = 1; u < pb->npoints; u += 2) /* For each arc in pb */
1299  {
1300  B2 = getPoint2d_cp(pb, u);
1301  B3 = getPoint2d_cp(pb, u + 1);
1302  dl->twisted = twist;
1303 
1304  lw_dist2d_seg_arc(A1, A2, B1, B2, B3, dl);
1305 
1306  /* If we've found a distance within tolerance, we're done */
1307  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
1308  return LW_TRUE;
1309 
1310  B1 = B3;
1311  }
1312  A1 = A2;
1313  }
1314  }
1315  return LW_TRUE;
1316 }
1317 
1321 int
1323 {
1324  uint32_t t, u;
1325  const POINT2D *A1;
1326  const POINT2D *A2;
1327  const POINT2D *A3;
1328  const POINT2D *B1;
1329  const POINT2D *B2;
1330  const POINT2D *B3;
1331  int twist = dl->twisted;
1332 
1333  LWDEBUGF(2, "lw_dist2d_ptarrayarc_ptarrayarc called (points: %d-%d)", pa->npoints, pb->npoints);
1334 
1335  if (dl->mode == DIST_MAX)
1336  {
1337  lwerror("lw_dist2d_ptarrayarc_ptarrayarc does not currently support DIST_MAX mode");
1338  return LW_FALSE;
1339  }
1340  else
1341  {
1342  A1 = getPoint2d_cp(pa, 0);
1343  for (t = 1; t < pa->npoints; t += 2) /* For each segment in pa */
1344  {
1345  A2 = getPoint2d_cp(pa, t);
1346  A3 = getPoint2d_cp(pa, t + 1);
1347  B1 = getPoint2d_cp(pb, 0);
1348  for (u = 1; u < pb->npoints; u += 2) /* For each arc in pb */
1349  {
1350  B2 = getPoint2d_cp(pb, u);
1351  B3 = getPoint2d_cp(pb, u + 1);
1352  dl->twisted = twist;
1353 
1354  lw_dist2d_arc_arc(A1, A2, A3, B1, B2, B3, dl);
1355 
1356  /* If we've found a distance within tolerance, we're done */
1357  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
1358  return LW_TRUE;
1359 
1360  B1 = B3;
1361  }
1362  A1 = A3;
1363  }
1364  }
1365  return LW_TRUE;
1366 }
1367 
1372 int
1374  const POINT2D *A2,
1375  const POINT2D *B1,
1376  const POINT2D *B2,
1377  const POINT2D *B3,
1378  DISTPTS *dl)
1379 {
1380  POINT2D C; /* center of arc circle */
1381  double radius_C; /* radius of arc circle */
1382  POINT2D D; /* point on A closest to C */
1383  double dist_C_D; /* distance from C to D */
1384  int pt_in_arc, pt_in_seg;
1385  DISTPTS dltmp;
1386 
1387  /* Bail out on crazy modes */
1388  if (dl->mode < 0)
1389  lwerror("lw_dist2d_seg_arc does not support maxdistance mode");
1390 
1391  /* What if the "arc" is a point? */
1392  if (lw_arc_is_pt(B1, B2, B3))
1393  return lw_dist2d_pt_seg(B1, A1, A2, dl);
1394 
1395  /* Calculate center and radius of the circle. */
1396  radius_C = lw_arc_center(B1, B2, B3, &C);
1397 
1398  /* This "arc" is actually a line (B2 is collinear with B1,B3) */
1399  if (radius_C < 0.0)
1400  return lw_dist2d_seg_seg(A1, A2, B1, B3, dl);
1401 
1402  /* Calculate distance between the line and circle center */
1404  if (lw_dist2d_pt_seg(&C, A1, A2, &dltmp) == LW_FALSE)
1405  lwerror("lw_dist2d_pt_seg failed in lw_dist2d_seg_arc");
1406 
1407  D = dltmp.p1;
1408  dist_C_D = dltmp.distance;
1409 
1410  /* Line intersects circle, maybe arc intersects edge? */
1411  /* If so, that's the closest point. */
1412  /* If not, the closest point is one of the end points of A */
1413  if (dist_C_D < radius_C)
1414  {
1415  double length_A; /* length of the segment A */
1416  POINT2D E, F; /* points of intersection of edge A and circle(B) */
1417  double dist_D_EF; /* distance from D to E or F (same distance both ways) */
1418 
1419  dist_D_EF = sqrt(radius_C * radius_C - dist_C_D * dist_C_D);
1420  length_A = sqrt((A2->x - A1->x) * (A2->x - A1->x) + (A2->y - A1->y) * (A2->y - A1->y));
1421 
1422  /* Point of intersection E */
1423  E.x = D.x - (A2->x - A1->x) * dist_D_EF / length_A;
1424  E.y = D.y - (A2->y - A1->y) * dist_D_EF / length_A;
1425  /* Point of intersection F */
1426  F.x = D.x + (A2->x - A1->x) * dist_D_EF / length_A;
1427  F.y = D.y + (A2->y - A1->y) * dist_D_EF / length_A;
1428 
1429  /* If E is within A and within B then it's an intersection point */
1430  pt_in_arc = lw_pt_in_arc(&E, B1, B2, B3);
1431  pt_in_seg = lw_pt_in_seg(&E, A1, A2);
1432 
1433  if (pt_in_arc && pt_in_seg)
1434  {
1435  dl->distance = 0.0;
1436  dl->p1 = E;
1437  dl->p2 = E;
1438  return LW_TRUE;
1439  }
1440 
1441  /* If F is within A and within B then it's an intersection point */
1442  pt_in_arc = lw_pt_in_arc(&F, B1, B2, B3);
1443  pt_in_seg = lw_pt_in_seg(&F, A1, A2);
1444 
1445  if (pt_in_arc && pt_in_seg)
1446  {
1447  dl->distance = 0.0;
1448  dl->p1 = F;
1449  dl->p2 = F;
1450  return LW_TRUE;
1451  }
1452  }
1453 
1454  /* Line grazes circle, maybe arc intersects edge? */
1455  /* If so, grazing point is the closest point. */
1456  /* If not, the closest point is one of the end points of A */
1457  else if (dist_C_D == radius_C)
1458  {
1459  /* Closest point D is also the point of grazing */
1460  pt_in_arc = lw_pt_in_arc(&D, B1, B2, B3);
1461  pt_in_seg = lw_pt_in_seg(&D, A1, A2);
1462 
1463  /* Is D contained in both A and B? */
1464  if (pt_in_arc && pt_in_seg)
1465  {
1466  dl->distance = 0.0;
1467  dl->p1 = D;
1468  dl->p2 = D;
1469  return LW_TRUE;
1470  }
1471  }
1472  /* Line misses circle. */
1473  /* If closest point to A on circle is within B, then that's the closest */
1474  /* Otherwise, the closest point will be an end point of A */
1475  else
1476  {
1477  POINT2D G; /* Point on circle closest to A */
1478  G.x = C.x + (D.x - C.x) * radius_C / dist_C_D;
1479  G.y = C.y + (D.y - C.y) * radius_C / dist_C_D;
1480 
1481  pt_in_arc = lw_pt_in_arc(&G, B1, B2, B3);
1482  pt_in_seg = lw_pt_in_seg(&D, A1, A2);
1483 
1484  /* Closest point is on the interior of A and B */
1485  if (pt_in_arc && pt_in_seg)
1486  return lw_dist2d_pt_pt(&D, &G, dl);
1487  }
1488 
1489  /* Now we test the many combinations of end points with either */
1490  /* arcs or edges. Each previous check determined if the closest */
1491  /* potential point was within the arc/segment inscribed on the */
1492  /* line/circle holding the arc/segment. */
1493 
1494  /* Closest point is in the arc, but not in the segment, so */
1495  /* one of the segment end points must be the closest. */
1496  if (pt_in_arc && !pt_in_seg)
1497  {
1498  lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1499  lw_dist2d_pt_arc(A2, B1, B2, B3, dl);
1500  return LW_TRUE;
1501  }
1502  /* or, one of the arc end points is the closest */
1503  else if (pt_in_seg && !pt_in_arc)
1504  {
1505  lw_dist2d_pt_seg(B1, A1, A2, dl);
1506  lw_dist2d_pt_seg(B3, A1, A2, dl);
1507  return LW_TRUE;
1508  }
1509  /* Finally, one of the end-point to end-point combos is the closest. */
1510  else
1511  {
1512  lw_dist2d_pt_pt(A1, B1, dl);
1513  lw_dist2d_pt_pt(A1, B3, dl);
1514  lw_dist2d_pt_pt(A2, B1, dl);
1515  lw_dist2d_pt_pt(A2, B3, dl);
1516  return LW_TRUE;
1517  }
1518 
1519  return LW_FALSE;
1520 }
1521 
1522 int
1523 lw_dist2d_pt_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, DISTPTS *dl)
1524 {
1525  double radius_A, d;
1526  POINT2D C; /* center of circle defined by arc A */
1527  POINT2D X; /* point circle(A) where line from C to P crosses */
1528 
1529  if (dl->mode < 0)
1530  lwerror("lw_dist2d_pt_arc does not support maxdistance mode");
1531 
1532  /* What if the arc is a point? */
1533  if (lw_arc_is_pt(A1, A2, A3))
1534  return lw_dist2d_pt_pt(P, A1, dl);
1535 
1536  /* Calculate centers and radii of circles. */
1537  radius_A = lw_arc_center(A1, A2, A3, &C);
1538 
1539  /* This "arc" is actually a line (A2 is colinear with A1,A3) */
1540  if (radius_A < 0.0)
1541  return lw_dist2d_pt_seg(P, A1, A3, dl);
1542 
1543  /* Distance from point to center */
1544  d = distance2d_pt_pt(&C, P);
1545 
1546  /* P is the center of the circle */
1547  if (FP_EQUALS(d, 0.0))
1548  {
1549  dl->distance = radius_A;
1550  dl->p1 = *A1;
1551  dl->p2 = *P;
1552  return LW_TRUE;
1553  }
1554 
1555  /* X is the point on the circle where the line from P to C crosses */
1556  X.x = C.x + (P->x - C.x) * radius_A / d;
1557  X.y = C.y + (P->y - C.y) * radius_A / d;
1558 
1559  /* Is crossing point inside the arc? Or arc is actually circle? */
1560  if (p2d_same(A1, A3) || lw_pt_in_arc(&X, A1, A2, A3))
1561  {
1562  lw_dist2d_pt_pt(P, &X, dl);
1563  }
1564  else
1565  {
1566  /* Distance is the minimum of the distances to the arc end points */
1567  lw_dist2d_pt_pt(A1, P, dl);
1568  lw_dist2d_pt_pt(A3, P, dl);
1569  }
1570  return LW_TRUE;
1571 }
1572 
1573 /* Auxiliary function to calculate the distance between 2 concentric arcs*/
1575  const POINT2D *A2,
1576  const POINT2D *A3,
1577  double radius_A,
1578  const POINT2D *B1,
1579  const POINT2D *B2,
1580  const POINT2D *B3,
1581  double radius_B,
1582  const POINT2D *CENTER,
1583  DISTPTS *dl);
1584 
1585 int
1587  const POINT2D *A2,
1588  const POINT2D *A3,
1589  const POINT2D *B1,
1590  const POINT2D *B2,
1591  const POINT2D *B3,
1592  DISTPTS *dl)
1593 {
1594  POINT2D CA, CB; /* Center points of arcs A and B */
1595  double radius_A, radius_B, d; /* Radii of arcs A and B */
1596  POINT2D D; /* Mid-point between the centers CA and CB */
1597  int pt_in_arc_A, pt_in_arc_B; /* Test whether potential intersection point is within the arc */
1598 
1599  if (dl->mode != DIST_MIN)
1600  lwerror("lw_dist2d_arc_arc only supports mindistance");
1601 
1602  /* TODO: Handle case where arc is closed circle (A1 = A3) */
1603 
1604  /* What if one or both of our "arcs" is actually a point? */
1605  if (lw_arc_is_pt(B1, B2, B3) && lw_arc_is_pt(A1, A2, A3))
1606  return lw_dist2d_pt_pt(B1, A1, dl);
1607  else if (lw_arc_is_pt(B1, B2, B3))
1608  return lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1609  else if (lw_arc_is_pt(A1, A2, A3))
1610  return lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1611 
1612  /* Calculate centers and radii of circles. */
1613  radius_A = lw_arc_center(A1, A2, A3, &CA);
1614  radius_B = lw_arc_center(B1, B2, B3, &CB);
1615 
1616  /* Two co-linear arcs?!? That's two segments. */
1617  if (radius_A < 0 && radius_B < 0)
1618  return lw_dist2d_seg_seg(A1, A3, B1, B3, dl);
1619 
1620  /* A is co-linear, delegate to lw_dist_seg_arc here. */
1621  if (radius_A < 0)
1622  return lw_dist2d_seg_arc(A1, A3, B1, B2, B3, dl);
1623 
1624  /* B is co-linear, delegate to lw_dist_seg_arc here. */
1625  if (radius_B < 0)
1626  return lw_dist2d_seg_arc(B1, B3, A1, A2, A3, dl);
1627 
1628  /* Center-center distance */
1629  d = distance2d_pt_pt(&CA, &CB);
1630 
1631  /* Concentric arcs */
1632  if (FP_EQUALS(d, 0.0))
1633  return lw_dist2d_arc_arc_concentric(A1, A2, A3, radius_A, B1, B2, B3, radius_B, &CA, dl);
1634 
1635  /* Make sure that arc "A" has the bigger radius */
1636  if (radius_B > radius_A)
1637  {
1638  const POINT2D *tmp;
1639  POINT2D TP; /* Temporary point P */
1640  double td;
1641  tmp = B1;
1642  B1 = A1;
1643  A1 = tmp;
1644  tmp = B2;
1645  B2 = A2;
1646  A2 = tmp;
1647  tmp = B3;
1648  B3 = A3;
1649  A3 = tmp;
1650  TP = CB;
1651  CB = CA;
1652  CA = TP;
1653  td = radius_B;
1654  radius_B = radius_A;
1655  radius_A = td;
1656  }
1657 
1658  /* Circles touch at a point. Is that point within the arcs? */
1659  if (d == (radius_A + radius_B))
1660  {
1661  D.x = CA.x + (CB.x - CA.x) * radius_A / d;
1662  D.y = CA.y + (CB.y - CA.y) * radius_A / d;
1663 
1664  pt_in_arc_A = lw_pt_in_arc(&D, A1, A2, A3);
1665  pt_in_arc_B = lw_pt_in_arc(&D, B1, B2, B3);
1666 
1667  /* Arcs do touch at D, return it */
1668  if (pt_in_arc_A && pt_in_arc_B)
1669  {
1670  dl->distance = 0.0;
1671  dl->p1 = D;
1672  dl->p2 = D;
1673  return LW_TRUE;
1674  }
1675  }
1676  /* Disjoint or contained circles don't intersect. Closest point may be on */
1677  /* the line joining CA to CB. */
1678  else if (d > (radius_A + radius_B) /* Disjoint */ || d < (radius_A - radius_B) /* Contained */)
1679  {
1680  POINT2D XA, XB; /* Points where the line from CA to CB cross their circle bounds */
1681 
1682  /* Calculate hypothetical nearest points, the places on the */
1683  /* two circles where the center-center line crosses. If both */
1684  /* arcs contain their hypothetical points, that's the crossing distance */
1685  XA.x = CA.x + (CB.x - CA.x) * radius_A / d;
1686  XA.y = CA.y + (CB.y - CA.y) * radius_A / d;
1687  XB.x = CB.x + (CA.x - CB.x) * radius_B / d;
1688  XB.y = CB.y + (CA.y - CB.y) * radius_B / d;
1689 
1690  pt_in_arc_A = lw_pt_in_arc(&XA, A1, A2, A3);
1691  pt_in_arc_B = lw_pt_in_arc(&XB, B1, B2, B3);
1692 
1693  /* If the nearest points are both within the arcs, that's our answer */
1694  /* the shortest distance is at the nearest points */
1695  if (pt_in_arc_A && pt_in_arc_B)
1696  {
1697  return lw_dist2d_pt_pt(&XA, &XB, dl);
1698  }
1699  }
1700  /* Circles cross at two points, are either of those points in both arcs? */
1701  /* http://paulbourke.net/geometry/2circle/ */
1702  else if (d < (radius_A + radius_B))
1703  {
1704  POINT2D E, F; /* Points where circle(A) and circle(B) cross */
1705  /* Distance from CA to D */
1706  double a = (radius_A * radius_A - radius_B * radius_B + d * d) / (2 * d);
1707  /* Distance from D to E or F */
1708  double h = sqrt(radius_A * radius_A - a * a);
1709 
1710  /* Location of D */
1711  D.x = CA.x + (CB.x - CA.x) * a / d;
1712  D.y = CA.y + (CB.y - CA.y) * a / d;
1713 
1714  /* Start from D and project h units perpendicular to CA-D to get E */
1715  E.x = D.x + (D.y - CA.y) * h / a;
1716  E.y = D.y + (D.x - CA.x) * h / a;
1717 
1718  /* Crossing point E contained in arcs? */
1719  pt_in_arc_A = lw_pt_in_arc(&E, A1, A2, A3);
1720  pt_in_arc_B = lw_pt_in_arc(&E, B1, B2, B3);
1721 
1722  if (pt_in_arc_A && pt_in_arc_B)
1723  {
1724  dl->p1 = dl->p2 = E;
1725  dl->distance = 0.0;
1726  return LW_TRUE;
1727  }
1728 
1729  /* Start from D and project h units perpendicular to CA-D to get F */
1730  F.x = D.x - (D.y - CA.y) * h / a;
1731  F.y = D.y - (D.x - CA.x) * h / a;
1732 
1733  /* Crossing point F contained in arcs? */
1734  pt_in_arc_A = lw_pt_in_arc(&F, A1, A2, A3);
1735  pt_in_arc_B = lw_pt_in_arc(&F, B1, B2, B3);
1736 
1737  if (pt_in_arc_A && pt_in_arc_B)
1738  {
1739  dl->p1 = dl->p2 = F;
1740  dl->distance = 0.0;
1741  return LW_TRUE;
1742  }
1743  }
1744  else
1745  {
1746  lwerror("lw_dist2d_arc_arc: arcs neither touch, intersect nor are disjoint! INCONCEIVABLE!");
1747  return LW_FALSE;
1748  }
1749 
1750  /* Closest point is in the arc A, but not in the arc B, so */
1751  /* one of the B end points must be the closest. */
1752  if (pt_in_arc_A && !pt_in_arc_B)
1753  {
1754  lw_dist2d_pt_arc(B1, A1, A2, A3, dl);
1755  lw_dist2d_pt_arc(B3, A1, A2, A3, dl);
1756  return LW_TRUE;
1757  }
1758  /* Closest point is in the arc B, but not in the arc A, so */
1759  /* one of the A end points must be the closest. */
1760  else if (pt_in_arc_B && !pt_in_arc_A)
1761  {
1762  lw_dist2d_pt_arc(A1, B1, B2, B3, dl);
1763  lw_dist2d_pt_arc(A3, B1, B2, B3, dl);
1764  return LW_TRUE;
1765  }
1766  /* Finally, one of the end-point to end-point combos is the closest. */
1767  else
1768  {
1769  lw_dist2d_pt_pt(A1, B1, dl);
1770  lw_dist2d_pt_pt(A1, B3, dl);
1771  lw_dist2d_pt_pt(A3, B1, dl);
1772  lw_dist2d_pt_pt(A3, B3, dl);
1773  return LW_TRUE;
1774  }
1775 
1776  return LW_TRUE;
1777 }
1778 
1779 int
1781  const POINT2D *A2,
1782  const POINT2D *A3,
1783  double radius_A,
1784  const POINT2D *B1,
1785  const POINT2D *B2,
1786  const POINT2D *B3,
1787  double radius_B,
1788  const POINT2D *CENTER,
1789  DISTPTS *dl)
1790 {
1791  int seg_size;
1792  double dist_sqr, shortest_sqr;
1793  const POINT2D *P1;
1794  const POINT2D *P2;
1795  POINT2D proj;
1796 
1797  if (radius_A == radius_B)
1798  {
1799  /* Check if B1 or B3 are in the same side as A2 in the A1-A3 arc */
1800  seg_size = lw_segment_side(A1, A3, A2);
1801  if (seg_size == lw_segment_side(A1, A3, B1))
1802  {
1803  dl->p1 = *B1;
1804  dl->p2 = *B1;
1805  dl->distance = 0;
1806  return LW_TRUE;
1807  }
1808  if (seg_size == lw_segment_side(A1, A3, B3))
1809  {
1810  dl->p1 = *B3;
1811  dl->p2 = *B3;
1812  dl->distance = 0;
1813  return LW_TRUE;
1814  }
1815  /* Check if A1 or A3 are in the same side as B2 in the B1-B3 arc */
1816  seg_size = lw_segment_side(B1, B3, B2);
1817  if (seg_size == lw_segment_side(B1, B3, A1))
1818  {
1819  dl->p1 = *A1;
1820  dl->p2 = *A1;
1821  dl->distance = 0;
1822  return LW_TRUE;
1823  }
1824  if (seg_size == lw_segment_side(B1, B3, A3))
1825  {
1826  dl->p1 = *A3;
1827  dl->p2 = *A3;
1828  dl->distance = 0;
1829  return LW_TRUE;
1830  }
1831  }
1832  else
1833  {
1834  /* Check if any projection of B ends are in A*/
1835  seg_size = lw_segment_side(A1, A3, A2);
1836 
1837  /* B1 */
1838  proj.x = CENTER->x + (B1->x - CENTER->x) * radius_A / radius_B;
1839  proj.y = CENTER->y + (B1->y - CENTER->y) * radius_A / radius_B;
1840 
1841  if (seg_size == lw_segment_side(A1, A3, &proj))
1842  {
1843  dl->p1 = proj;
1844  dl->p2 = *B1;
1845  dl->distance = fabs(radius_A - radius_B);
1846  return LW_TRUE;
1847  }
1848  /* B3 */
1849  proj.x = CENTER->x + (B3->x - CENTER->x) * radius_A / radius_B;
1850  proj.y = CENTER->y + (B3->y - CENTER->y) * radius_A / radius_B;
1851  if (seg_size == lw_segment_side(A1, A3, &proj))
1852  {
1853  dl->p1 = proj;
1854  dl->p2 = *B3;
1855  dl->distance = fabs(radius_A - radius_B);
1856  return LW_TRUE;
1857  }
1858 
1859  /* Now check projections of A in B */
1860  seg_size = lw_segment_side(B1, B3, B2);
1861 
1862  /* A1 */
1863  proj.x = CENTER->x + (A1->x - CENTER->x) * radius_B / radius_A;
1864  proj.y = CENTER->y + (A1->y - CENTER->y) * radius_B / radius_A;
1865  if (seg_size == lw_segment_side(B1, B3, &proj))
1866  {
1867  dl->p1 = proj;
1868  dl->p2 = *A1;
1869  dl->distance = fabs(radius_A - radius_B);
1870  return LW_TRUE;
1871  }
1872 
1873  /* A3 */
1874  proj.x = CENTER->x + (A3->x - CENTER->x) * radius_B / radius_A;
1875  proj.y = CENTER->y + (A3->y - CENTER->y) * radius_B / radius_A;
1876  if (seg_size == lw_segment_side(B1, B3, &proj))
1877  {
1878  dl->p1 = proj;
1879  dl->p2 = *A3;
1880  dl->distance = fabs(radius_A - radius_B);
1881  return LW_TRUE;
1882  }
1883  }
1884 
1885  /* Check the shortest between the distances of the 4 ends */
1886  shortest_sqr = dist_sqr = distance2d_sqr_pt_pt(A1, B1);
1887  P1 = A1;
1888  P2 = B1;
1889 
1890  dist_sqr = distance2d_sqr_pt_pt(A1, B3);
1891  if (dist_sqr < shortest_sqr)
1892  {
1893  shortest_sqr = dist_sqr;
1894  P1 = A1;
1895  P2 = B3;
1896  }
1897 
1898  dist_sqr = distance2d_sqr_pt_pt(A3, B1);
1899  if (dist_sqr < shortest_sqr)
1900  {
1901  shortest_sqr = dist_sqr;
1902  P1 = A3;
1903  P2 = B1;
1904  }
1905 
1906  dist_sqr = distance2d_sqr_pt_pt(A3, B3);
1907  if (dist_sqr < shortest_sqr)
1908  {
1909  shortest_sqr = dist_sqr;
1910  P1 = A3;
1911  P2 = B3;
1912  }
1913 
1914  dl->p1 = *P1;
1915  dl->p2 = *P2;
1916  dl->distance = sqrt(shortest_sqr);
1917 
1918  return LW_TRUE;
1919 }
1920 
1926 int
1927 lw_dist2d_seg_seg(const POINT2D *A, const POINT2D *B, const POINT2D *C, const POINT2D *D, DISTPTS *dl)
1928 {
1929  double s_top, s_bot, s;
1930  double r_top, r_bot, r;
1931 
1932  /*A and B are the same point */
1933  if ((A->x == B->x) && (A->y == B->y))
1934  {
1935  return lw_dist2d_pt_seg(A, C, D, dl);
1936  }
1937 
1938  /*U and V are the same point */
1939  if ((C->x == D->x) && (C->y == D->y))
1940  {
1941  dl->twisted = ((dl->twisted) * (-1));
1942  return lw_dist2d_pt_seg(D, A, B, dl);
1943  }
1944 
1945  /* AB and CD are line segments */
1946  /* from comp.graphics.algo
1947 
1948  Solving the above for r and s yields
1949  (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
1950  r = ----------------------------- (eqn 1)
1951  (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
1952 
1953  (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
1954  s = ----------------------------- (eqn 2)
1955  (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
1956  Let P be the position vector of the intersection point, then
1957  P=A+r(B-A) or
1958  Px=Ax+r(Bx-Ax)
1959  Py=Ay+r(By-Ay)
1960  By examining the values of r & s, you can also determine some other limiting conditions:
1961  If 0<=r<=1 & 0<=s<=1, intersection exists
1962  r<0 or r>1 or s<0 or s>1 line segments do not intersect
1963  If the denominator in eqn 1 is zero, AB & CD are parallel
1964  If the numerator in eqn 1 is also zero, AB & CD are collinear.
1965 
1966  */
1967  r_top = (A->y - C->y) * (D->x - C->x) - (A->x - C->x) * (D->y - C->y);
1968  r_bot = (B->x - A->x) * (D->y - C->y) - (B->y - A->y) * (D->x - C->x);
1969 
1970  s_top = (A->y - C->y) * (B->x - A->x) - (A->x - C->x) * (B->y - A->y);
1971  s_bot = (B->x - A->x) * (D->y - C->y) - (B->y - A->y) * (D->x - C->x);
1972 
1973  if ((r_bot == 0) || (s_bot == 0))
1974  {
1975  if ((lw_dist2d_pt_seg(A, C, D, dl)) && (lw_dist2d_pt_seg(B, C, D, dl)))
1976  {
1977  /* change the order of inputted geometries and that we notice by changing sign on dl->twisted*/
1978  dl->twisted *= -1;
1979  return ((lw_dist2d_pt_seg(C, A, B, dl)) && (lw_dist2d_pt_seg(D, A, B, dl)));
1980  }
1981  else
1982  return LW_FALSE; /* if any of the calls to lw_dist2d_pt_seg goes wrong we return false*/
1983  }
1984 
1985  s = s_top / s_bot;
1986  r = r_top / r_bot;
1987 
1988  if (((r < 0) || (r > 1) || (s < 0) || (s > 1)) || (dl->mode == DIST_MAX))
1989  {
1990  if ((lw_dist2d_pt_seg(A, C, D, dl)) && (lw_dist2d_pt_seg(B, C, D, dl)))
1991  {
1992  /* change the order of inputted geometries and that we notice by changing sign on dl->twisted*/
1993  dl->twisted *= -1;
1994  return ((lw_dist2d_pt_seg(C, A, B, dl)) && (lw_dist2d_pt_seg(D, A, B, dl)));
1995  }
1996  else
1997  return LW_FALSE; /* if any of the calls to lw_dist2d_pt_seg goes wrong we return false*/
1998  }
1999  else
2000  {
2001  /* If there is intersection we identify the intersection point and return it but only if we are looking
2002  * for mindistance */
2003  if (dl->mode == DIST_MIN)
2004  {
2005  POINT2D theP;
2006 
2007  if (((A->x == C->x) && (A->y == C->y)) || ((A->x == D->x) && (A->y == D->y)))
2008  {
2009  theP.x = A->x;
2010  theP.y = A->y;
2011  }
2012  else if (((B->x == C->x) && (B->y == C->y)) || ((B->x == D->x) && (B->y == D->y)))
2013  {
2014  theP.x = B->x;
2015  theP.y = B->y;
2016  }
2017  else
2018  {
2019  theP.x = A->x + r * (B->x - A->x);
2020  theP.y = A->y + r * (B->y - A->y);
2021  }
2022  dl->distance = 0.0;
2023  dl->p1 = theP;
2024  dl->p2 = theP;
2025  }
2026  return LW_TRUE;
2027  }
2028 }
2029 
2030 /*------------------------------------------------------------------------------------------------------------
2031 End of Brute force functions
2032 --------------------------------------------------------------------------------------------------------------*/
2033 
2034 /*------------------------------------------------------------------------------------------------------------
2035 New faster distance calculations
2036 --------------------------------------------------------------------------------------------------------------*/
2037 
2045 int
2047 {
2048  /*here we define two lists to hold our calculated "z"-values and the order number in the geometry*/
2049 
2050  double k, thevalue;
2051  float deltaX, deltaY, c1m, c2m;
2052  POINT2D c1, c2;
2053  const POINT2D *theP;
2054  float min1X, max1X, max1Y, min1Y, min2X, max2X, max2Y, min2Y;
2055  int t;
2056  int n1 = l1->npoints;
2057  int n2 = l2->npoints;
2058 
2059  LISTSTRUCT *list1, *list2;
2060  list1 = (LISTSTRUCT *)lwalloc(sizeof(LISTSTRUCT) * n1);
2061  list2 = (LISTSTRUCT *)lwalloc(sizeof(LISTSTRUCT) * n2);
2062 
2063  LWDEBUG(2, "lw_dist2d_fast_ptarray_ptarray is called");
2064 
2065  max1X = box1->xmax;
2066  min1X = box1->xmin;
2067  max1Y = box1->ymax;
2068  min1Y = box1->ymin;
2069  max2X = box2->xmax;
2070  min2X = box2->xmin;
2071  max2Y = box2->ymax;
2072  min2Y = box2->ymin;
2073  /*we want the center of the bboxes, and calculate the slope between the centerpoints*/
2074  c1.x = min1X + (max1X - min1X) / 2;
2075  c1.y = min1Y + (max1Y - min1Y) / 2;
2076  c2.x = min2X + (max2X - min2X) / 2;
2077  c2.y = min2Y + (max2Y - min2Y) / 2;
2078 
2079  deltaX = (c2.x - c1.x);
2080  deltaY = (c2.y - c1.y);
2081 
2082  /*Here we calculate where the line perpendicular to the center-center line crosses the axes for each vertex
2083  if the center-center line is vertical the perpendicular line will be horizontal and we find it's crossing the
2084  Y-axes with z = y-kx */
2085  if ((deltaX * deltaX) < (deltaY * deltaY)) /*North or South*/
2086  {
2087  k = -deltaX / deltaY;
2088  for (t = 0; t < n1; t++) /*for each segment in L1 */
2089  {
2090  theP = getPoint2d_cp(l1, t);
2091  thevalue = theP->y - (k * theP->x);
2092  list1[t].themeasure = thevalue;
2093  list1[t].pnr = t;
2094  }
2095  for (t = 0; t < n2; t++) /*for each segment in L2*/
2096  {
2097  theP = getPoint2d_cp(l2, t);
2098  thevalue = theP->y - (k * theP->x);
2099  list2[t].themeasure = thevalue;
2100  list2[t].pnr = t;
2101  }
2102  c1m = c1.y - (k * c1.x);
2103  c2m = c2.y - (k * c2.x);
2104  }
2105 
2106  /*if the center-center line is horizontal the perpendicular line will be vertical. To eliminate problems with
2107  dividing by zero we are here mirroring the coordinate-system and we find it's crossing the X-axes with z =
2108  x-(1/k)y */
2109  else /*West or East*/
2110  {
2111  k = -deltaY / deltaX;
2112  for (t = 0; t < n1; t++) /*for each segment in L1 */
2113  {
2114  theP = getPoint2d_cp(l1, t);
2115  thevalue = theP->x - (k * theP->y);
2116  list1[t].themeasure = thevalue;
2117  list1[t].pnr = t;
2118  /* lwnotice("l1 %d, measure=%f",t,thevalue ); */
2119  }
2120  for (t = 0; t < n2; t++) /*for each segment in L2*/
2121  {
2122  theP = getPoint2d_cp(l2, t);
2123  thevalue = theP->x - (k * theP->y);
2124  list2[t].themeasure = thevalue;
2125  list2[t].pnr = t;
2126  /* lwnotice("l2 %d, measure=%f",t,thevalue ); */
2127  }
2128  c1m = c1.x - (k * c1.y);
2129  c2m = c2.x - (k * c2.y);
2130  }
2131 
2132  /*we sort our lists by the calculated values*/
2133  qsort(list1, n1, sizeof(LISTSTRUCT), struct_cmp_by_measure);
2134  qsort(list2, n2, sizeof(LISTSTRUCT), struct_cmp_by_measure);
2135 
2136  if (c1m < c2m)
2137  {
2138  if (!lw_dist2d_pre_seg_seg(l1, l2, list1, list2, k, dl))
2139  {
2140  lwfree(list1);
2141  lwfree(list2);
2142  return LW_FALSE;
2143  }
2144  }
2145  else
2146  {
2147  dl->twisted = ((dl->twisted) * (-1));
2148  if (!lw_dist2d_pre_seg_seg(l2, l1, list2, list1, k, dl))
2149  {
2150  lwfree(list1);
2151  lwfree(list2);
2152  return LW_FALSE;
2153  }
2154  }
2155  lwfree(list1);
2156  lwfree(list2);
2157  return LW_TRUE;
2158 }
2159 
2160 int
2161 struct_cmp_by_measure(const void *a, const void *b)
2162 {
2163  LISTSTRUCT *ia = (LISTSTRUCT *)a;
2164  LISTSTRUCT *ib = (LISTSTRUCT *)b;
2165  return (ia->themeasure > ib->themeasure) ? 1 : ((ia->themeasure < ib->themeasure) ? -1 : 0);
2166 }
2167 
2169 int
2171 {
2172  const POINT2D *p1, *p2, *p3, *p4, *p01, *p02;
2173  int pnr1, pnr2, pnr3, pnr4, n1, n2, i, u, r, twist;
2174  double maxmeasure;
2175  n1 = l1->npoints;
2176  n2 = l2->npoints;
2177 
2178  LWDEBUG(2, "lw_dist2d_pre_seg_seg is called");
2179 
2180  p1 = getPoint2d_cp(l1, list1[0].pnr);
2181  p3 = getPoint2d_cp(l2, list2[0].pnr);
2182  lw_dist2d_pt_pt(p1, p3, dl);
2183  maxmeasure = sqrt(dl->distance * dl->distance + (dl->distance * dl->distance * k * k));
2184  twist = dl->twisted; /*to keep the incoming order between iterations*/
2185  for (i = (n1 - 1); i >= 0; --i)
2186  {
2187  /*we break this iteration when we have checked every point closer to our perpendicular "checkline" than
2188  * our shortest found distance*/
2189  if (((list2[0].themeasure - list1[i].themeasure)) > maxmeasure)
2190  break;
2191  /*because we are not iterating in the original point order we have to check the segment before and after
2192  * every point*/
2193  for (r = -1; r <= 1; r += 2)
2194  {
2195  pnr1 = list1[i].pnr;
2196  p1 = getPoint2d_cp(l1, pnr1);
2197  if (pnr1 + r < 0)
2198  {
2199  p01 = getPoint2d_cp(l1, (n1 - 1));
2200  if ((p1->x == p01->x) && (p1->y == p01->y))
2201  pnr2 = (n1 - 1);
2202  else
2203  pnr2 = pnr1; /* if it is a line and the last and first point is not the same we
2204  avoid the edge between start and end this way*/
2205  }
2206 
2207  else if (pnr1 + r > (n1 - 1))
2208  {
2209  p01 = getPoint2d_cp(l1, 0);
2210  if ((p1->x == p01->x) && (p1->y == p01->y))
2211  pnr2 = 0;
2212  else
2213  pnr2 = pnr1; /* if it is a line and the last and first point is not the same we
2214  avoid the edge between start and end this way*/
2215  }
2216  else
2217  pnr2 = pnr1 + r;
2218 
2219  p2 = getPoint2d_cp(l1, pnr2);
2220  for (u = 0; u < n2; ++u)
2221  {
2222  if (((list2[u].themeasure - list1[i].themeasure)) >= maxmeasure)
2223  break;
2224  pnr3 = list2[u].pnr;
2225  p3 = getPoint2d_cp(l2, pnr3);
2226  if (pnr3 == 0)
2227  {
2228  p02 = getPoint2d_cp(l2, (n2 - 1));
2229  if ((p3->x == p02->x) && (p3->y == p02->y))
2230  pnr4 = (n2 - 1);
2231  else
2232  pnr4 = pnr3; /* if it is a line and the last and first point is not the
2233  same we avoid the edge between start and end this way*/
2234  }
2235  else
2236  pnr4 = pnr3 - 1;
2237 
2238  p4 = getPoint2d_cp(l2, pnr4);
2239  dl->twisted = twist;
2240  if (!lw_dist2d_selected_seg_seg(p1, p2, p3, p4, dl))
2241  return LW_FALSE;
2242 
2243  if (pnr3 >= (n2 - 1))
2244  {
2245  p02 = getPoint2d_cp(l2, 0);
2246  if ((p3->x == p02->x) && (p3->y == p02->y))
2247  pnr4 = 0;
2248  else
2249  pnr4 = pnr3; /* if it is a line and the last and first point is not the
2250  same we avoid the edge between start and end this way*/
2251  }
2252 
2253  else
2254  pnr4 = pnr3 + 1;
2255 
2256  p4 = getPoint2d_cp(l2, pnr4);
2257  dl->twisted = twist; /*we reset the "twist" for each iteration*/
2258  if (!lw_dist2d_selected_seg_seg(p1, p2, p3, p4, dl))
2259  return LW_FALSE;
2260  /*here we "translate" the found mindistance so it can be compared to our "z"-values*/
2261  maxmeasure = sqrt(dl->distance * dl->distance + (dl->distance * dl->distance * k * k));
2262  }
2263  }
2264  }
2265 
2266  return LW_TRUE;
2267 }
2268 
2274 int
2275 lw_dist2d_selected_seg_seg(const POINT2D *A, const POINT2D *B, const POINT2D *C, const POINT2D *D, DISTPTS *dl)
2276 {
2277  /*A and B are the same point */
2278  if ((A->x == B->x) && (A->y == B->y))
2279  {
2280  return lw_dist2d_pt_seg(A, C, D, dl);
2281  }
2282  /*U and V are the same point */
2283 
2284  if ((C->x == D->x) && (C->y == D->y))
2285  {
2286  dl->twisted *= -1;
2287  return lw_dist2d_pt_seg(D, A, B, dl);
2288  }
2289 
2290  if ((lw_dist2d_pt_seg(A, C, D, dl)) && (lw_dist2d_pt_seg(B, C, D, dl)))
2291  {
2292  /* change the order of inputted geometries and that we notice by changing sign on dl->twisted */
2293  dl->twisted *= -1;
2294  return ((lw_dist2d_pt_seg(C, A, B, dl)) && (lw_dist2d_pt_seg(D, A, B, dl)));
2295  }
2296  else
2297  return LW_FALSE; /* if any of the calls to lw_dist2d_pt_seg goes wrong we return false*/
2298 }
2299 
2300 /*------------------------------------------------------------------------------------------------------------
2301 End of New faster distance calculations
2302 --------------------------------------------------------------------------------------------------------------*/
2303 
2304 /*------------------------------------------------------------------------------------------------------------
2305 Functions in common for Brute force and new calculation
2306 --------------------------------------------------------------------------------------------------------------*/
2307 
2315 int
2316 lw_dist2d_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B, DISTPTS *dl)
2317 {
2318  double r;
2319 
2320  LWDEBUG(2, "lw_dist2d_pt_seg called");
2321 
2322  /*if start==end, then use pt distance */
2323  if ((A->x == B->x) && (A->y == B->y))
2324  {
2325  LWDEBUG(2, "lw_dist2d_pt_seg found first and last segment points being the same");
2326  return lw_dist2d_pt_pt(p, A, dl);
2327  }
2328 
2329 
2330  /*
2331  * otherwise, we use comp.graphics.algorithms
2332  * Frequently Asked Questions method
2333  *
2334  * (1) AC dot AB
2335  * r = ---------
2336  * ||AB||^2
2337  * r has the following meaning:
2338  * r=0 P = A
2339  * r=1 P = B
2340  * r<0 P is on the backward extension of AB
2341  * r>1 P is on the forward extension of AB
2342  * 0<r<1 P is interior to AB
2343  */
2344 
2345  r = ((p->x - A->x) * (B->x - A->x) + (p->y - A->y) * (B->y - A->y)) /
2346  ((B->x - A->x) * (B->x - A->x) + (B->y - A->y) * (B->y - A->y));
2347 
2348  LWDEBUGF(2, "lw_dist2d_pt_seg found r = %.15g", r);
2349 
2350  /*This is for finding the maxdistance.
2351  the maxdistance have to be between two vertexes, compared to mindistance which can be between two vertexes.*/
2352  if (dl->mode == DIST_MAX)
2353  {
2354  if (r >= 0.5)
2355  return lw_dist2d_pt_pt(p, A, dl);
2356  else /* (r < 0.5) */
2357  return lw_dist2d_pt_pt(p, B, dl);
2358  }
2359 
2360  if (r < 0) /*If p projected on the line is outside point A*/
2361  return lw_dist2d_pt_pt(p, A, dl);
2362  if (r >= 1) /*If p projected on the line is outside point B or on point B*/
2363  return lw_dist2d_pt_pt(p, B, dl);
2364 
2365  /*If the point p is on the segment this is a more robust way to find out that*/
2366  if ((((A->y - p->y) * (B->x - A->x) == (A->x - p->x) * (B->y - A->y))) && (dl->mode == DIST_MIN))
2367  {
2368  dl->distance = 0.0;
2369  dl->p1 = *p;
2370  dl->p2 = *p;
2371  }
2372 
2373 
2374  /*
2375  (2)
2376  (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
2377  s = -----------------------------
2378  L^2
2379 
2380  Then the distance from C to P = |s|*L.
2381  */
2382 
2383  double s = ((A->y - p->y) * (B->x - A->x) - (A->x - p->x) * (B->y - A->y)) /
2384  ((B->x - A->x) * (B->x - A->x) + (B->y - A->y) * (B->y - A->y));
2385 
2386  double dist = fabs(s) * sqrt(((B->x - A->x) * (B->x - A->x) + (B->y - A->y) * (B->y - A->y)));
2387  if ( dist < dl->distance )
2388  {
2389  dl->distance = dist;
2390  {
2391  POINT2D c;
2392  c.x = A->x + r * (B->x - A->x);
2393  c.y = A->y + r * (B->y - A->y);
2394  if (dl->twisted > 0)
2395  {
2396  dl->p1 = *p;
2397  dl->p2 = c;
2398  }
2399  else
2400  {
2401  dl->p1 = c;
2402  dl->p2 = *p;
2403  }
2404  }
2405  }
2406 
2407  return LW_TRUE;
2408 }
2409 
2412 int
2413 lw_dist2d_pt_pt(const POINT2D *thep1, const POINT2D *thep2, DISTPTS *dl)
2414 {
2415  double hside = thep2->x - thep1->x;
2416  double vside = thep2->y - thep1->y;
2417  double dist = sqrt(hside * hside + vside * vside);
2418 
2419  /*multiplication with mode to handle mindistance (mode=1) and maxdistance (mode = (-1)*/
2420  if (((dl->distance - dist) * (dl->mode)) > 0)
2421  {
2422  dl->distance = dist;
2423 
2424  /* To get the points in right order. twisted is updated between 1 and (-1) every time the order is
2425  * changed earlier in the chain*/
2426  if (dl->twisted > 0)
2427  {
2428  dl->p1 = *thep1;
2429  dl->p2 = *thep2;
2430  }
2431  else
2432  {
2433  dl->p1 = *thep2;
2434  dl->p2 = *thep1;
2435  }
2436  }
2437  return LW_TRUE;
2438 }
2439 
2440 /*------------------------------------------------------------------------------------------------------------
2441 End of Functions in common for Brute force and new calculation
2442 --------------------------------------------------------------------------------------------------------------*/
2443 
2444 inline double
2445 distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
2446 {
2447  double hside = p2->x - p1->x;
2448  double vside = p2->y - p1->y;
2449 
2450  return hypot(hside, vside);
2451 }
2452 
2453 /* return distance squared, useful to avoid sqrt calculations */
2454 double
2455 distance2d_sqr_pt_seg(const POINT2D *C, const POINT2D *A, const POINT2D *B)
2456 {
2457  /*if start==end, then use pt distance */
2458  if ((A->x == B->x) && (A->y == B->y))
2459  return distance2d_sqr_pt_pt(C, A);
2460 
2461  /*
2462  * otherwise, we use comp.graphics.algorithms
2463  * Frequently Asked Questions method
2464  *
2465  * (1) AC dot AB
2466  * r = ---------
2467  * ||AB||^2
2468  * r has the following meaning:
2469  * r=0 P = A
2470  * r=1 P = B
2471  * r<0 P is on the backward extension of AB
2472  * r>1 P is on the forward extension of AB
2473  * 0<r<1 P is interior to AB
2474  */
2475 
2476  double ba_x = (B->x - A->x);
2477  double ba_y = (B->y - A->y);
2478  double ab_length_sqr = (ba_x * ba_x + ba_y * ba_y);
2479  double ca_x = (C->x - A->x);
2480  double ca_y = (C->y - A->y);
2481  double dot_ac_ab = (ca_x * ba_x + ca_y * ba_y);
2482 
2483  if (dot_ac_ab <= 0)
2484  return distance2d_sqr_pt_pt(C, A);
2485  if (dot_ac_ab >= ab_length_sqr)
2486  return distance2d_sqr_pt_pt(C, B);
2487 
2488  /*
2489  * (2)
2490  * (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
2491  * s = -----------------------------
2492  * L^2
2493  *
2494  * Then the distance from C to P = |s|*L.
2495  *
2496  */
2497 
2498  double s_numerator = ca_x * ba_y - ca_y * ba_x;
2499 
2500  /* Distance = (s_num / ab) * (s_num / ab) * ab == s_num * s_num / ab) */
2501  return s_numerator * s_numerator / ab_length_sqr;
2502 }
2503 
2508 int
2509 azimuth_pt_pt(const POINT2D *A, const POINT2D *B, double *d)
2510 {
2511  if (A->x == B->x && A->y == B->y)
2512  return LW_FALSE;
2513  *d = fmod(2 * M_PI + M_PI / 2 - atan2(B->y - A->y, B->x - A->x), 2 * M_PI);
2514  return LW_TRUE;
2515 }
char * s
Definition: cu_in_wkt.c:23
char * r
Definition: cu_in_wkt.c:24
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
#define LW_FALSE
Definition: liblwgeom.h:109
#define COLLECTIONTYPE
Definition: liblwgeom.h:123
#define COMPOUNDTYPE
Definition: liblwgeom.h:125
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
Definition: lwpoint.c:163
LWLINE * lwline_from_ptarray(int32_t srid, uint32_t npoints, LWPOINT **points)
Definition: lwline.c:228
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
#define CURVEPOLYTYPE
Definition: liblwgeom.h:126
#define MULTILINETYPE
Definition: liblwgeom.h:121
LWCURVEPOLY * lwcurvepoly_construct_from_lwpoly(LWPOLY *lwpoly)
Construct an equivalent curve polygon from a polygon.
Definition: lwcurvepoly.c:52
#define MULTISURFACETYPE
Definition: liblwgeom.h:128
#define LINETYPE
Definition: liblwgeom.h:118
#define MULTIPOINTTYPE
Definition: liblwgeom.h:120
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:117
#define TINTYPE
Definition: liblwgeom.h:131
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:122
void lwfree(void *mem)
Definition: lwutil.c:242
#define POLYGONTYPE
Definition: liblwgeom.h:119
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:129
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:124
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition: lwgeom.c:755
#define MULTICURVETYPE
Definition: liblwgeom.h:127
#define TRIANGLETYPE
Definition: liblwgeom.h:130
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:233
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:108
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:695
#define LW_INSIDE
Constants for point-in-polygon return values.
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
#define FP_EQUALS(A, B)
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:740
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 lwgeom_contains_point(const LWGEOM *geom, const POINT2D *pt)
Definition: lwcompound.c:129
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
#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
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:101
static double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: lwinline.h:35
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:203
static double distance(double x1, double y1, double x2, double y2)
Definition: lwtree.c:1032
int lw_dist2d_circstring_curvepoly(LWCIRCSTRING *circ, LWCURVEPOLY *poly, DISTPTS *dl)
Definition: measures.c:1060
int struct_cmp_by_measure(const void *a, const void *b)
Definition: measures.c:2161
int lw_dist2d_line_curvepoly(LWLINE *line, LWCURVEPOLY *poly, DISTPTS *dl)
Definition: measures.c:779
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:2445
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures.c:55
double lwgeom_maxdistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing max distance calculation.
Definition: measures.c:168
int lw_dist2d_line_circstring(LWLINE *line1, LWCIRCSTRING *line2, DISTPTS *dl)
Definition: measures.c:727
int lw_dist2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2, DISTPTS *dl)
Function handling polygon to polygon calculation 1 if we are looking for maxdistance,...
Definition: measures.c:982
LWGEOM * lw_dist2d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
Function initializing shortestline and longestline calculations.
Definition: measures.c:84
int lw_dist2d_comp(const LWGEOM *lw1, const LWGEOM *lw2, DISTPTS *dl)
This function just deserializes geometries Bboxes is not checked here since it is the subgeometries b...
Definition: measures.c:239
int lw_dist2d_pt_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, DISTPTS *dl)
Definition: measures.c:1523
int lw_dist2d_pre_seg_seg(POINTARRAY *l1, POINTARRAY *l2, LISTSTRUCT *list1, LISTSTRUCT *list2, double k, DISTPTS *dl)
preparation before lw_dist2d_seg_seg.
Definition: measures.c:2170
int azimuth_pt_pt(const POINT2D *A, const POINT2D *B, double *d)
Compute the azimuth of segment AB in radians.
Definition: measures.c:2509
int lw_dist2d_point_curvepoly(LWPOINT *point, LWCURVEPOLY *poly, DISTPTS *dl)
Definition: measures.c:676
int lw_dist2d_point_circstring(LWPOINT *point, LWCIRCSTRING *circ, DISTPTS *dl)
Definition: measures.c:633
int lw_dist2d_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B, DISTPTS *dl)
lw_dist2d_comp from p to line A->B This one is now sending every occasion to lw_dist2d_pt_pt Before i...
Definition: measures.c:2316
int lw_dist2d_circstring_poly(LWCIRCSTRING *circ, LWPOLY *poly, DISTPTS *dl)
Definition: measures.c:1051
int lw_dist2d_tri_circstring(LWTRIANGLE *tri, LWCIRCSTRING *line, DISTPTS *dl)
Definition: measures.c:958
LWGEOM * lwgeom_furthest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures.c:61
int lw_dist2d_arc_arc_concentric(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, double radius_A, const POINT2D *B1, const POINT2D *B2, const POINT2D *B3, double radius_B, const POINT2D *CENTER, DISTPTS *dl)
Definition: measures.c:1780
int lw_dist2d_line_tri(LWLINE *line, LWTRIANGLE *tri, DISTPTS *dl)
Definition: measures.c:711
int lw_dist2d_pt_ptarray(const POINT2D *p, POINTARRAY *pa, DISTPTS *dl)
search all the segments of pointarray to see which one is closest to p1 Returns minimum distance betw...
Definition: measures.c:1134
int lw_dist2d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl)
This is a recursive function delivering every possible combination of subgeometries.
Definition: measures.c:271
int lw_dist2d_seg_seg(const POINT2D *A, const POINT2D *B, const POINT2D *C, const POINT2D *D, DISTPTS *dl)
Finds the shortest distance between two segments.
Definition: measures.c:1927
int lw_dist2d_curvepoly_curvepoly(LWCURVEPOLY *poly1, LWCURVEPOLY *poly2, DISTPTS *dl)
Definition: measures.c:1072
int lw_dist2d_poly_curvepoly(LWPOLY *poly1, LWCURVEPOLY *curvepoly2, DISTPTS *dl)
Definition: measures.c:1042
int lw_dist2d_seg_arc(const POINT2D *A1, const POINT2D *A2, const POINT2D *B1, const POINT2D *B2, const POINT2D *B3, DISTPTS *dl)
Calculate the shortest distance between an arc and an edge.
Definition: measures.c:1373
int lw_dist2d_point_line(LWPOINT *point, LWLINE *line, DISTPTS *dl)
point to line calculation
Definition: measures.c:610
int lw_dist2d_tri_curvepoly(LWTRIANGLE *tri, LWCURVEPOLY *poly, DISTPTS *dl)
Definition: measures.c:912
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition: measures.c:210
void lw_dist2d_distpts_init(DISTPTS *dl, int mode)
Definition: measures.c:67
int lw_dist2d_fast_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2, DISTPTS *dl, GBOX *box1, GBOX *box2)
The new faster calculation comparing pointarray to another pointarray the arrays can come from both p...
Definition: measures.c:2046
static int lw_dist2d_is_collection(const LWGEOM *g)
Definition: measures.c:245
int lw_dist2d_arc_arc(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *B1, const POINT2D *B2, const POINT2D *B3, DISTPTS *dl)
Definition: measures.c:1586
int lw_dist2d_line_line(LWLINE *line1, LWLINE *line2, DISTPTS *dl)
Definition: measures.c:703
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures.c:43
static const POINT2D * lw_curvering_getfirstpoint2d_cp(LWGEOM *geom)
Definition: measures.c:891
int lw_dist2d_tri_tri(LWTRIANGLE *tri1, LWTRIANGLE *tri2, DISTPTS *dl)
Definition: measures.c:813
int lw_dist2d_point_tri(LWPOINT *point, LWTRIANGLE *tri, DISTPTS *dl)
Definition: measures.c:617
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition: measures.c:200
int lw_dist2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2, DISTPTS *dl)
test each segment of l1 against each segment of l2.
Definition: measures.c:1219
int lw_dist2d_ptarray_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl)
Test each segment of pa against each arc of pb for distance.
Definition: measures.c:1268
int lw_dist2d_selected_seg_seg(const POINT2D *A, const POINT2D *B, const POINT2D *C, const POINT2D *D, DISTPTS *dl)
This is the same function as lw_dist2d_seg_seg but without any calculations to determine intersection...
Definition: measures.c:2275
int lw_dist2d_line_poly(LWLINE *line, LWPOLY *poly, DISTPTS *dl)
line to polygon calculation Brute force.
Definition: measures.c:744
int lw_dist2d_distribute_bruteforce(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl)
Definition: measures.c:361
int lw_dist2d_ptarrayarc_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl)
Test each arc of pa against each arc of pb for distance.
Definition: measures.c:1322
LWGEOM * lwgeom_furthest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures.c:49
double lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling max distance calculations and dfullywithin calculations.
Definition: measures.c:180
LWGEOM * lw_dist2d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
Function initializing closestpoint calculations.
Definition: measures.c:131
double distance2d_sqr_pt_seg(const POINT2D *C, const POINT2D *A, const POINT2D *B)
Definition: measures.c:2455
int lw_dist2d_distribute_fast(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl)
Geometries are distributed for the new faster distance-calculations.
Definition: measures.c:543
int lw_dist2d_pt_pt(const POINT2D *thep1, const POINT2D *thep2, DISTPTS *dl)
Compares incoming points and stores the points closest to each other or most far away from each other...
Definition: measures.c:2413
int lw_dist2d_circstring_circstring(LWCIRCSTRING *line1, LWCIRCSTRING *line2, DISTPTS *dl)
Definition: measures.c:1066
int lw_dist2d_pt_ptarrayarc(const POINT2D *p, const POINTARRAY *pa, DISTPTS *dl)
Search all the arcs of pointarray to see which one is closest to p1 Returns minimum distance between ...
Definition: measures.c:1170
int lw_dist2d_point_poly(LWPOINT *point, LWPOLY *poly, DISTPTS *dl)
Definition: measures.c:646
int lw_dist2d_tri_poly(LWTRIANGLE *tri, LWPOLY *poly, DISTPTS *dl)
Definition: measures.c:839
int lw_dist2d_point_point(LWPOINT *point1, LWPOINT *point2, DISTPTS *dl)
point to point calculation
Definition: measures.c:600
int lw_dist2d_check_overlap(LWGEOM *lwg1, LWGEOM *lwg2)
Definition: measures.c:522
#define DIST_MIN
Definition: measures.h:44
#define DIST_MAX
Definition: measures.h:43
POINT2D p1
Definition: measures.h:52
POINT2D p2
Definition: measures.h:53
int twisted
Definition: measures.h:55
double tolerance
Definition: measures.h:56
int mode
Definition: measures.h:54
double distance
Definition: measures.h:51
Structure used in distance-calculations.
Definition: measures.h:50
double ymax
Definition: liblwgeom.h:372
double xmax
Definition: liblwgeom.h:370
double ymin
Definition: liblwgeom.h:371
double xmin
Definition: liblwgeom.h:369
int pnr
Definition: measures.h:62
double themeasure
Definition: measures.h:61
POINTARRAY * points
Definition: liblwgeom.h:522
uint32_t ngeoms
Definition: liblwgeom.h:595
LWGEOM ** geoms
Definition: liblwgeom.h:590
LWGEOM ** geoms
Definition: liblwgeom.h:604
LWGEOM ** rings
Definition: liblwgeom.h:618
uint32_t nrings
Definition: liblwgeom.h:623
uint8_t type
Definition: liblwgeom.h:477
GBOX * bbox
Definition: liblwgeom.h:473
int32_t srid
Definition: liblwgeom.h:475
POINTARRAY * points
Definition: liblwgeom.h:498
POINTARRAY * point
Definition: liblwgeom.h:486
POINTARRAY ** rings
Definition: liblwgeom.h:534
uint32_t nrings
Definition: liblwgeom.h:539
POINTARRAY * points
Definition: liblwgeom.h:510
double y
Definition: liblwgeom.h:405
double x
Definition: liblwgeom.h:405
uint32_t npoints
Definition: liblwgeom.h:442