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