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