root/spike/nicklas/distcalc/liblwgeom/measures.c

Revision 4884, 42.9 KB (checked in by nicklas, 3 years ago)

blindly copy and paste error corrected

  • Property svn:keywords set to Author Date Id Revision
Line 
1
2/**********************************************************************
3 * $Id$
4 *
5 * PostGIS - Spatial Types for PostgreSQL
6 * http://postgis.refractions.net
7 * Copyright 2001-2006 Refractions Research Inc.
8 *
9 * This is free software; you can redistribute and/or modify it under
10 * the terms of the GNU General Public Licence. See the COPYING file.
11 *
12 **********************************************************************/
13
14#include <math.h>
15#include <string.h>
16#include <stdlib.h>
17
18#include "measures.h"
19
20
21/*------------------------------------------------------------------------------------------------------------
22Initializing functions
23The functions starting the distance-calculation processses
24--------------------------------------------------------------------------------------------------------------*/
25
26/**
27Function initializing shortestline and longestline calculations.
28*/
29LWGEOM *
30lw_dist2d_distanceline(uchar *lw1, uchar *lw2,int srid,int mode)
31{
32        LWDEBUG(2, "lw_dist2d_distanceline is called");
33        double x1,x2,y1,y2;
34        LWPOINT *point1, *point2;
35        double initdistance = ( mode == DIST2D_MIN ? MAXFLOAT : -1.0);
36        DISTPTS thedl;
37        thedl.mode = mode;
38        thedl.distance = initdistance;
39        thedl.tolerance = 0.0;
40
41        LWPOINT *lwpoints[2];
42        LWGEOM *result;
43
44        if (!lw_dist2d_comp( lw1,lw2,&thedl))
45        {
46        /*should never get here. all cases ought to be error handled earlier*/
47                lwerror("Some unspecified error.");
48                result =(LWGEOM *)lwcollection_construct_empty(srid, 0, 0);
49        }
50
51        /*if thedl.distance is unchanged there where only empty geometries input*/
52        if (thedl.distance == initdistance)
53        {
54                LWDEBUG(3, "didn't find geometries to measure between, returning null");
55                result =(LWGEOM *)lwcollection_construct_empty(srid, 0, 0);
56        }
57        else
58        {
59                x1=thedl.p1.x;
60                y1=thedl.p1.y;
61                x2=thedl.p2.x;
62                y2=thedl.p2.y;
63
64                point1 = make_lwpoint2d(srid, x1, y1);
65                point2 = make_lwpoint2d(srid, x2, y2);
66
67                lwpoints[0] = make_lwpoint2d(srid, x1, y1);
68                lwpoints[1] = make_lwpoint2d(srid, x2, y2);
69
70                result = (LWGEOM *)lwline_from_lwpointarray(srid, 2, lwpoints);
71        }
72        return result;
73}
74
75/**
76Function initializing closestpoint calculations.
77*/
78LWGEOM *
79lw_dist2d_distancepoint(uchar *lw1, uchar *lw2,int srid,int mode)
80{
81        LWDEBUG(2, "lw_dist2d_distancepoint is called");
82        double x,y;
83        DISTPTS thedl;
84        double initdistance = MAXFLOAT;
85
86        thedl.mode = mode;
87        thedl.distance= initdistance;
88        thedl.tolerance = 0;
89
90        LWGEOM *result;
91
92        if (!lw_dist2d_comp( lw1,lw2,&thedl))
93        {
94        /*should never get here. all cases ought to be error handled earlier*/
95        lwerror("Some unspecified error.");
96        result =(LWGEOM *)lwcollection_construct_empty(srid, 0, 0);
97        }
98        if (thedl.distance == initdistance)
99        {
100                LWDEBUG(3, "didn't find geometries to measure between, returning null");
101                result =(LWGEOM *)lwcollection_construct_empty(srid, 0, 0);
102        }
103        else
104        {
105                x=thedl.p1.x;
106                y=thedl.p1.y;
107                result = (LWGEOM *)make_lwpoint2d(srid, x, y);
108        }
109        return result;
110}
111
112
113/**
114Function initialazing max distance calculation
115*/
116double
117lwgeom_maxdistance2d(uchar *lw1, uchar *lw2)
118{
119        LWDEBUG(2, "lwgeom_maxdistance2d is called");
120
121        return lwgeom_maxdistance2d_tolerance( lw1, lw2, 0.0 );
122}
123
124/**
125Function handling max distance calculations and dfyllywithin calculations.
126The difference is just the tolerance.
127*/
128double
129lwgeom_maxdistance2d_tolerance(uchar *lw1, uchar *lw2, double tolerance)
130{
131        LWDEBUG(2, "lwgeom_maxdistance2d_tolerance is called");
132        /*double thedist;*/
133        DISTPTS thedl;
134        thedl.mode = DIST2D_MAX;
135        thedl.distance= -1;
136        thedl.tolerance = tolerance;
137        if (lw_dist2d_comp( lw1,lw2,&thedl))
138        {
139                return thedl.distance;
140        }
141        /*should never get here. all cases ought to be error handled earlier*/
142        lwerror("Some unspecified error.");
143        return -1;
144}
145
146/**
147        Function initialazing min distance calculation
148*/
149double
150lwgeom_mindistance2d(uchar *lw1, uchar *lw2)
151{
152        LWDEBUG(2, "lwgeom_mindistance2d is called");
153        return lwgeom_mindistance2d_tolerance( lw1, lw2, 0.0 );
154}
155
156/**
157        Function handling min distance calculations and dwithin calculations.
158        The difference is just the tolerance.
159*/
160double
161lwgeom_mindistance2d_tolerance(uchar *lw1, uchar *lw2, double tolerance)
162{
163        LWDEBUG(2, "lwgeom_mindistance2d_tolerance is called");
164        DISTPTS thedl;
165        thedl.mode = DIST2D_MIN;
166        thedl.distance= MAXFLOAT;
167        thedl.tolerance = tolerance;
168        if (lw_dist2d_comp( lw1,lw2,&thedl))
169        {
170                return thedl.distance;
171        }
172        /*should never get here. all cases ought to be error handled earlier*/
173        lwerror("Some unspecified error.");
174        return MAXFLOAT;
175}
176
177
178/*------------------------------------------------------------------------------------------------------------
179End of Initializing functions
180--------------------------------------------------------------------------------------------------------------*/
181
182/*------------------------------------------------------------------------------------------------------------
183Preprocessing functions
184Functions preparing geometries for distance-calculations
185--------------------------------------------------------------------------------------------------------------*/
186
187/**
188        This function just deserializes geometries
189        Bboxes is not checked here since it is the subgeometries
190        bboxes we will use anyway.
191*/
192int
193lw_dist2d_comp(uchar *lw1, uchar *lw2, DISTPTS *dl)
194{
195        LWDEBUG(2, "lw_dist2d_comp is called");
196
197        LWGEOM *lwg1 = lwgeom_deserialize(lw1);
198        LWGEOM *lwg2 = lwgeom_deserialize(lw2);
199
200        return lw_dist2d_recursive      ((LWCOLLECTION*) lwg1,(LWCOLLECTION*) lwg2, dl);
201}
202
203/**
204This is a recursive function delivering every possible combinatin of subgeometries
205*/
206int lw_dist2d_recursive(const LWCOLLECTION * lwg1,const LWCOLLECTION * lwg2,DISTPTS *dl)
207{
208        LWDEBUGF(2, "lw_dist2d_comp is called with type1=%d, type2=%d", TYPE_GETTYPE(lwg1->type), TYPE_GETTYPE(lwg2->type));
209        /*If empty gemetry, return. True here only means continue searching. False would have stoped the process
210        if (lwgeom_is_empty(lwg1)||lwgeom_is_empty(lwg2)) return LW_TRUE;               moved down*/
211
212        int i, j;
213        int n1=1;
214        int n2=1;;
215        LWGEOM *g1, *g2;
216
217        if (lwgeom_is_collection(TYPE_GETTYPE(lwg1->type)))
218        {
219                LWDEBUG(3, "First geometry is collection");
220                n1=lwg1->ngeoms;
221        }
222        if (lwgeom_is_collection(TYPE_GETTYPE(lwg2->type)))
223        {
224                LWDEBUG(3, "Second geometry is collection");
225                n2=lwg2->ngeoms;
226        }
227
228        for ( i = 0; i < n1; i++ )
229        {
230
231                if (lwgeom_is_collection(TYPE_GETTYPE(lwg1->type)))
232                {
233                        g1=lwg1->geoms[i];
234                }
235                else
236                {
237                        g1=(LWGEOM*)lwg1;
238                }
239
240                if (lwgeom_is_empty(g1)) return LW_TRUE;
241
242                if (lwgeom_is_collection(TYPE_GETTYPE(g1->type)))
243                {
244                        LWDEBUG(3, "Found collection inside first geometry collection, recursing");
245                        if (!lw_dist2d_recursive((LWCOLLECTION*)g1, (LWCOLLECTION*)lwg2, dl)) return LW_FALSE;
246                        continue;
247                }
248                for ( j = 0; j < n2; j++ )
249                {
250                        if (lwgeom_is_collection(TYPE_GETTYPE(lwg2->type)))
251                        {
252                                g2=lwg2->geoms[j];
253                        }
254                        else
255                        {
256                                g2=(LWGEOM*)lwg2;
257                        }
258                        if (lwgeom_is_collection(TYPE_GETTYPE(g2->type)))
259                        {
260                                LWDEBUG(3, "Found collection inside second geometry collection, recursing");
261                                if (!lw_dist2d_recursive((LWCOLLECTION*) g1, (LWCOLLECTION*)g2, dl)) return LW_FALSE;
262                                continue;
263                        }
264
265                        if ( ! g1->bbox )
266                        {
267                                g1->bbox = lwgeom_compute_box2d(g1);
268                        }
269                        if ( ! g2->bbox )
270                        {
271                                g2->bbox = lwgeom_compute_box2d(g2);
272                        }
273                        /*If one of geometries is empty, return. True here only means continue searching. False would have stoped the process*/
274                        if (lwgeom_is_empty(g1)||lwgeom_is_empty(g2)) return LW_TRUE;
275
276                        if ((dl->mode==DIST2D_MAX)||(TYPE_GETTYPE(g1->type)==POINTTYPE) ||(TYPE_GETTYPE(g2->type)==POINTTYPE)||lw_dist2d_check_overlap(g1, g2))
277                        {
278                                if (!lw_dist2d_distribute_bruteforce(g1, g2, dl)) return LW_FALSE;
279                                if (dl->distance<=dl->tolerance && dl->mode == DIST2D_MIN) return LW_TRUE; /*just a check if  the answer is already given*/
280                        }
281                        else
282                        {
283                                if (!lw_dist2d_distribute_fast(g1, g2, dl)) return LW_FALSE;
284                        }
285                }
286        }
287        return LW_TRUE;
288}
289
290
291
292/**
293
294This function distributes the "old-type" brut-force tasks depending on type
295*/
296int
297lw_dist2d_distribute_bruteforce(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl)
298{
299        LWDEBUGF(2, "lw_dist2d_distribute_bruteforce is called with typ1=%d, type2=%d", TYPE_GETTYPE(lwg1->type), TYPE_GETTYPE(lwg2->type));
300
301        int     t1 = TYPE_GETTYPE(lwg1->type);
302        int     t2 = TYPE_GETTYPE(lwg2->type);
303
304
305        if  ( t1 == POINTTYPE )
306        {
307                if  ( t2 == POINTTYPE )
308                {
309                        dl->twisted=1;
310                        return lw_dist2d_point_point((LWPOINT *)lwg1, (LWPOINT *)lwg2, dl);
311                }
312                else if  ( t2 == LINETYPE )
313                {
314                        dl->twisted=1;
315                        return lw_dist2d_point_line((LWPOINT *)lwg1, (LWLINE *)lwg2, dl);
316                }
317                else if  ( t2 == POLYGONTYPE )
318                {
319                        dl->twisted=1;
320                        return lw_dist2d_point_poly((LWPOINT *)lwg1, (LWPOLY *)lwg2,dl);
321                }
322                else
323                {
324                        lwerror("Unsupported geometry type: %s", lwgeom_typename(t2));
325                        return LW_FALSE;
326                }
327        }
328        else if ( t1 == LINETYPE )
329        {
330                if ( t2 == POINTTYPE )
331                {
332                        dl->twisted=(-1);
333                        return lw_dist2d_point_line((LWPOINT *)lwg2,(LWLINE *)lwg1,dl);
334                }
335                else if ( t2 == LINETYPE )
336                {
337                        dl->twisted=1;
338                        /*lwnotice("start line");*/
339                        return lw_dist2d_line_line((LWLINE *)lwg1,(LWLINE *)lwg2,dl);
340                }
341                else if ( t2 == POLYGONTYPE )
342                {
343                        dl->twisted=1;
344                        return lw_dist2d_line_poly((LWLINE *)lwg1,(LWPOLY *)lwg2,dl);
345                }
346                else
347                {
348                        lwerror("Unsupported geometry type: %s", lwgeom_typename(t2));
349                        return LW_FALSE;
350                }
351        }
352        else if ( t1 == POLYGONTYPE )
353        {
354                if ( t2 == POLYGONTYPE )
355                {
356                        dl->twisted=(1);
357                        return lw_dist2d_poly_poly((LWPOLY *)lwg1,(LWPOLY *)lwg2,dl);
358                }
359                else if ( t2 == POINTTYPE )
360                {
361                        dl->twisted=(-1);
362                        return lw_dist2d_point_poly((LWPOINT *)lwg2,  (LWPOLY *)lwg1, dl);
363                }
364                else if ( t2 == LINETYPE )
365                {
366                        dl->twisted=(-1);
367                        return lw_dist2d_line_poly((LWLINE *)lwg2,(LWPOLY *)lwg1,dl);
368                }
369                else
370                {
371                        lwerror("Unsupported geometry type: %s", lwgeom_typename(t2));
372                        return LW_FALSE;
373                }
374        }
375        else
376        {
377                lwerror("Unsupported geometry type: %s", lwgeom_typename(t1));
378                return LW_FALSE;
379        }
380        /*You shouldn't being able to get here*/
381        lwerror("unspecified error in function lw_dist2d_distribute_bruteforce");
382        return LW_FALSE;
383}
384
385/**
386
387We have to check for overlapping bboxes
388*/
389int
390lw_dist2d_check_overlap(LWGEOM *lwg1,LWGEOM *lwg2)
391{
392        LWDEBUG(2, "lw_dist2d_check_overlap is called");
393        if ( ! lwg1->bbox )
394                lwg1->bbox = lwgeom_compute_box2d(lwg1);
395        if ( ! lwg2->bbox )
396                lwg2->bbox = lwgeom_compute_box2d(lwg2);
397
398        /*Check if the geometries intersect.
399        */
400        if ((lwg1->bbox->xmax<lwg2->bbox->xmin||lwg1->bbox->xmin>lwg2->bbox->xmax||lwg1->bbox->ymax<lwg2->bbox->ymin||lwg1->bbox->ymin>lwg2->bbox->ymax))
401        {
402                LWDEBUG(3, "geometries bboxes did not overlap");
403                return LW_FALSE;
404        }
405        LWDEBUG(3, "geometries bboxes overlap");
406        return LW_TRUE;
407}
408
409/**
410
411Here the geometries are distributed for the new faster distance-calculations
412*/
413int
414lw_dist2d_distribute_fast(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl)
415{
416        LWDEBUGF(2, "lw_dist2d_distribute_fast is called with typ1=%d, type2=%d", TYPE_GETTYPE(lwg1->type), TYPE_GETTYPE(lwg2->type));
417
418        POINTARRAY *pa1, *pa2;
419        int     type1 = TYPE_GETTYPE(lwg1->type);
420        int     type2 = TYPE_GETTYPE(lwg2->type);
421
422        switch (type1)
423        {
424        case LINETYPE:
425                pa1 = ((LWLINE *)lwg1)->points;
426                break;
427        case POLYGONTYPE:
428                pa1 = ((LWPOLY *)lwg1)->rings[0];
429                break;
430        default:
431                lwerror("Unsupported geometry1 type: %s", lwgeom_typename(type1));
432                return LW_FALSE;
433        }
434        switch (type2)
435        {
436        case LINETYPE:
437                pa2 = ((LWLINE *)lwg2)->points;
438                break;
439        case POLYGONTYPE:
440                pa2 = ((LWPOLY *)lwg2)->rings[0];
441                break;
442        default:
443                lwerror("Unsupported geometry2 type: %s", lwgeom_typename(type1));
444                return LW_FALSE;
445        }
446        dl->twisted=1;
447        return lw_dist2d_fast_ptarray_ptarray(pa1, pa2, dl, lwg1->bbox, lwg2->bbox);
448}
449
450/*------------------------------------------------------------------------------------------------------------
451End of Preprocessing functions
452--------------------------------------------------------------------------------------------------------------*/
453
454
455/*------------------------------------------------------------------------------------------------------------
456Brute force functions
457The old way of calculating distances, now used for:
4581)      distances to points (because there shouldn't be anything to gain by the new way of doing it)
4592)      distances when subgeometries geometries bboxes overlaps
460--------------------------------------------------------------------------------------------------------------*/
461
462/**
463
464point to point calculation
465*/
466int
467lw_dist2d_point_point(LWPOINT *point1, LWPOINT *point2, DISTPTS *dl)
468{
469        POINT2D p1;
470        POINT2D p2;
471
472        getPoint2d_p(point1->point, 0, &p1);
473        getPoint2d_p(point2->point, 0, &p2);
474
475        return lw_dist2d_pt_pt(&p1, &p2,dl);
476}
477/**
478
479point to line calculation
480*/
481int
482lw_dist2d_point_line(LWPOINT *point, LWLINE *line, DISTPTS *dl)
483{
484        LWDEBUG(2, "lw_dist2d_point_line is called");
485        POINT2D p;
486        POINTARRAY *pa = line->points;
487        getPoint2d_p(point->point, 0, &p);
488        return lw_dist2d_pt_ptarray(&p, pa, dl);
489}
490/**
491 * 1. see if pt in outer boundary. if no, then treat the outer ring like a line
492 * 2. if in the boundary, test to see if its in a hole.
493 *    if so, then return dist to hole, else return 0 (point in polygon)
494 */
495int
496lw_dist2d_point_poly(LWPOINT *point, LWPOLY *poly, DISTPTS *dl)
497{
498        LWDEBUG(2, "lw_dist2d_point_poly called");
499
500        POINT2D p;
501        int i;
502
503        getPoint2d_p(point->point, 0, &p);
504
505
506
507
508        if (dl->mode == DIST2D_MAX)
509        {
510                LWDEBUG(3, "looking for maxdistance");
511                return lw_dist2d_pt_ptarray(&p, poly->rings[0], dl);
512        }
513        /* Return distance to outer ring if not inside it */
514        if ( ! pt_in_ring_2d(&p, poly->rings[0]) )
515        {
516                LWDEBUG(3, "first point not inside outer-ring");
517                return lw_dist2d_pt_ptarray(&p, poly->rings[0], dl);
518        }
519
520        /*
521         * Inside the outer ring.
522         * Scan though each of the inner rings looking to
523         * see if its inside.  If not, distance==0.
524         * Otherwise, distance = pt to ring distance
525         */
526        for (i=1; i<poly->nrings; i++)
527        {
528                /* Inside a hole. Distance = pt -> ring */
529                if ( pt_in_ring_2d(&p, poly->rings[i]) )
530                {
531                        LWDEBUG(3, " inside an hole");
532                        return lw_dist2d_pt_ptarray(&p, poly->rings[i], dl);
533                }
534        }
535
536        LWDEBUG(3, " inside the polygon");
537        if (dl->mode == DIST2D_MIN)
538        {
539                dl->distance=0.0;
540                dl->p1.x=p.x;
541                dl->p1.y=p.y;
542                dl->p2.x=p.x;
543                dl->p2.y=p.y;
544        }
545        return LW_TRUE; /* Is inside the polygon */
546}
547/**
548
549line to line calculation
550*/
551int
552lw_dist2d_line_line(LWLINE *line1, LWLINE *line2, DISTPTS *dl)
553{
554        LWDEBUG(2, "lw_dist2d_line_line is called");
555        POINTARRAY *pa1 = line1->points;
556        POINTARRAY *pa2 = line2->points;
557        return lw_dist2d_ptarray_ptarray(pa1, pa2, dl);
558}
559/**
560
561line to polygon calculation
562*/
563int
564lw_dist2d_line_poly(LWLINE *line, LWPOLY *poly, DISTPTS *dl)
565{
566        LWDEBUG(2, "lw_dist2d_line_poly is called");
567        return lw_dist2d_ptarray_poly(line->points, poly, dl);
568}
569
570/**
571
572Function handling polygon to polygon calculation
5731       if we are looking for maxdistance, just check the outer rings.
5742       check if poly1 has first point outside poly2 and vice versa, if so, just check outer rings
5753       check if first point of poly2 is in a hole of poly1. If so check outer ring of poly2 against that hole of poly1
5764       check if first point of poly1 is in a hole of poly2. If so check outer ring of poly1 against that hole of poly2
5775       If we have come all the way here we know that the first point of one of them is inside the other ones outer ring and not in holes so we check wich one is inside.
578 */
579int
580lw_dist2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2, DISTPTS *dl)
581{
582
583        LWDEBUG(2, "lw_dist2d_poly_poly called");
584
585        POINT2D pt;
586        int i;
587
588
589        /*1     if we are looking for maxdistance, just check the outer rings.*/
590        if (dl->mode == DIST2D_MAX)
591        {
592                return lw_dist2d_ptarray_ptarray(poly1->rings[0],       poly2->rings[0],dl);
593        }
594
595
596        /* 2    check if poly1 has first point outside poly2 and vice versa, if so, just check outer rings
597        here it would be possible to handle the information about wich one is inside wich one and only search for the smaller ones in the bigger ones holes.*/
598        getPoint2d_p(poly1->rings[0], 0, &pt);
599        if ( !pt_in_ring_2d(&pt, poly2->rings[0]))
600        {
601                getPoint2d_p(poly2->rings[0], 0, &pt);
602                if (!pt_in_ring_2d(&pt, poly1->rings[0]))
603                {
604                        return lw_dist2d_ptarray_ptarray(poly1->rings[0],       poly2->rings[0],dl);
605                }
606        }
607
608        /*3     check if first point of poly2 is in a hole of poly1. If so check outer ring of poly2 against that hole of poly1*/
609        getPoint2d_p(poly2->rings[0], 0, &pt);
610        for (i=1; i<poly1->nrings; i++)
611        {
612                /* Inside a hole */
613                if ( pt_in_ring_2d(&pt, poly1->rings[i]) )
614                {
615                        return lw_dist2d_ptarray_ptarray(poly1->rings[i],       poly2->rings[0],dl);
616                }
617        }
618
619        /*4     check if first point of poly1 is in a hole of poly2. If so check outer ring of poly1 against that hole of poly2*/
620        getPoint2d_p(poly1->rings[0], 0, &pt);
621        for (i=1; i<poly2->nrings; i++)
622        {
623                /* Inside a hole */
624                if ( pt_in_ring_2d(&pt, poly2->rings[i]) )
625                {
626                        return lw_dist2d_ptarray_ptarray(poly1->rings[0],       poly2->rings[i],dl);
627                }
628        }
629
630
631        /*5     If we have come all the way here we know that the first point of one of them is inside the other ones outer ring and not in holes so we check wich one is inside.*/
632        getPoint2d_p(poly1->rings[0], 0, &pt);
633        if ( pt_in_ring_2d(&pt, poly2->rings[0]))
634        {
635                dl->distance=0.0;
636                dl->p1.x=pt.x;
637                dl->p1.y=pt.y;
638                dl->p2.x=pt.x;
639                dl->p2.y=pt.y;
640                return LW_TRUE;
641        }
642
643        getPoint2d_p(poly2->rings[0], 0, &pt);
644        if (pt_in_ring_2d(&pt, poly1->rings[0]))
645        {
646                dl->distance=0.0;
647                dl->p1.x=pt.x;
648                dl->p1.y=pt.y;
649                dl->p2.x=pt.x;
650                dl->p2.y=pt.y;
651                return LW_TRUE;
652        }
653
654
655        lwerror("Unspecified error in function lw_dist2d_poly_poly");
656        return LW_FALSE;
657}
658
659/**
660
661 * search all the segments of pointarray to see which one is closest to p1
662 * Returns minimum distance between point and pointarray
663 */
664int
665lw_dist2d_pt_ptarray(POINT2D *p, POINTARRAY *pa,DISTPTS *dl)
666{
667        LWDEBUG(2, "lw_dist2d_pt_ptarray is called");
668
669        int t;
670        POINT2D start, end;
671        int twist = dl->twisted;
672        getPoint2d_p(pa, 0, &start);
673
674        for (t=1; t<pa->npoints; t++)
675        {
676                dl->twisted=twist;
677                getPoint2d_p(pa, t, &end);
678                if (!lw_dist2d_pt_seg(p, &start, &end,dl)) return LW_FALSE;
679
680                if (dl->distance<=dl->tolerance && dl->mode == DIST2D_MIN) return LW_TRUE; /*just a check if  the answer is already given*/
681                start = end;
682        }
683
684        return LW_TRUE;
685}
686
687/**
688 * Brute force.
689 * Test line-ring distance against each ring.
690 * If there's an intersection (distance==0) then return 0 (crosses boundary).
691 * Otherwise, test to see if any point is inside outer rings of polygon,
692 * but not in inner rings.
693 * If so, return 0  (line inside polygon),
694 * otherwise return min distance to a ring (could be outside
695 * polygon or inside a hole)
696 */
697
698int
699lw_dist2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly, DISTPTS *dl)
700{
701        LWDEBUGF(2, "lw_dist2d_ptarray_poly called (%d rings)", poly->nrings);
702
703        POINT2D pt;
704        int i;
705
706
707
708        getPoint2d_p(pa, 0, &pt);
709        if ( !pt_in_ring_2d(&pt, poly->rings[0]))
710        {
711                return lw_dist2d_ptarray_ptarray(pa,poly->rings[0],dl);
712        }
713
714        for (i=1; i<poly->nrings; i++)
715        {
716                if (!lw_dist2d_ptarray_ptarray(pa, poly->rings[i], dl)) return LW_FALSE;
717
718                LWDEBUGF(3, " distance from ring %d: %f, mindist: %f",
719                         i, dist, mindist);
720                if (dl->distance<=dl->tolerance && dl->mode == DIST2D_MIN) return LW_TRUE; /*just a check if  the answer is already given*/
721        }
722
723        /*
724         * No intersection, have to check if a point is
725         * inside polygon
726         */
727        getPoint2d_p(pa, 0, &pt);
728
729        /*
730         * Outside outer ring, so min distance to a ring
731         * is the actual min distance
732
733        if ( ! pt_in_ring_2d(&pt, poly->rings[0]) )
734        {
735                return ;
736        } */
737
738        /*
739         * Its in the outer ring.
740         * Have to check if its inside a hole
741         */
742        for (i=1; i<poly->nrings; i++)
743        {
744                if ( pt_in_ring_2d(&pt, poly->rings[i]) )
745                {
746                        /*
747                         * Its inside a hole, then the actual
748                         * distance is the min ring distance
749                         */
750                        return LW_TRUE;
751                }
752        }
753        if (dl->mode == DIST2D_MIN)
754        {
755                dl->distance=0.0;
756                dl->p1.x=pt.x;
757                dl->p1.y=pt.y;
758                dl->p2.x=pt.x;
759                dl->p2.y=pt.y;
760        }
761        return LW_TRUE; /* Not in hole, so inside polygon */
762}
763
764
765
766/**
767
768test each segment of l1 against each segment of l2.
769*/
770int
771lw_dist2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2,DISTPTS *dl)
772{
773        LWDEBUG(2, "lw_dist2d_ptarray_ptarray is called");
774
775        int t,u;
776        POINT2D start, end;
777        POINT2D start2, end2;
778        int twist = dl->twisted;
779        LWDEBUGF(2, "lw_dist2d_ptarray_ptarray called (points: %d-%d)",l1->npoints, l2->npoints);
780        if (dl->mode == DIST2D_MAX)/*If we are searching for maxdistance we go straight to point-point calculation since the maxdistance have to be between two vertexes*/
781        {
782                for (t=0; t<l1->npoints; t++) /*for each segment in L1 */
783                {
784                        getPoint2d_p(l1, t, &start);
785                        for (u=0; u<l2->npoints; u++) /*for each segment in L2 */
786                        {
787                                getPoint2d_p(l2, u, &start2);
788                                lw_dist2d_pt_pt(&start,&start2,dl);
789                                LWDEBUGF(4, "maxdist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dist);
790                                LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f",
791                                         t, u, dl->distance, result);
792                        }
793                }
794        }
795        else
796        {
797                getPoint2d_p(l1, 0, &start);
798                for (t=1; t<l1->npoints; t++) /*for each segment in L1 */
799                {
800                        getPoint2d_p(l1, t, &end);
801                        getPoint2d_p(l2, 0, &start2);
802                        for (u=1; u<l2->npoints; u++) /*for each segment in L2 */
803                        {
804                                getPoint2d_p(l2, u, &end2);
805                                dl->twisted=twist;
806                                lw_dist2d_seg_seg(&start, &end, &start2, &end2,dl);
807                                LWDEBUGF(4, "mindist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dist);
808                                LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f",
809                                         t, u, dl->distance, result);
810                                if (dl->distance<=dl->tolerance && dl->mode == DIST2D_MIN) return LW_TRUE; /*just a check if  the answer is already given*/
811                                start2 = end2;
812                        }
813                        start = end;
814                }
815        }
816        return LW_TRUE;
817}
818
819/**
820
821Finds the shortest distance between two segments.
822This function is changed so it is not doing any comparasion of distance
823but just sending every possible combination further to lw_dist2d_pt_seg
824*/
825int
826lw_dist2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D, DISTPTS *dl)
827{
828        LWDEBUGF(2, "lw_dist2d_seg_seg [%g,%g]->[%g,%g] by [%g,%g]->[%g,%g]",
829                 A->x,A->y,B->x,B->y, C->x,C->y, D->x, D->y);
830
831        double  s_top, s_bot,s;
832        double  r_top, r_bot,r;
833
834
835
836
837        /*A and B are the same point */
838        if (  ( A->x == B->x) && (A->y == B->y) )
839        {
840                return lw_dist2d_pt_seg(A,C,D,dl);
841        }
842        /*U and V are the same point */
843
844        if (  ( C->x == D->x) && (C->y == D->y) )
845        {
846                dl->twisted= ((dl->twisted) * (-1));
847                return lw_dist2d_pt_seg(D,A,B,dl);
848        }
849        /* AB and CD are line segments */
850        /* from comp.graphics.algo
851
852        Solving the above for r and s yields
853                                (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
854                   r = ----------------------------- (eqn 1)
855                                (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
856
857                        (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
858                s = ----------------------------- (eqn 2)
859                        (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
860        Let P be the position vector of the intersection point, then
861                P=A+r(B-A) or
862                Px=Ax+r(Bx-Ax)
863                Py=Ay+r(By-Ay)
864        By examining the values of r & s, you can also determine some other limiting conditions:
865                If 0<=r<=1 & 0<=s<=1, intersection exists
866                r<0 or r>1 or s<0 or s>1 line segments do not intersect
867                If the denominator in eqn 1 is zero, AB & CD are parallel
868                If the numerator in eqn 1 is also zero, AB & CD are collinear.
869
870        */
871        r_top = (A->y-C->y)*(D->x-C->x) - (A->x-C->x)*(D->y-C->y) ;
872        r_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x) ;
873
874        s_top = (A->y-C->y)*(B->x-A->x) - (A->x-C->x)*(B->y-A->y);
875        s_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x);
876
877        if  ( (r_bot==0) || (s_bot == 0) )
878        {
879                if ((lw_dist2d_pt_seg(A,C,D,dl)) && (lw_dist2d_pt_seg(B,C,D,dl)))
880                {
881                        dl->twisted= ((dl->twisted) * (-1));  /*here we change the order of inputted geometrys and that we  notice by changing sign on dl->twisted*/
882                        return ((lw_dist2d_pt_seg(C,A,B,dl)) && (lw_dist2d_pt_seg(D,A,B,dl))); /*if all is successful we return true*/
883                }
884                else
885                {
886                        return LW_FALSE; /* if any of the calls to lw_dist2d_pt_seg goes wrong we return false*/
887                }
888        }
889
890        s = s_top/s_bot;
891        r=  r_top/r_bot;
892
893        if (((r<0) || (r>1) || (s<0) || (s>1)) || (dl->mode == DIST2D_MAX))
894        {
895                if ((lw_dist2d_pt_seg(A,C,D,dl)) && (lw_dist2d_pt_seg(B,C,D,dl)))
896                {
897                        dl->twisted= ((dl->twisted) * (-1));  /*here we change the order of inputted geometrys and that we  notice by changing sign on dl->twisted*/
898                        return ((lw_dist2d_pt_seg(C,A,B,dl)) && (lw_dist2d_pt_seg(D,A,B,dl))); /*if all is successful we return true*/
899                }
900                else
901                {
902                        return LW_FALSE; /* if any of the calls to lw_dist2d_pt_seg goes wrong we return false*/
903                }
904        }
905        else
906        {
907                if (dl->mode == DIST2D_MIN)     /*If there is intersection we identify the intersection point and return it but only if we are looking for mindistance*/
908                {
909                        POINT2D theP;
910
911                        if (((A->x==C->x)&&(A->y==C->y))||((A->x==D->x)&&(A->y==D->y)))
912                        {
913                                theP.x = A->x;
914                                theP.y = A->y;
915                        }
916                        else if (((B->x==C->x)&&(B->y==C->y))||((B->x==D->x)&&(B->y==D->y)))
917                        {
918                                theP.x = B->x;
919                                theP.y = B->y;
920                        }
921                        else
922                        {
923                                theP.x = A->x+r*(B->x-A->x);
924                                theP.y = A->y+r*(B->y-A->y);
925                        }
926                        dl->distance=0.0;
927                        dl->p1=theP;
928                        dl->p2=theP;
929                }
930                return LW_TRUE;
931
932        }
933        lwerror("unspecified error in function lw_dist2d_seg_seg");
934        return LW_FALSE; /*If we have come here something is wrong*/
935}
936
937
938/*------------------------------------------------------------------------------------------------------------
939End of Brute force functions
940--------------------------------------------------------------------------------------------------------------*/
941
942
943/*------------------------------------------------------------------------------------------------------------
944New faster distance calculations
945--------------------------------------------------------------------------------------------------------------*/
946
947/**
948
949The new faster calculation comparing pointarray to another pointarray
950the arrays can come from both polygons and linestrings.
951The naming is not good but comes from that it compares a
952chosen selection of the points not all of them
953*/
954int
955lw_dist2d_fast_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2,DISTPTS *dl, BOX2DFLOAT4 *box1, BOX2DFLOAT4 *box2)
956{
957        LWDEBUG(2, "lw_dist2d_fast_ptarray_ptarray is called");
958        /*here we define two lists to hold our calculated "z"-values and the order number in the geometry*/
959
960        double k, thevalue;
961        float   deltaX, deltaY, c1m, c2m;
962        POINT2D theP,c1, c2;
963        float min1X, max1X, max1Y, min1Y,min2X, max2X, max2Y, min2Y;
964        int t,  n1, n2;
965        n1 = l1->npoints;
966        n2 = l2->npoints;
967
968        LISTSTRUCT list1[n1];
969        LISTSTRUCT list2[n2];
970
971        max1X = box1->xmax;
972        min1X = box1->xmin;
973        max1Y = box1->ymax;
974        min1Y = box1->ymin;
975        max2X = box2->xmax;
976        min2X = box2->xmin;
977        max2Y = box2->ymax;
978        min2Y = box2->ymin;
979        /*we want the center of the bboxes, and calculate the slope between the centerpoints*/
980        c1.x = min1X + (max1X-min1X)/2;
981        c1.y = min1Y + (max1Y-min1Y)/2;
982        c2.x = min2X + (max2X-min2X)/2;
983        c2.y = min2Y + (max2Y-min2Y)/2;
984
985        deltaX=(c2.x-c1.x);
986        deltaY=(c2.y-c1.y);
987
988
989        /*Here we calculate where the line perpendicular to the center-center line crosses the axes for each vertex
990        if the center-center line is vertical the perpendicular line will be horizontal and we find it's crossing the Y-axes with z = y-kx */
991        if ((deltaX*deltaX)<(deltaY*deltaY))        /*North or South*/
992        {
993                k = -deltaX/deltaY;
994                for (t=0; t<n1; t++) /*for each segment in L1 */
995                {
996                        getPoint2d_p(l1, t, &theP);
997                        thevalue = theP.y-(k*theP.x);
998                        list1[t].themeasure=thevalue;
999                        list1[t].pnr=t;
1000
1001                }
1002                for (t=0; t<n2; t++) /*for each segment in L2*/
1003                {
1004                        getPoint2d_p(l2, t, &theP);
1005                        thevalue = theP.y-(k*theP.x);
1006                        list2[t].themeasure=thevalue;
1007                        list2[t].pnr=t;
1008
1009                }
1010                c1m = c1.y-(k*c1.x);
1011                c2m = c2.y-(k*c2.x);
1012        }
1013
1014
1015        /*if the center-center line is horizontal the perpendicular line will be vertical. To eliminate problems with deviding by zero we are here mirroring the coordinate-system
1016         and we find it's crossing the X-axes with z = x-(1/k)y */
1017        else        /*West or East*/
1018        {
1019                k = -deltaY/deltaX;
1020                for (t=0; t<n1; t++) /*for each segment in L1 */
1021                {
1022                        getPoint2d_p(l1, t, &theP);
1023                        thevalue = theP.x-(k*theP.y);
1024                        list1[t].themeasure=thevalue;
1025                        list1[t].pnr=t;
1026                        /*lwnotice("1pnr=%d, pnr=%d, themeasure=%f, themeasure=%f",t,list1[t].pnr,thevalue,list1[t].themeasure  );*/
1027                }
1028                for (t=0; t<n2; t++) /*for each segment in L2*/
1029                {
1030                        getPoint2d_p(l2, t, &theP);
1031
1032                        thevalue = theP.x-(k*theP.y);
1033                        list2[t].themeasure=thevalue;
1034                        list2[t].pnr=t;
1035                }
1036                c1m = c1.x-(k*c1.y);
1037                c2m = c2.x-(k*c2.y);
1038        }
1039
1040        /*we sort our lists by the calculated values*/
1041        qsort(list1, n1, sizeof(LISTSTRUCT), struct_cmp_by_measure);
1042        qsort(list2, n2, sizeof(LISTSTRUCT), struct_cmp_by_measure);
1043
1044        if (c1m < c2m)
1045        {
1046                if (!lw_dist2d_pre_seg_seg(l1,l2,list1,list2,k,dl)) return LW_FALSE;
1047        }
1048        else
1049        {
1050                dl->twisted= ((dl->twisted) * (-1));
1051                if (!lw_dist2d_pre_seg_seg(l2,l1,list2,list1,k,dl)) return LW_FALSE;
1052        }
1053        return LW_TRUE;
1054}
1055
1056int
1057struct_cmp_by_measure(const void *a, const void *b)
1058{
1059        LISTSTRUCT *ia = (LISTSTRUCT*)a;
1060        LISTSTRUCT *ib = (LISTSTRUCT*)b;
1061        return ( ia->themeasure>ib->themeasure ) ? 1 : -1;
1062}
1063
1064/**
1065        preparation before lw_dist2d_seg_seg.
1066*/
1067int
1068lw_dist2d_pre_seg_seg(POINTARRAY *l1, POINTARRAY *l2,LISTSTRUCT *list1, LISTSTRUCT *list2,double k, DISTPTS *dl)
1069{
1070        LWDEBUG(2, "lw_dist2d_pre_seg_seg is called");
1071
1072
1073        POINT2D p1, p2, p3, p4, p01, p02;
1074        int pnr1,pnr2,pnr3,pnr4, n1, n2, i, u, r, twist;
1075
1076        double maxmeasure;
1077        n1=     l1->npoints;
1078        n2 = l2->npoints;
1079
1080
1081        getPoint2d_p(l1, list1[0].pnr, &p1);
1082        getPoint2d_p(l2, list2[0].pnr, &p3);
1083        lw_dist2d_pt_pt(&p1, &p3,dl);
1084        maxmeasure = sqrt(dl->distance*dl->distance + (dl->distance*dl->distance*k*k));
1085        twist = dl->twisted; /*to keep the incomming order between iterations*/
1086        for (i =(n1-1); i>=0; --i)
1087        {
1088                /*we break this iteration when we have checked every
1089                point closer to our perpendicular "checkline" than
1090                our shortest found distance*/
1091                if (((list2[0].themeasure-list1[i].themeasure)) > maxmeasure) break;
1092                for (r=-1; r<=1; r +=2) /*because we are not iterating in the original pointorder we have to check the segment before and after every point*/
1093                {
1094                        pnr1 = list1[i].pnr;
1095                        getPoint2d_p(l1, pnr1, &p1);
1096                        if (pnr1+r<0)
1097                        {
1098                                getPoint2d_p(l1, (n1-1), &p01);
1099                                if (( p1.x == p01.x) && (p1.y == p01.y)) pnr2 = (n1-1);
1100                                else pnr2 = pnr1; /* if it is a line and the last and first point is not the same we avoid the edge between start and end this way*/
1101                        }
1102
1103                        else if (pnr1+r>(n1-1))
1104                        {
1105                                getPoint2d_p(l1, 0, &p01);
1106                                if (( p1.x == p01.x) && (p1.y == p01.y)) pnr2 = 0;
1107                                else pnr2 = pnr1; /* if it is a line and the last and first point is not the same we avoid the edge between start and end this way*/
1108                        }
1109                        else pnr2 = pnr1+r;
1110
1111
1112                        getPoint2d_p(l1, pnr2, &p2);
1113                        for (u=0; u<n2; ++u)
1114                        {
1115                                if (((list2[u].themeasure-list1[i].themeasure)) >= maxmeasure) break;
1116                                pnr3 = list2[u].pnr;
1117                                getPoint2d_p(l2, pnr3, &p3);
1118                                if (pnr3==0)
1119                                {
1120                                        getPoint2d_p(l2, (n2-1), &p02);
1121                                        if (( p3.x == p02.x) && (p3.y == p02.y)) pnr4 = (n2-1);
1122                                        else pnr4 = pnr3; /* if it is a line and the last and first point is not the same we avoid the edge between start and end this way*/
1123                                }
1124                                else pnr4 = pnr3-1;
1125
1126                                getPoint2d_p(l2, pnr4, &p4);
1127                                dl->twisted=twist;
1128                                if (!lw_dist2d_selected_seg_seg(&p1, &p2, &p3, &p4, dl)) return LW_FALSE;
1129
1130                                if (pnr3>=(n2-1))
1131                                {
1132                                        getPoint2d_p(l2, 0, &p02);
1133                                        if (( p3.x == p02.x) && (p3.y == p02.y)) pnr4 = 0;
1134                                        else pnr4 = pnr3; /* if it is a line and the last and first point is not the same we avoid the edge between start and end this way*/
1135                                }
1136
1137                                else pnr4 = pnr3+1;
1138
1139                                getPoint2d_p(l2, pnr4, &p4);
1140                                dl->twisted=twist; /*we reset the "twist" for each iteration*/
1141                                if (!lw_dist2d_selected_seg_seg(&p1, &p2, &p3, &p4, dl)) return LW_FALSE;
1142
1143                                maxmeasure = sqrt(dl->distance*dl->distance + (dl->distance*dl->distance*k*k));/*here we "translate" the found mindistance so it can be compared to our "z"-values*/
1144                        }
1145                }
1146        }
1147
1148        return LW_TRUE;
1149}
1150
1151
1152/**
1153        This is the same function as lw_dist2d_seg_seg but
1154        without any calculations to determine intersection since we
1155        already know they do not intersect
1156*/
1157int
1158lw_dist2d_selected_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D, DISTPTS *dl)
1159{
1160        LWDEBUGF(2, "lw_dist2d_selected_seg_seg [%g,%g]->[%g,%g] by [%g,%g]->[%g,%g]",
1161                 A->x,A->y,B->x,B->y, C->x,C->y, D->x, D->y);
1162
1163        /*A and B are the same point */
1164        if (  ( A->x == B->x) && (A->y == B->y) )
1165        {
1166                return lw_dist2d_pt_seg(A,C,D,dl);
1167        }
1168        /*U and V are the same point */
1169
1170        if (  ( C->x == D->x) && (C->y == D->y) )
1171        {
1172                dl->twisted= ((dl->twisted) * (-1));
1173                return lw_dist2d_pt_seg(D,A,B,dl);
1174        }
1175
1176        if ((lw_dist2d_pt_seg(A,C,D,dl)) && (lw_dist2d_pt_seg(B,C,D,dl)))
1177        {
1178                dl->twisted= ((dl->twisted) * (-1));  /*here we change the order of inputted geometrys and that we  notice by changing sign on dl->twisted*/
1179                return ((lw_dist2d_pt_seg(C,A,B,dl)) && (lw_dist2d_pt_seg(D,A,B,dl))); /*if all is successful we return true*/
1180        }
1181        else
1182        {
1183                return LW_FALSE; /* if any of the calls to lw_dist2d_pt_seg goes wrong we return false*/
1184        }
1185}
1186
1187/*------------------------------------------------------------------------------------------------------------
1188End of New faster distance calculations
1189--------------------------------------------------------------------------------------------------------------*/
1190
1191
1192/*------------------------------------------------------------------------------------------------------------
1193Functions in common for Brute force and new calculation
1194--------------------------------------------------------------------------------------------------------------*/
1195
1196/**
1197 * pt_in_ring_2d(): crossing number test for a point in a polygon
1198 *      input:   p = a point,
1199 *               pa = vertex points of a ring V[n+1] with V[n]=V[0]
1200 *      returns: 0 = outside, 1 = inside
1201 *
1202 *      Our polygons have first and last point the same,
1203 *
1204 */
1205int
1206pt_in_ring_2d(POINT2D *p, POINTARRAY *ring)
1207{
1208        int cn = 0;    /* the crossing number counter */
1209        int i;
1210        POINT2D v1, v2;
1211
1212#if INTEGRITY_CHECKS
1213        POINT2D first, last;
1214
1215        getPoint2d_p(ring, 0, &first);
1216        getPoint2d_p(ring, ring->npoints-1, &last);
1217        if ( memcmp(&first, &last, sizeof(POINT2D)) )
1218        {
1219                lwerror("pt_in_ring_2d: V[n] != V[0] (%g %g != %g %g)",
1220                        first.x, first.y, last.x, last.y);
1221                return LW_FALSE;
1222
1223        }
1224#endif
1225
1226        LWDEBUGF(2, "pt_in_ring_2d called with point: %g %g", p->x, p->y);
1227        /* printPA(ring); */
1228
1229        /* loop through all edges of the polygon */
1230        getPoint2d_p(ring, 0, &v1);
1231        for (i=0; i<ring->npoints-1; i++)
1232        {
1233                double vt;
1234                getPoint2d_p(ring, i+1, &v2);
1235
1236                /* edge from vertex i to vertex i+1 */
1237                if
1238                (
1239                    /* an upward crossing */
1240                    ((v1.y <= p->y) && (v2.y > p->y))
1241                    /* a downward crossing */
1242                    || ((v1.y > p->y) && (v2.y <= p->y))
1243                )
1244                {
1245
1246                        vt = (double)(p->y - v1.y) / (v2.y - v1.y);
1247
1248                        /* P.x <intersect */
1249                        if (p->x < v1.x + vt * (v2.x - v1.x))
1250                        {
1251                                /* a valid crossing of y=p.y right of p.x */
1252                                ++cn;
1253                        }
1254                }
1255                v1 = v2;
1256        }
1257
1258        LWDEBUGF(3, "pt_in_ring_2d returning %d", cn&1);
1259
1260        return (cn&1);    /* 0 if even (out), and 1 if odd (in) */
1261}
1262
1263
1264/**
1265
1266lw_dist2d_comp from p to line A->B
1267This one is now sending every occation to lw_dist2d_pt_pt
1268Before it was handling occations where r was between 0 and 1 internally
1269and just returning the distance without identifying the points.
1270To get this points it was nessecary to change and it also showed to be about 10%faster.
1271*/
1272int
1273lw_dist2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B, DISTPTS *dl)
1274{
1275        double  r;
1276        /*if start==end, then use pt distance */
1277        if (  ( A->x == B->x) && (A->y == B->y) )
1278        {
1279                return lw_dist2d_pt_pt(p,A,dl);
1280        }
1281        /*
1282         * otherwise, we use comp.graphics.algorithms
1283         * Frequently Asked Questions method
1284         *
1285         *  (1)               AC dot AB
1286             *         r = ---------
1287             *               ||AB||^2
1288         *      r has the following meaning:
1289         *      r=0 P = A
1290         *      r=1 P = B
1291         *      r<0 P is on the backward extension of AB
1292         *      r>1 P is on the forward extension of AB
1293         *      0<r<1 P is interior to AB
1294         */
1295
1296        r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
1297
1298        /*This is for finding the maxdistance.
1299        the maxdistance have to be between two vertexes,
1300        compared to mindistance which can be between
1301        tvo vertexes vertex.*/
1302        if (dl->mode == DIST2D_MAX)
1303        {
1304                if (r>=0.5)
1305                {
1306                        return lw_dist2d_pt_pt(p,A,dl);
1307                }
1308                if (r<0.5)
1309                {
1310                        return lw_dist2d_pt_pt(p,B,dl);
1311                }
1312        }
1313
1314        if (r<0)        /*If the first vertex A is closest to the point p*/
1315        {
1316                return lw_dist2d_pt_pt(p,A,dl);
1317        }
1318        if (r>1)        /*If the second vertex B is closest to the point p*/
1319        {
1320                return lw_dist2d_pt_pt(p,B,dl);
1321        }
1322
1323
1324        /*else if the point p is closer to some point between a and b
1325        then we find that point and send it to lw_dist2d_pt_pt*/
1326        POINT2D c;
1327        c.x=A->x + r * (B->x-A->x);
1328        c.y=A->y + r * (B->y-A->y);
1329
1330        return lw_dist2d_pt_pt(p,&c,dl);
1331}
1332
1333
1334/**
1335
1336Compares incomming points and
1337stores the points closest to each other
1338or most far away from each other
1339depending on dl->mode (max or min)
1340*/
1341int
1342lw_dist2d_pt_pt(POINT2D *thep1, POINT2D *thep2,DISTPTS *dl)
1343{
1344        double hside = thep2->x - thep1->x;
1345        double vside = thep2->y - thep1->y;
1346        double dist = sqrt ( hside*hside + vside*vside );
1347
1348        if (((dl->distance - dist)*(dl->mode))>0) /*multiplication with mode to handle mindistance (mode=1)  and maxdistance (mode = (-1)*/
1349        {
1350                dl->distance = dist;
1351
1352                if (dl->twisted>0)      /*To get the points in right order. twisted is updated between 1 and (-1) every time the order is changed earlier in the chain*/
1353                {
1354                        dl->p1 = *thep1;
1355                        dl->p2 = *thep2;
1356                }
1357                else
1358                {
1359                        dl->p1 = *thep2;
1360                        dl->p2 = *thep1;
1361                }
1362        }
1363        return LW_TRUE;
1364}
1365
1366
1367
1368
1369/*------------------------------------------------------------------------------------------------------------
1370End of Functions in common for Brute force and new calculation
1371--------------------------------------------------------------------------------------------------------------*/
1372
1373
1374/*Mixed functions*/
1375
1376
1377/**
1378
1379 true if point is in poly (and not in its holes)
1380 It's not used by postgis but since I don't know what else
1381 can be affectes in the world I don't dare removing it.
1382 */
1383int
1384pt_in_poly_2d(POINT2D *p, LWPOLY *poly)
1385{
1386        int i;
1387
1388        /* Not in outer ring */
1389        if ( ! pt_in_ring_2d(p, poly->rings[0]) ) return 0;
1390
1391        /* Check holes */
1392        for (i=1; i<poly->nrings; i++)
1393        {
1394                /* Inside a hole */
1395                if ( pt_in_ring_2d(p, poly->rings[i]) ) return 0;
1396        }
1397
1398        return 1; /* In outer ring, not in holes */
1399}
1400
1401
1402/**
1403The old function nessecary for ptarray_segmentize2d in ptarray.c
1404*/
1405double
1406distance2d_pt_pt(POINT2D *p1, POINT2D *p2)
1407{
1408        double hside = p2->x - p1->x;
1409        double vside = p2->y - p1->y;
1410
1411        return sqrt ( hside*hside + vside*vside );
1412
1413        /* the above is more readable
1414           return sqrt(
1415                (p2->x-p1->x) * (p2->x-p1->x) + (p2->y-p1->y) * (p2->y-p1->y)
1416                );  */
1417}
1418
1419
1420
1421/**
1422
1423The old function nessecary for ptarray_segmentize2d in ptarray.c
1424*/
1425double
1426distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B)
1427{
1428        double  r,s;
1429
1430        /*if start==end, then use pt distance */
1431        if (  ( A->x == B->x) && (A->y == B->y) )
1432                return distance2d_pt_pt(p,A);
1433
1434        /*
1435         * otherwise, we use comp.graphics.algorithms
1436         * Frequently Asked Questions method
1437         *
1438         *  (1)               AC dot AB
1439                *         r = ---------
1440                *               ||AB||^2
1441         *      r has the following meaning:
1442         *      r=0 P = A
1443         *      r=1 P = B
1444         *      r<0 P is on the backward extension of AB
1445         *      r>1 P is on the forward extension of AB
1446         *      0<r<1 P is interior to AB
1447         */
1448
1449        r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
1450
1451        if (r<0) return distance2d_pt_pt(p,A);
1452        if (r>1) return distance2d_pt_pt(p,B);
1453
1454
1455        /*
1456         * (2)
1457         *           (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
1458         *      s = -----------------------------
1459         *                      L^2
1460         *
1461         *      Then the distance from C to P = |s|*L.
1462         *
1463         */
1464
1465        s = ( (A->y-p->y)*(B->x-A->x)- (A->x-p->x)*(B->y-A->y) ) /
1466            ( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
1467
1468        return LW_ABS(s) * sqrt(
1469                   (B->x-A->x)*(B->x-A->x) + (B->y-A->y)*(B->y-A->y)
1470               );
1471}
1472
1473
1474
1475
1476
1477
1478
1479/**
1480find the 2d length of the given POINTARRAY (even if it's 3d)
1481*/
1482double
1483lwgeom_pointarray_length2d(POINTARRAY *pts)
1484{
1485        double dist = 0.0;
1486        int i;
1487        POINT2D frm;
1488        POINT2D to;
1489
1490        if ( pts->npoints < 2 ) return 0.0;
1491        for (i=0; i<pts->npoints-1; i++)
1492        {
1493                getPoint2d_p(pts, i, &frm);
1494                getPoint2d_p(pts, i+1, &to);
1495                dist += sqrt( ( (frm.x - to.x)*(frm.x - to.x) )  +
1496                              ((frm.y - to.y)*(frm.y - to.y) ) );
1497        }
1498        return dist;
1499}
1500
1501/**
1502 * Find the 3d/2d length of the given POINTARRAY
1503 * (depending on its dimensions)
1504 */
1505double
1506lwgeom_pointarray_length(POINTARRAY *pts)
1507{
1508        double dist = 0.0;
1509        int i;
1510        POINT3DZ frm;
1511        POINT3DZ to;
1512
1513        if ( pts->npoints < 2 ) return 0.0;
1514
1515        /* compute 2d length if 3d is not available */
1516        if ( ! TYPE_HASZ(pts->dims) ) return lwgeom_pointarray_length2d(pts);
1517
1518        for (i=0; i<pts->npoints-1; i++)
1519        {
1520                getPoint3dz_p(pts, i, &frm);
1521                getPoint3dz_p(pts, i+1, &to);
1522                dist += sqrt( ( (frm.x - to.x)*(frm.x - to.x) )  +
1523                              ((frm.y - to.y)*(frm.y - to.y) ) +
1524                              ((frm.z - to.z)*(frm.z - to.z) ) );
1525        }
1526        return dist;
1527}
1528
1529/**
1530 * This should be rewritten to make use of the curve itself.
1531 */
1532double
1533lwgeom_curvepolygon_area(LWCURVEPOLY *curvepoly)
1534{
1535        LWPOLY *poly = (LWPOLY *)lwgeom_segmentize((LWGEOM *)curvepoly, 32);
1536        return lwgeom_polygon_area(poly);
1537}
1538
1539/**
1540 * Find the area of the outer ring - sum (area of inner rings).
1541 * Could use a more numerically stable calculator...
1542 */
1543double
1544lwgeom_polygon_area(LWPOLY *poly)
1545{
1546        double poly_area=0.0;
1547        int i;
1548        POINT2D p1;
1549        POINT2D p2;
1550
1551        LWDEBUGF(2, "in lwgeom_polygon_area (%d rings)", poly->nrings);
1552
1553        for (i=0; i<poly->nrings; i++)
1554        {
1555                int j;
1556                POINTARRAY *ring = poly->rings[i];
1557                double ringarea = 0.0;
1558
1559                LWDEBUGF(4, " rings %d has %d points", i, ring->npoints);
1560
1561                if ( ! ring->npoints ) continue; /* empty ring */
1562                for (j=0; j<ring->npoints-1; j++)
1563                {
1564                        getPoint2d_p(ring, j, &p1);
1565                        getPoint2d_p(ring, j+1, &p2);
1566                        ringarea += ( p1.x * p2.y ) - ( p1.y * p2.x );
1567                }
1568
1569                ringarea  /= 2.0;
1570
1571                LWDEBUGF(4, " ring 1 has area %lf",ringarea);
1572
1573                ringarea  = fabs(ringarea);
1574                if (i != 0)     /*outer */
1575                        ringarea  = -1.0*ringarea ; /* its a hole */
1576
1577                poly_area += ringarea;
1578        }
1579
1580        return poly_area;
1581}
1582
1583/**
1584 * Compute the sum of polygon rings length.
1585 * Could use a more numerically stable calculator...
1586 */
1587double
1588lwgeom_polygon_perimeter(LWPOLY *poly)
1589{
1590        double result=0.0;
1591        int i;
1592
1593        LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
1594
1595        for (i=0; i<poly->nrings; i++)
1596                result += lwgeom_pointarray_length(poly->rings[i]);
1597
1598        return result;
1599}
1600
1601/**
1602 * Compute the sum of polygon rings length (forcing 2d computation).
1603 * Could use a more numerically stable calculator...
1604 */
1605double
1606lwgeom_polygon_perimeter2d(LWPOLY *poly)
1607{
1608        double result=0.0;
1609        int i;
1610
1611        LWDEBUGF(2, "in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
1612
1613        for (i=0; i<poly->nrings; i++)
1614                result += lwgeom_pointarray_length2d(poly->rings[i]);
1615
1616        return result;
1617}
1618
1619
1620int
1621lwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad)
1622{
1623        POINT2D center;
1624
1625        center.x = cx;
1626        center.y = cy;
1627
1628        if ( distance2d_pt_pt(p, &center) < rad ) return 1;
1629        else return 0;
1630
1631}
1632
1633/**
1634 * Compute the azimuth of segment AB in radians.
1635 * Return 0 on exception (same point), 1 otherwise.
1636 */
1637int
1638azimuth_pt_pt(POINT2D *A, POINT2D *B, double *d)
1639{
1640        if ( A->x == B->x )
1641        {
1642                if ( A->y < B->y ) *d=0.0;
1643                else if ( A->y > B->y ) *d=M_PI;
1644                else return 0;
1645                return 1;
1646        }
1647
1648        if ( A->y == B->y )
1649        {
1650                if ( A->x < B->x ) *d=M_PI/2;
1651                else if ( A->x > B->x ) *d=M_PI+(M_PI/2);
1652                else return 0;
1653                return 1;
1654        }
1655
1656        if ( A->x < B->x )
1657        {
1658                if ( A->y < B->y )
1659                {
1660                        *d=atan(fabs(A->x - B->x) / fabs(A->y - B->y) );
1661                }
1662                else /* ( A->y > B->y )  - equality case handled above */
1663                {
1664                        *d=atan(fabs(A->y - B->y) / fabs(A->x - B->x) )
1665                           + (M_PI/2);
1666                }
1667        }
1668
1669        else /* ( A->x > B->x ) - equality case handled above */
1670        {
1671                if ( A->y > B->y )
1672                {
1673                        *d=atan(fabs(A->x - B->x) / fabs(A->y - B->y) )
1674                           + M_PI;
1675                }
1676                else /* ( A->y < B->y )  - equality case handled above */
1677                {
1678                        *d=atan(fabs(A->y - B->y) / fabs(A->x - B->x) )
1679                           + (M_PI+(M_PI/2));
1680                }
1681        }
1682
1683        return 1;
1684}
1685
Note: See TracBrowser for help on using the browser.