PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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/*------------------------------------------------------------------------------------------------------------
35Initializing functions
36The functions starting the distance-calculation processses
37--------------------------------------------------------------------------------------------------------------*/
38
39LWGEOM *
40lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
41{
42 return lw_dist2d_distanceline(lw1, lw2, lw1->srid, DIST_MIN);
43}
44
45LWGEOM *
46lwgeom_furthest_line(const LWGEOM *lw1, const LWGEOM *lw2)
47{
48 return lw_dist2d_distanceline(lw1, lw2, lw1->srid, DIST_MAX);
49}
50
51LWGEOM *
52lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
53{
54 return lw_dist2d_distancepoint(lw1, lw2, lw1->srid, DIST_MIN);
55}
56
57LWGEOM *
58lwgeom_furthest_point(const LWGEOM *lw1, const LWGEOM *lw2)
59{
60 return lw_dist2d_distancepoint(lw1, lw2, lw1->srid, DIST_MAX);
61}
62
63void
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
80LWGEOM *
81lw_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
127LWGEOM *
128lw_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
164double
165lwgeom_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
176double
177lwgeom_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
196double
197lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
198{
199 return lwgeom_mindistance2d_tolerance(lw1, lw2, 0.0);
200}
201
206double
207lwgeom_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/*------------------------------------------------------------------------------------------------------------
222End of Initializing functions
223--------------------------------------------------------------------------------------------------------------*/
224
225/*------------------------------------------------------------------------------------------------------------
226Preprocessing functions
227Functions preparing geometries for distance-calculations
228--------------------------------------------------------------------------------------------------------------*/
229
235int
236lw_dist2d_comp(const LWGEOM *lw1, const LWGEOM *lw2, DISTPTS *dl)
237{
238 return lw_dist2d_recursive(lw1, lw2, dl);
239}
240
241static 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
264
265/* Check for overlapping bboxes */
266static int
267lw_dist2d_check_overlap(const LWGEOM *lwg1, const LWGEOM *lwg2)
268{
269 assert(lwg1 && lwg2 && lwg1->bbox && lwg2->bbox);
270
271 /* Check if the geometries intersect. */
272 if ((lwg1->bbox->xmax < lwg2->bbox->xmin || lwg1->bbox->xmin > lwg2->bbox->xmax ||
273 lwg1->bbox->ymax < lwg2->bbox->ymin || lwg1->bbox->ymin > lwg2->bbox->ymax))
274 {
275 return LW_FALSE;
276 }
277 return LW_TRUE;
278}
279
283int
284lw_dist2d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl)
285{
286 int i, j;
287 int n1 = 1;
288 int n2 = 1;
289 LWGEOM *g1 = NULL;
290 LWGEOM *g2 = NULL;
291 LWCOLLECTION *c1 = NULL;
292 LWCOLLECTION *c2 = NULL;
293
294 LWDEBUGF(2, "lw_dist2d_comp is called with type1=%d, type2=%d", lwg1->type, lwg2->type);
295
296 if (lw_dist2d_is_collection(lwg1))
297 {
298 LWDEBUG(3, "First geometry is collection");
299 c1 = lwgeom_as_lwcollection(lwg1);
300 n1 = c1->ngeoms;
301 }
302 if (lw_dist2d_is_collection(lwg2))
303 {
304 LWDEBUG(3, "Second geometry is collection");
305 c2 = lwgeom_as_lwcollection(lwg2);
306 n2 = c2->ngeoms;
307 }
308
309 for (i = 0; i < n1; i++)
310 {
311
312 if (lw_dist2d_is_collection(lwg1))
313 g1 = c1->geoms[i];
314 else
315 g1 = (LWGEOM *)lwg1;
316
317 if (!g1) continue;
318
319 if (lwgeom_is_empty(g1))
320 continue;
321
323 {
324 LWDEBUG(3, "Found collection inside first geometry collection, recursing");
325 if (!lw_dist2d_recursive(g1, lwg2, dl))
326 return LW_FALSE;
327 continue;
328 }
329 for (j = 0; j < n2; j++)
330 {
331 if (lw_dist2d_is_collection(lwg2))
332 g2 = c2->geoms[j];
333 else
334 g2 = (LWGEOM *)lwg2;
335
336 if (!g2) continue;
337
339 {
340 LWDEBUG(3, "Found collection inside second geometry collection, recursing");
341 if (!lw_dist2d_recursive(g1, g2, dl))
342 return LW_FALSE;
343 continue;
344 }
345
346 if (!g1->bbox)
347 lwgeom_add_bbox(g1);
348
349 if (!g2->bbox)
350 lwgeom_add_bbox(g2);
351
352 /* If one of geometries is empty, skip */
353 if (lwgeom_is_empty(g1) || lwgeom_is_empty(g2))
354 continue;
355
356 if ((dl->mode != DIST_MAX) && (!lw_dist2d_check_overlap(g1, g2)) &&
357 (g1->type == LINETYPE || g1->type == POLYGONTYPE || g1->type == TRIANGLETYPE) &&
358 (g2->type == LINETYPE || g2->type == POLYGONTYPE || g2->type == TRIANGLETYPE))
359 {
360 if (!lw_dist2d_distribute_fast(g1, g2, dl))
361 return LW_FALSE;
362 }
363 else
364 {
365 if (!lw_dist2d_distribute_bruteforce(g1, g2, dl))
366 return LW_FALSE;
367 if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
368 return LW_TRUE; /*just a check if the answer is already given*/
369 }
370 }
371 }
372 return LW_TRUE;
373}
374
375int
377{
378
379 int t1 = lwg1->type;
380 int t2 = lwg2->type;
381
382 switch (t1)
383 {
384 case POINTTYPE:
385 {
386 dl->twisted = 1;
387 switch (t2)
388 {
389 case POINTTYPE:
390 return lw_dist2d_point_point((LWPOINT *)lwg1, (LWPOINT *)lwg2, dl);
391 case LINETYPE:
392 return lw_dist2d_point_line((LWPOINT *)lwg1, (LWLINE *)lwg2, dl);
393 case TRIANGLETYPE:
394 return lw_dist2d_point_tri((LWPOINT *)lwg1, (LWTRIANGLE *)lwg2, dl);
395 case POLYGONTYPE:
396 return lw_dist2d_point_poly((LWPOINT *)lwg1, (LWPOLY *)lwg2, dl);
397 case CIRCSTRINGTYPE:
398 return lw_dist2d_point_circstring((LWPOINT *)lwg1, (LWCIRCSTRING *)lwg2, dl);
399 case CURVEPOLYTYPE:
400 return lw_dist2d_point_curvepoly((LWPOINT *)lwg1, (LWCURVEPOLY *)lwg2, dl);
401 default:
402 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
403 return LW_FALSE;
404 }
405 }
406 case LINETYPE:
407 {
408 dl->twisted = 1;
409 switch (t2)
410 {
411 case POINTTYPE:
412 dl->twisted = -1;
413 return lw_dist2d_point_line((LWPOINT *)lwg2, (LWLINE *)lwg1, dl);
414 case LINETYPE:
415 return lw_dist2d_line_line((LWLINE *)lwg1, (LWLINE *)lwg2, dl);
416 case TRIANGLETYPE:
417 return lw_dist2d_line_tri((LWLINE *)lwg1, (LWTRIANGLE *)lwg2, dl);
418 case POLYGONTYPE:
419 return lw_dist2d_line_poly((LWLINE *)lwg1, (LWPOLY *)lwg2, dl);
420 case CIRCSTRINGTYPE:
421 return lw_dist2d_line_circstring((LWLINE *)lwg1, (LWCIRCSTRING *)lwg2, dl);
422 case CURVEPOLYTYPE:
423 return lw_dist2d_line_curvepoly((LWLINE *)lwg1, (LWCURVEPOLY *)lwg2, dl);
424 default:
425 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
426 return LW_FALSE;
427 }
428 }
429 case TRIANGLETYPE:
430 {
431 dl->twisted = 1;
432 switch (t2)
433 {
434 case POINTTYPE:
435 dl->twisted = -1;
436 return lw_dist2d_point_tri((LWPOINT *)lwg2, (LWTRIANGLE *)lwg1, dl);
437 case LINETYPE:
438 dl->twisted = -1;
439 return lw_dist2d_line_tri((LWLINE *)lwg2, (LWTRIANGLE *)lwg1, dl);
440 case TRIANGLETYPE:
441 return lw_dist2d_tri_tri((LWTRIANGLE *)lwg1, (LWTRIANGLE *)lwg2, dl);
442 case POLYGONTYPE:
443 return lw_dist2d_tri_poly((LWTRIANGLE *)lwg1, (LWPOLY *)lwg2, dl);
444 case CIRCSTRINGTYPE:
445 return lw_dist2d_tri_circstring((LWTRIANGLE *)lwg1, (LWCIRCSTRING *)lwg2, dl);
446 case CURVEPOLYTYPE:
447 return lw_dist2d_tri_curvepoly((LWTRIANGLE *)lwg1, (LWCURVEPOLY *)lwg2, dl);
448 default:
449 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
450 return LW_FALSE;
451 }
452 }
453 case CIRCSTRINGTYPE:
454 {
455 dl->twisted = 1;
456 switch (t2)
457 {
458 case POINTTYPE:
459 dl->twisted = -1;
460 return lw_dist2d_point_circstring((LWPOINT *)lwg2, (LWCIRCSTRING *)lwg1, dl);
461 case LINETYPE:
462 dl->twisted = -1;
463 return lw_dist2d_line_circstring((LWLINE *)lwg2, (LWCIRCSTRING *)lwg1, dl);
464 case TRIANGLETYPE:
465 dl->twisted = -1;
466 return lw_dist2d_tri_circstring((LWTRIANGLE *)lwg2, (LWCIRCSTRING *)lwg1, dl);
467 case POLYGONTYPE:
468 return lw_dist2d_circstring_poly((LWCIRCSTRING *)lwg1, (LWPOLY *)lwg2, dl);
469 case CIRCSTRINGTYPE:
470 return lw_dist2d_circstring_circstring((LWCIRCSTRING *)lwg1, (LWCIRCSTRING *)lwg2, dl);
471 case CURVEPOLYTYPE:
472 return lw_dist2d_circstring_curvepoly((LWCIRCSTRING *)lwg1, (LWCURVEPOLY *)lwg2, dl);
473 default:
474 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
475 return LW_FALSE;
476 }
477 }
478 case POLYGONTYPE:
479 {
480 dl->twisted = -1;
481 switch (t2)
482 {
483 case POINTTYPE:
484 return lw_dist2d_point_poly((LWPOINT *)lwg2, (LWPOLY *)lwg1, dl);
485 case LINETYPE:
486 return lw_dist2d_line_poly((LWLINE *)lwg2, (LWPOLY *)lwg1, dl);
487 case TRIANGLETYPE:
488 return lw_dist2d_tri_poly((LWTRIANGLE *)lwg2, (LWPOLY *)lwg1, dl);
489 case CIRCSTRINGTYPE:
490 return lw_dist2d_circstring_poly((LWCIRCSTRING *)lwg2, (LWPOLY *)lwg1, dl);
491 case POLYGONTYPE:
492 dl->twisted = 1;
493 return lw_dist2d_poly_poly((LWPOLY *)lwg1, (LWPOLY *)lwg2, dl);
494 case CURVEPOLYTYPE:
495 dl->twisted = 1;
496 return lw_dist2d_poly_curvepoly((LWPOLY *)lwg1, (LWCURVEPOLY *)lwg2, dl);
497 default:
498 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
499 return LW_FALSE;
500 }
501 }
502 case CURVEPOLYTYPE:
503 {
504 dl->twisted = -1;
505 switch (t2)
506 {
507 case POINTTYPE:
508 return lw_dist2d_point_curvepoly((LWPOINT *)lwg2, (LWCURVEPOLY *)lwg1, dl);
509 case LINETYPE:
510 return lw_dist2d_line_curvepoly((LWLINE *)lwg2, (LWCURVEPOLY *)lwg1, dl);
511 case TRIANGLETYPE:
512 return lw_dist2d_tri_curvepoly((LWTRIANGLE *)lwg2, (LWCURVEPOLY *)lwg1, dl);
513 case POLYGONTYPE:
514 return lw_dist2d_poly_curvepoly((LWPOLY *)lwg2, (LWCURVEPOLY *)lwg1, dl);
515 case CIRCSTRINGTYPE:
516 return lw_dist2d_circstring_curvepoly((LWCIRCSTRING *)lwg2, (LWCURVEPOLY *)lwg1, dl);
517 case CURVEPOLYTYPE:
518 dl->twisted = 1;
519 return lw_dist2d_curvepoly_curvepoly((LWCURVEPOLY *)lwg1, (LWCURVEPOLY *)lwg2, dl);
520 default:
521 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
522 return LW_FALSE;
523 }
524 }
525 default:
526 {
527 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t1));
528 return LW_FALSE;
529 }
530 }
531
532 return LW_FALSE;
533}
534
535
537int
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/*------------------------------------------------------------------------------------------------------------
581End of Preprocessing functions
582--------------------------------------------------------------------------------------------------------------*/
583
584/*------------------------------------------------------------------------------------------------------------
585Brute force functions
586The old way of calculating distances, now used for:
5871) distances to points (because there shouldn't be anything to gain by the new way of doing it)
5882) distances when subgeometries geometries bboxes overlaps
589--------------------------------------------------------------------------------------------------------------*/
590
594int
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}
604int
606{
607 const POINT2D *p = getPoint2d_cp(point->point, 0);
608 return lw_dist2d_pt_ptarray(p, line->points, dl);
609}
610
611int
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
627int
629{
630 const POINT2D *p;
631 p = getPoint2d_cp(point->point, 0);
632 return lw_dist2d_pt_ptarrayarc(p, circ->points, dl);
633}
634
640int
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
670int
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
697int
699{
700 POINTARRAY *pa1 = line1->points;
701 POINTARRAY *pa2 = line2->points;
702 return lw_dist2d_ptarray_ptarray(pa1, pa2, dl);
703}
704
705int
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
721int
723{
724 return lw_dist2d_ptarray_ptarrayarc(line1->points, line2->points, dl);
725}
726
738int
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
773int
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
807int
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
833int
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}
885static 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
906int
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
952int
954{
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
976int
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
1036int
1038{
1040 int rv = lw_dist2d_curvepoly_curvepoly(curvepoly1, curvepoly2, dl);
1041 lwgeom_free((LWGEOM *)curvepoly1);
1042 return rv;
1043}
1044
1045int
1047{
1049 int rv = lw_dist2d_line_curvepoly((LWLINE *)circ, curvepoly, dl);
1050 lwgeom_free((LWGEOM *)curvepoly);
1051 return rv;
1052}
1053
1054int
1056{
1057 return lw_dist2d_line_curvepoly((LWLINE *)circ, poly, dl);
1058}
1059
1060int
1065
1066int
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
1128int
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
1158int
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
1207int
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
1256int
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
1310int
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
1361int
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
1511int
1512lw_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
1574int
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
1768int
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
1915int
1916lw_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/*------------------------------------------------------------------------------------------------------------
2020End of Brute force functions
2021--------------------------------------------------------------------------------------------------------------*/
2022
2023/*------------------------------------------------------------------------------------------------------------
2024New faster distance calculations
2025--------------------------------------------------------------------------------------------------------------*/
2026
2034int
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
2149int
2150struct_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
2158int
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
2263int
2264lw_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/*------------------------------------------------------------------------------------------------------------
2290End of New faster distance calculations
2291--------------------------------------------------------------------------------------------------------------*/
2292
2293/*------------------------------------------------------------------------------------------------------------
2294Functions in common for Brute force and new calculation
2295--------------------------------------------------------------------------------------------------------------*/
2296
2304int
2305lw_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
2364int
2365lw_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/*------------------------------------------------------------------------------------------------------------
2393End of Functions in common for Brute force and new calculation
2394--------------------------------------------------------------------------------------------------------------*/
2395
2396inline double
2397distance2d_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 */
2406double
2407distance2d_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
2460int
2461azimuth_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
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
#define LW_FALSE
Definition liblwgeom.h:108
#define COLLECTIONTYPE
Definition liblwgeom.h:122
#define COMPOUNDTYPE
Definition liblwgeom.h:124
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1138
#define CURVEPOLYTYPE
Definition liblwgeom.h:125
#define MULTILINETYPE
Definition liblwgeom.h:120
#define MULTISURFACETYPE
Definition liblwgeom.h:127
#define LINETYPE
Definition liblwgeom.h:117
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition lwgeom.c:215
LWCURVEPOLY * lwcurvepoly_construct_from_lwpoly(LWPOLY *lwpoly)
Construct an equivalent curve polygon from a polygon.
Definition lwcurvepoly.c:52
#define MULTIPOINTTYPE
Definition liblwgeom.h:119
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
void * lwalloc(size_t size)
Definition lwutil.c:227
#define TINTYPE
Definition liblwgeom.h:130
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:121
void lwfree(void *mem)
Definition lwutil.c:242
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
Definition lwpoint.c:163
#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)
#define MULTICURVETYPE
Definition liblwgeom.h:126
#define TRIANGLETYPE
Definition liblwgeom.h:129
#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
LWLINE * lwline_from_ptarray(int32_t srid, uint32_t npoints, LWPOINT **points)
Definition lwline.c:228
#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.
#define FP_EQUALS(A, B)
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return 1 if the point is inside the POINTARRAY, -1 if it is outside, and 0 if it is on the boundary.
Definition ptarray.c:740
int lw_pt_in_seg(const POINT2D *P, const POINT2D *A1, const POINT2D *A2)
Returns true if P is between A1/A2.
Definition lwalgorithm.c:96
#define LW_OUTSIDE
int lwgeom_contains_point(const LWGEOM *geom, const POINT2D *pt)
Definition lwcompound.c:129
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition lwalgorithm.c:65
int lw_arc_is_pt(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if arc A is actually a point (all vertices are the same) .
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 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
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
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
double lwgeom_maxdistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing max distance calculation.
Definition measures.c:165
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:52
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
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
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:40
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
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
static int lw_dist2d_check_overlap(const LWGEOM *lwg1, const LWGEOM *lwg2)
Definition measures.c:267
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:284
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_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
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:376
static const POINT2D * lw_curvering_getfirstpoint2d_cp(LWGEOM *geom)
Definition measures.c:886
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
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
LWGEOM * lwgeom_furthest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:46
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
LWGEOM * lwgeom_furthest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:58
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
#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
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