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