source: anuga_core/source/anuga/fit_interpolate/ptinpoly.c @ 5485

Last change on this file since 5485 was 4737, checked in by duncan, 17 years ago

typo

File size: 56.4 KB
Line 
1/* ptinpoly.c - point in polygon inside/outside code.
2
3   by Eric Haines, 3D/Eye Inc, erich@eye.com
4
5   This code contains the following algorithms:
6        crossings - count the crossing made by a ray from the test point
7        crossings-multiply - as above, but avoids a division; often a bit faster
8        angle summation - sum the angle formed by point and vertex pairs
9        weiler angle summation - sum the angles using quad movements
10        half-plane testing - test triangle fan using half-space planes
11        barycentric coordinates - test triangle fan w/barycentric coords
12        spackman barycentric - preprocessed barycentric coordinates
13        trapezoid testing - bin sorting algorithm
14        grid testing - grid imposed on polygon
15        exterior test - for convex polygons, check exterior of polygon
16        inclusion test - for convex polygons, use binary search for edge.
17       
18        if a no preprocessing and nor extra storage is available use the
19        Crossings test.
20        if a little preprocessing and extra storage is available:
21          - For general polygons
22          * with few sides, use the half-plane or spackman test
23          * with many sides use the crossings test
24          - For convex polygons
25          * with few sides, use the hybrid half-plane or spackman test
26          * with many sides use the inclusion test
27        if preprocessing and extra storage is available in abundance, use the
28        Grid test, except for perhaps triangles.
29*/
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <math.h>
34#include "ptinpoly.h"
35
36#define X       0
37#define Y       1
38
39#ifndef TRUE
40#define TRUE    1
41#define FALSE   0
42#endif
43
44#ifndef HUGE
45#define HUGE    1.797693134862315e+308
46#endif
47
48#ifndef M_PI
49#define M_PI    3.14159265358979323846
50#endif
51
52/* test if a & b are within epsilon.  Favors cases where a < b */
53#define Near(a,b,eps)   ( ((b)-(eps)<(a)) && ((a)-(eps)<(b)) )
54
55#define MALLOC_CHECK( a )       if ( !(a) ) {                              \
56                                    fprintf( stderr, "out of memory\n" ) ; \
57                                    exit(1) ;                              \
58                                }
59
60
61/* ======= Crossings algorithm ============================================ */
62
63/* Shoot a test ray along +X axis.  The strategy, from MacMartin, is to
64 * compare vertex Y values to the testing point's Y and quickly discard
65 * edges which are entirely to one side of the test ray.
66 *
67 * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
68 * _point_, returns 1 if inside, 0 if outside.  WINDING and CONVEX can be
69 * defined for this test.
70 */
71int CrossingsTest( pgon, numverts, point )
72double  pgon[][2] ;
73int     numverts ;
74double  point[2] ;
75{
76#ifdef  WINDING
77register int    crossings ;
78#endif
79register int    j, yflag0, yflag1, inside_flag, xflag0 ;
80register double ty, tx, *vtx0, *vtx1 ;
81#ifdef  CONVEX
82register int    line_flag ;
83#endif
84
85    tx = point[X] ;
86    ty = point[Y] ;
87
88    vtx0 = pgon[numverts-1] ;
89    /* get test bit for above/below X axis */
90    yflag0 = ( vtx0[Y] >= ty ) ;
91    vtx1 = pgon[0] ;
92
93#ifdef  WINDING
94    crossings = 0 ;
95#else
96    inside_flag = 0 ;
97#endif
98#ifdef  CONVEX
99    line_flag = 0 ;
100#endif
101    for ( j = numverts+1 ; --j ; ) {
102
103        yflag1 = ( vtx1[Y] >= ty ) ;
104        /* check if endpoints straddle (are on opposite sides) of X axis
105         * (i.e. the Y's differ); if so, +X ray could intersect this edge.
106         */
107        if ( yflag0 != yflag1 ) {
108            xflag0 = ( vtx0[X] >= tx ) ;
109            /* check if endpoints are on same side of the Y axis (i.e. X's
110             * are the same); if so, it's easy to test if edge hits or misses.
111             */
112            if ( xflag0 == ( vtx1[X] >= tx ) ) {
113
114                /* if edge's X values both right of the point, must hit */
115#ifdef  WINDING
116                if ( xflag0 ) crossings += ( yflag0 ? -1 : 1 ) ;
117#else
118                if ( xflag0 ) inside_flag = !inside_flag ;
119#endif
120            } else {
121                /* compute intersection of pgon segment with +X ray, note
122                 * if >= point's X; if so, the ray hits it.
123                 */
124                if ( (vtx1[X] - (vtx1[Y]-ty)*
125                     ( vtx0[X]-vtx1[X])/(vtx0[Y]-vtx1[Y])) >= tx ) {
126#ifdef  WINDING
127                    crossings += ( yflag0 ? -1 : 1 ) ;
128#else
129                    inside_flag = !inside_flag ;
130#endif
131                }
132            }
133#ifdef  CONVEX
134            /* if this is second edge hit, then done testing */
135            if ( line_flag ) goto Exit ;
136
137            /* note that one edge has been hit by the ray's line */
138            line_flag = TRUE ;
139#endif
140        }
141
142        /* move to next pair of vertices, retaining info as possible */
143        yflag0 = yflag1 ;
144        vtx0 = vtx1 ;
145        vtx1 += 2 ;
146    }
147#ifdef  CONVEX
148    Exit: ;
149#endif
150#ifdef  WINDING
151    /* test if crossings is not zero */
152    inside_flag = (crossings != 0) ;
153#endif
154
155    return( inside_flag ) ;
156}
157
158/* ======= Angle summation algorithm ======================================= */
159
160/* Sum angles made by (vtxN to test point to vtxN+1), check if in proper
161 * range to be inside.  VERY SLOW, included for tutorial reasons (i.e.
162 * to show why one should never use this algorithm).
163 *
164 * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
165 * _point_, returns 1 if inside, 0 if outside.
166 */
167int AngleTest( pgon, numverts, point )
168double  pgon[][2] ;
169int     numverts ;
170double  point[2] ;
171{
172register double *vtx0, *vtx1, angle, len, vec0[2], vec1[2], vec_dot ;
173register int    j ;
174int     inside_flag ;
175
176    /* sum the angles and see if answer mod 2*PI > PI */
177    vtx0 = pgon[numverts-1] ;
178    vec0[X] = vtx0[X] - point[X] ;
179    vec0[Y] = vtx0[Y] - point[Y] ;
180    len = sqrt( vec0[X] * vec0[X] + vec0[Y] * vec0[Y] ) ;
181    if ( len <= 0.0 ) {
182        /* point and vertex coincide */
183        return( 1 ) ;
184    }
185    vec0[X] /= len ;
186    vec0[Y] /= len ;
187
188    angle = 0.0 ;
189    for ( j = 0 ; j < numverts ; j++ ) {
190        vtx1 = pgon[j] ;
191        vec1[X] = vtx1[X] - point[X] ;
192        vec1[Y] = vtx1[Y] - point[Y] ;
193        len = sqrt( vec1[X] * vec1[X] + vec1[Y] * vec1[Y] ) ;
194        if ( len <= 0.0 ) {
195            /* point and vertex coincide */
196            return( 1 ) ;
197        }
198        vec1[X] /= len ;
199        vec1[Y] /= len ;
200
201        /* check if vec1 is to "left" or "right" of vec0 */
202        vec_dot = vec0[X] * vec1[X] + vec0[Y] * vec1[Y] ;
203        if ( vec_dot < -1.0 ) {
204            /* point is on edge, so always add 180 degrees.  always
205             * adding is not necessarily the right answer for
206             * concave polygons and subtractive triangles.
207             */
208            angle += M_PI ;
209        } else if ( vec_dot < 1.0 ) {
210            if ( vec0[X] * vec1[Y] - vec1[X] * vec0[Y] >= 0.0 ) {
211                /* add angle due to dot product of vectors */
212                angle += acos( vec_dot ) ;
213            } else {
214                /* subtract angle due to dot product of vectors */
215                angle -= acos( vec_dot ) ;
216            }
217        } /* if vec_dot >= 1.0, angle does not change */
218
219        /* get to next point */
220        vtx0 = vtx1 ;
221        vec0[X] = vec1[X] ;
222        vec0[Y] = vec1[Y] ;
223    }
224    /* test if between PI and 3*PI, 5*PI and 7*PI, etc */
225    inside_flag = fmod( fabs(angle) + M_PI, 4.0*M_PI ) > 2.0*M_PI ;
226
227    return( inside_flag ) ;
228}
229
230/* ======= Weiler algorithm ============================================ */
231
232/* Track quadrant movements using Weiler's algorithm (elsewhere in Graphics
233 * Gems IV).  Algorithm has been optimized for testing purposes, but the
234 * crossings algorithm is still faster.  Included to provide timings.
235 *
236 * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
237 * _point_, returns 1 if inside, 0 if outside.  WINDING can be defined for
238 * this test.
239 */
240
241#define QUADRANT( vtx, x, y )   \
242        (((vtx)[X]>(x)) ? ( ((vtx)[Y]>(y)) ? 0:3 ) : ( ((vtx)[Y]>(y)) ? 1:2 ))
243
244#define X_INTERCEPT( v0, v1, y )        \
245        ( (((v1)[X]-(v0)[X])/((v1)[Y]-(v0)[Y])) * ((y)-(v0)[Y]) + (v0)[X] )
246
247int WeilerTest( pgon, numverts, point )
248double  pgon[][2] ;
249int     numverts ;
250double  point[2] ;
251{
252register int    angle, qd, next_qd, delta, j ;
253register double ty, tx, *vtx0, *vtx1 ;
254int     inside_flag ;
255
256    tx = point[X] ;
257    ty = point[Y] ;
258
259    vtx0 = pgon[numverts-1] ;
260    qd = QUADRANT( vtx0, tx, ty ) ;
261    angle = 0 ;
262
263    vtx1 = pgon[0] ;
264
265    for ( j = numverts+1 ; --j ; ) {
266        /* calculate quadrant and delta from last quadrant */
267        next_qd = QUADRANT( vtx1, tx, ty ) ;
268        delta = next_qd - qd ;
269
270        /* adjust delta and add it to total angle sum */
271        switch ( delta ) {
272            case 0:     /* do nothing */
273                break ;
274            case -1:
275            case 3:
276                angle-- ;
277                qd = next_qd ;
278                break ;
279
280            case 1:
281            case -3:
282                angle++ ;
283                qd = next_qd ;
284                break ;
285
286            case 2:
287            case -2:
288                if (X_INTERCEPT( vtx0, vtx1, ty ) > tx ) {
289                    angle -= delta ;
290                } else {
291                    angle += delta ;
292                }
293                qd = next_qd ;
294                break ;
295        }
296
297        /* increment for next step */
298        vtx0 = vtx1 ;
299        vtx1 += 2 ;
300    }
301
302#ifdef  WINDING
303    /* simple windings test:  if angle != 0, then point is inside */
304    inside_flag = ( angle != 0 ) ;
305#else
306    /* Jordan test:  if angle is +-4, 12, 20, etc then point is inside */
307    inside_flag = ( (angle/4) & 0x1 ) ;
308#endif
309
310    return (inside_flag) ;
311}
312
313#undef  QUADRANT
314#undef  Y_INTERCEPT
315
316/* ======= Triangle half-plane algorithm ================================== */
317
318/* Split the polygon into a fan of triangles and for each triangle test if
319 * the point is inside of the three half-planes formed by the triangle's edges.
320 *
321 * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices,
322 * which returns a pointer to a plane set array.
323 * Call testing procedure with a pointer to this array, _numverts_, and
324 * test point _point_, returns 1 if inside, 0 if outside.
325 * Call cleanup with pointer to plane set array to free space.
326 *
327 * SORT and CONVEX can be defined for this test.
328 */
329
330/* split polygons along set of x axes - call preprocess once */
331pPlaneSet       PlaneSetup( pgon, numverts )
332double  pgon[][2] ;
333int     numverts ;
334{
335int     i, p1, p2 ;
336double  tx, ty, vx0, vy0 ;
337pPlaneSet       pps, pps_return ;
338#ifdef  SORT
339double  len[3], len_temp ;
340int     j ;
341PlaneSet        ps_temp ;
342#ifdef  CONVEX
343pPlaneSet       pps_new ;
344pSizePlanePair p_size_pair ;
345#endif
346#endif
347
348    pps = pps_return =
349            (pPlaneSet)malloc( 3 * (numverts-2) * sizeof( PlaneSet )) ;
350    MALLOC_CHECK( pps ) ;
351#ifdef  CONVEX
352#ifdef  SORT
353    p_size_pair =
354        (pSizePlanePair)malloc( (numverts-2) * sizeof( SizePlanePair ) ) ;
355    MALLOC_CHECK( p_size_pair ) ;
356#endif
357#endif
358
359    vx0 = pgon[0][X] ;
360    vy0 = pgon[0][Y] ;
361
362    for ( p1 = 1, p2 = 2 ; p2 < numverts ; p1++, p2++ ) {
363        pps->vx = vy0 - pgon[p1][Y] ;
364        pps->vy = pgon[p1][X] - vx0 ;
365        pps->c = pps->vx * vx0 + pps->vy * vy0 ;
366#ifdef  SORT
367        len[0] = pps->vx * pps->vx + pps->vy * pps->vy ;
368#ifdef  CONVEX
369#ifdef  HYBRID
370        pps->ext_flag = ( p1 == 1 ) ;
371#endif
372        /* Sort triangles by areas, so compute (twice) the area here */
373        p_size_pair[p1-1].pps = pps ;
374        p_size_pair[p1-1].size =
375                        ( pgon[0][X] * pgon[p1][Y] ) +
376                        ( pgon[p1][X] * pgon[p2][Y] ) +
377                        ( pgon[p2][X] * pgon[0][Y] ) -
378                        ( pgon[p1][X] * pgon[0][Y] ) -
379                        ( pgon[p2][X] * pgon[p1][Y] ) -
380                        ( pgon[0][X] * pgon[p2][Y] ) ;
381#endif
382#endif
383        pps++ ;
384        pps->vx = pgon[p1][Y] - pgon[p2][Y] ;
385        pps->vy = pgon[p2][X] - pgon[p1][X] ;
386        pps->c = pps->vx * pgon[p1][X] + pps->vy * pgon[p1][Y] ;
387#ifdef  SORT
388        len[1] = pps->vx * pps->vx + pps->vy * pps->vy ;
389#endif
390#ifdef  CONVEX
391#ifdef  HYBRID
392        pps->ext_flag = TRUE ;
393#endif
394#endif
395        pps++ ;
396        pps->vx = pgon[p2][Y] - vy0 ;
397        pps->vy = vx0 - pgon[p2][X] ;
398        pps->c = pps->vx * pgon[p2][X] + pps->vy * pgon[p2][Y] ;
399#ifdef  SORT
400        len[2] = pps->vx * pps->vx + pps->vy * pps->vy ;
401#endif
402#ifdef  CONVEX
403#ifdef  HYBRID
404        pps->ext_flag = ( p2 == numverts-1 ) ;
405#endif
406#endif
407
408        /* find an average point which must be inside of the triangle */
409        tx = ( vx0 + pgon[p1][X] + pgon[p2][X] ) / 3.0 ;
410        ty = ( vy0 + pgon[p1][Y] + pgon[p2][Y] ) / 3.0 ;
411
412        /* check sense and reverse if test point is not thought to be inside
413         * first triangle
414         */
415        if ( pps->vx * tx + pps->vy * ty >= pps->c ) {
416            /* back up to start of plane set */
417            pps -= 2 ;
418            /* point is thought to be outside, so reverse sense of edge
419             * normals so that it is correctly considered inside.
420             */
421            for ( i = 0 ; i < 3 ; i++ ) {
422                pps->vx = -pps->vx ;
423                pps->vy = -pps->vy ;
424                pps->= -pps->c ;
425                pps++ ;
426            }
427        } else {
428            pps++ ;
429        }
430
431#ifdef  SORT
432        /* sort the planes based on the edge lengths */
433        pps -= 3 ;
434        for ( i = 0 ; i < 2 ; i++ ) {
435            for ( j = i+1 ; j < 3 ; j++ ) {
436                if ( len[i] < len[j] ) {
437                    ps_temp = pps[i] ;
438                    pps[i] = pps[j] ;
439                    pps[j] = ps_temp ;
440                    len_temp = len[i] ;
441                    len[i] = len[j] ;
442                    len[j] = len_temp ;
443                }
444            }
445        }
446        pps += 3 ;
447#endif
448    }
449
450#ifdef  CONVEX
451#ifdef  SORT
452    /* sort the triangles based on their areas */
453    qsort( p_size_pair, numverts-2,
454            sizeof( SizePlanePair ), CompareSizePlanePairs ) ;
455
456    /* make the plane sets match the sorted order */
457    for ( i = 0, pps = pps_return
458        ; i < numverts-2
459        ; i++ ) {
460
461        pps_new = p_size_pair[i].pps ;
462        for ( j = 0 ; j < 3 ; j++, pps++, pps_new++ ) {
463            ps_temp = *pps ;
464            *pps = *pps_new ;
465            *pps_new = ps_temp ;
466        }
467    }
468    free( p_size_pair ) ;
469#endif
470#endif
471
472    return( pps_return ) ;
473}
474
475#ifdef  CONVEX
476#ifdef  SORT
477int CompareSizePlanePairs( p_sp0, p_sp1 )
478pSizePlanePair  p_sp0, p_sp1 ;
479{
480    if ( p_sp0->size == p_sp1->size ) {
481        return( 0 ) ;
482    } else {
483        return( p_sp0->size > p_sp1->size ? -1 : 1 ) ;
484    }
485}
486#endif
487#endif
488
489
490/* check point for inside of three "planes" formed by triangle edges */
491int PlaneTest( p_plane_set, numverts, point )
492pPlaneSet       p_plane_set ;
493int     numverts ;
494double  point[2] ;
495{
496register pPlaneSet      ps ;
497register int    p2 ;
498#ifndef CONVEX
499register int    inside_flag ;
500#endif
501register double tx, ty ;
502
503    tx = point[X] ;
504    ty = point[Y] ;
505
506#ifndef CONVEX
507    inside_flag = 0 ;
508#endif
509
510    for ( ps = p_plane_set, p2 = numverts-1 ; --p2 ; ) {
511
512        if ( ps->vx * tx + ps->vy * ty < ps->c ) {
513            ps++ ;
514            if ( ps->vx * tx + ps->vy * ty < ps->c ) {
515                ps++ ;
516                /* note: we make the third edge have a slightly different
517                 * equality condition, since this third edge is in fact
518                 * the next triangle's first edge.  Not fool-proof, but
519                 * it doesn't hurt (better would be to keep track of the
520                 * triangle's area sign so we would know which kind of
521                 * triangle this is).  Note that edge sorting nullifies
522                 * this special inequality, too.
523                 */
524                if ( ps->vx * tx + ps->vy * ty <= ps->c ) {
525                    /* point is inside polygon */
526#ifdef CONVEX
527                    return( 1 ) ;
528#else
529                    inside_flag = !inside_flag ;
530#endif
531                }
532#ifdef  CONVEX
533#ifdef  HYBRID
534                /* check if outside exterior edge */
535                else if ( ps->ext_flag ) return( 0 ) ;
536#endif
537#endif
538                ps++ ;
539            } else {
540#ifdef  CONVEX
541#ifdef  HYBRID
542                /* check if outside exterior edge */
543                if ( ps->ext_flag ) return( 0 ) ;
544#endif
545#endif
546                /* get past last two plane tests */
547                ps += 2 ;
548            }
549        } else {
550#ifdef  CONVEX
551#ifdef  HYBRID
552            /* check if outside exterior edge */
553            if ( ps->ext_flag ) return( 0 ) ;
554#endif
555#endif
556            /* get past all three plane tests */
557            ps += 3 ;
558        }
559    }
560
561#ifdef CONVEX
562    /* for convex, if we make it to here, all triangles were missed */
563    return( 0 ) ;
564#else
565    return( inside_flag ) ;
566#endif
567}
568
569void PlaneCleanup( p_plane_set )
570pPlaneSet       p_plane_set ;
571{
572    free( p_plane_set ) ;
573}
574
575/* ======= Barycentric algorithm ========================================== */
576
577/* Split the polygon into a fan of triangles and for each triangle test if
578 * the point has barycentric coordinates which are inside the triangle.
579 * Similar to Badouel's code in Graphics Gems, with a little more efficient
580 * coding.
581 *
582 * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
583 * _point_, returns 1 if inside, 0 if outside.
584 */
585int BarycentricTest( pgon, numverts, point )
586double  pgon[][2] ;
587int     numverts ;
588double  point[2] ;
589{
590register double *pg1, *pg2, *pgend ;
591register double tx, ty, u0, u1, u2, v0, v1, vx0, vy0, alpha, beta, denom ;
592int     inside_flag ;
593
594    tx = point[X] ;
595    ty = point[Y] ;
596    vx0 = pgon[0][X] ;
597    vy0 = pgon[0][Y] ;
598    u0 = tx - vx0 ;
599    v0 = ty - vy0 ;
600
601    inside_flag = 0 ;
602    pgend = pgon[numverts-1] ;
603    for ( pg1 = pgon[1], pg2 = pgon[2] ; pg1 != pgend ; pg1+=2, pg2+=2 ) {
604
605        u1 = pg1[X] - vx0 ;
606        if ( u1 == 0.0 ) {
607
608            /* 0 and 1 vertices have same X value */
609
610            /* zero area test - can be removed for convex testing */
611            u2 = pg2[X] - vx0 ;
612            if ( ( u2 == 0.0 ) ||
613
614                /* compute beta and check bounds */
615                /* we use "<= 0.0" so that points on the shared interior
616                 * edge will (generally) be inside only one polygon.
617                 */
618                 ( ( beta = u0 / u2 ) <= 0.0 ) ||
619                 ( beta > 1.0 ) ||
620
621                 /* zero area test - remove for convex testing */
622                 ( ( v1 = pg1[Y] - vy0 ) == 0.0 ) ||
623
624                 /* compute alpha and check bounds */
625                 ( ( alpha = ( v0 - beta *
626                    ( pg2[Y] - vy0 ) ) / v1 ) < 0.0 ) ) {
627
628                /* whew! missed! */
629                goto NextTri ;
630            }
631
632        } else {
633            /* 0 and 1 vertices have different X value */
634
635            /* compute denom and check for zero area triangle - check
636             * is not needed for convex polygon testing
637             */
638            u2 = pg2[X] - vx0 ;
639            v1 = pg1[Y] - vy0 ;
640            denom = ( pg2[Y] - vy0 ) * u1 - u2 * v1 ;
641            if ( ( denom == 0.0 ) ||
642
643                /* compute beta and check bounds */
644                /* we use "<= 0.0" so that points on the shared interior
645                 * edge will (generally) be inside only one polygon.
646                 */
647                 ( ( beta = ( v0 * u1 - u0 * v1 ) / denom ) <= 0.0 ) ||
648                 ( beta > 1.0 ) ||
649
650                 /* compute alpha & check bounds */
651                 ( ( alpha = ( u0 - beta * u2 ) / u1 ) < 0.0 ) ) {
652
653                /* whew! missed! */
654                goto NextTri ;
655            }
656        }
657
658        /* check gamma */
659        if ( alpha + beta <= 1.0 ) {
660            /* survived */
661            inside_flag = !inside_flag ;
662        }
663
664        NextTri: ;
665    }
666    return( inside_flag ) ;
667}
668
669/* ======= Barycentric precompute (Spackman) algorithm ===================== */
670
671/* Split the polygon into a fan of triangles and for each triangle test if
672 * the point has barycentric coordinates which are inside the triangle.
673 * Use Spackman's normalization method to precompute various parameters.
674 *
675 * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices,
676 * which returns a pointer to the array of the parameters records and the
677 * number of parameter records created.
678 * Call testing procedure with the first vertex in the polygon _pgon[0]_,
679 * a pointer to this array, the number of parameter records, and test point
680 * _point_, returns 1 if inside, 0 if outside.
681 * Call cleanup with pointer to parameter record array to free space.
682 *
683 * SORT can be defined for this test.
684 * (CONVEX could be added: see PlaneSetup and PlaneTest for method)
685 */
686pSpackmanSet    SpackmanSetup( pgon, numverts, p_numrec )
687double  pgon[][2] ;
688int     numverts ;
689int     *p_numrec ;
690{
691int     p1, p2, degen ;
692double  denom, u1, v1, *pv[3] ;
693pSpackmanSet    pss, pss_return ;
694#ifdef  SORT
695double  u[2], v[2], len[2], *pv_temp ;
696#endif
697
698    pss = pss_return =
699            (pSpackmanSet)malloc( (numverts-2) * sizeof( SpackmanSet )) ;
700    MALLOC_CHECK( pss ) ;
701
702    degen = 0 ;
703
704    for ( p1 = 1, p2 = 2 ; p2 < numverts ; p1++, p2++ ) {
705
706        pv[0] = pgon[0] ;
707        pv[1] = pgon[p1] ;
708        pv[2] = pgon[p2] ;
709
710#ifdef  SORT
711        /* Note that sorting can cause a mismatch of alpha/beta inequality
712         * tests.  In other words, test points on an interior line between
713         * test triangles will often then be wrong.
714         */
715        u[0] = pv[1][X] - pv[0][X] ;
716        u[1] = pv[2][X] - pv[0][X] ;
717        v[0] = pv[1][Y] - pv[0][Y] ;
718        v[1] = pv[2][Y] - pv[0][Y] ;
719        len[0] = u[0] * u[0] + v[0] * v[0] ;
720        len[1] = u[1] * u[1] + v[1] * v[1] ;
721
722        /* compare two edges touching anchor point and put longest first */
723        /* we don't sort all three edges because the anchor point and
724         * values computed from it gets used for all triangles in the fan.
725         */
726        if ( len[0] < len[1] ) {
727            pv_temp = pv[1] ;
728            pv[1] = pv[2] ;
729            pv[2] = pv_temp ;
730        }
731#endif
732
733        u1 = pv[1][X] - pv[0][X] ;
734        pss->u2 = pv[2][X] - pv[0][X] ;
735        v1 = pv[1][Y] - pv[0][Y] ;
736        pss->v2 = pv[2][Y] - pv[0][Y] ;
737        pss->u1_nonzero = !( u1 == 0.0 ) ;
738        if ( pss->u1_nonzero ) {
739            /* not zero, so compute inverse */
740            pss->inv_u1 = 1.0 / u1 ;
741            denom = pss->v2 * u1 - pss->u2 * v1 ;
742            if ( denom == 0.0 ) {
743                /* degenerate triangle, ignore it */
744                degen++ ;
745                goto Skip ;
746            } else {
747                pss->u1p = u1 / denom ;
748                pss->v1p = v1 / denom ;
749            }
750        } else {
751            if ( pss->u2 == 0.0 ) {
752                /* degenerate triangle, ignore it */
753                degen++ ;
754                goto Skip ;
755            } else {
756                /* not zero, so compute inverse */
757                pss->inv_u2 = 1.0 / pss->u2 ;
758                if ( v1 == 0.0 ) {
759                    /* degenerate triangle, ignore it */
760                    degen++ ;
761                    goto Skip ;
762                } else {
763                    pss->inv_v1 = 1.0 / v1 ;
764                }
765            }
766        }
767
768        pss++ ;
769        Skip: ;
770    }
771
772    /* number of Spackman records */
773    *p_numrec = numverts - degen - 2 ;
774    if ( degen ) {
775        pss = pss_return =
776                (pSpackmanSet)realloc( pss_return,
777                        (numverts-2-degen) * sizeof( SpackmanSet )) ;
778    }
779
780    return( pss_return ) ;
781}
782
783/* barycentric, a la Gems I and Spackman's normalization precompute */
784int SpackmanTest( anchor, p_spackman_set, numrec, point )
785double  anchor[2] ;
786pSpackmanSet    p_spackman_set ;
787int     numrec ;
788double  point[2] ;
789{
790register pSpackmanSet   pss ;
791register int    inside_flag ;
792register int    nr ;
793register double tx, ty, vx0, vy0, u0, v0, alpha, beta ;
794
795    tx = point[X] ;
796    ty = point[Y] ;
797    /* note that we really need only the first vertex of the polygon,
798     * so do not really need to keep the whole polygon around.
799     */
800    vx0 = anchor[X] ;
801    vy0 = anchor[Y] ;
802    u0 = tx - vx0 ;
803    v0 = ty - vy0 ;
804
805    inside_flag = 0 ;
806
807    for ( pss = p_spackman_set, nr = numrec+1 ; --nr ; pss++ ) {
808
809        if ( pss->u1_nonzero ) {
810            /* 0 and 2 vertices have different X value */
811
812            /* compute beta and check bounds */
813            /* we use "<= 0.0" so that points on the shared interior edge
814             * will (generally) be inside only one polygon.
815             */
816            beta = ( v0 * pss->u1p - u0 * pss->v1p ) ;
817            if ( ( beta <= 0.0 ) || ( beta > 1.0 ) ||
818
819                 /* compute alpha & check bounds */
820                 ( ( alpha = ( u0 - beta * pss->u2 ) * pss->inv_u1 )
821                        < 0.0 ) ) {
822
823                /* whew! missed! */
824                goto NextTri ;
825            }
826        } else {
827            /* 0 and 2 vertices have same X value */
828
829            /* compute beta and check bounds */
830            /* we use "<= 0.0" so that points on the shared interior edge
831             * will (generally) be inside only one polygon.
832             */
833            beta = u0 * pss->inv_u2 ;
834            if ( ( beta <= 0.0 ) || ( beta >= 1.0 ) ||
835
836                 /* compute alpha and check bounds */
837                 ( ( alpha = ( v0 - beta * pss->v2 ) * pss->inv_v1 )
838                        < 0.0 ) ) {
839
840                /* whew! missed! */
841                goto NextTri ;
842            }
843        }
844
845        /* check gamma */
846        if ( alpha + beta <= 1.0 ) {
847            /* survived */
848            inside_flag = !inside_flag ;
849        }
850
851        NextTri: ;
852    }
853
854    return( inside_flag ) ;
855}
856
857void SpackmanCleanup( p_spackman_set )
858pSpackmanSet    p_spackman_set ;
859{
860    free( p_spackman_set ) ;
861}
862
863/* ======= Trapezoid (bin) algorithm ======================================= */
864
865/* Split polygons along set of y bins and sorts the edge fragments.  Testing
866 * is done against these fragments.
867 *
868 * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, the
869 * number of bins desired _bins_, and a pointer to a trapezoid structure
870 * _p_trap_set_.
871 * Call testing procedure with 2D polygon _pgon_ with _numverts_ number of
872 * vertices, _p_trap_set_ pointer to trapezoid structure, and test point
873 * _point_, returns 1 if inside, 0 if outside.
874 * Call cleanup with pointer to trapezoid structure to free space.
875 */
876void TrapezoidSetup( pgon, numverts, bins, p_trap_set )
877double  pgon[][2] ;
878int     numverts ;
879int     bins ;
880pTrapezoidSet   p_trap_set ;
881{
882double  *vtx0, *vtx1, *vtxa, *vtxb, slope ;
883int     i, j, bin_tot[TOT_BINS], ba, bb, id, full_cross, count ;
884double  fba, fbb, vx0, vx1, dy, vy0 ;
885
886    p_trap_set->bins = bins ;
887    p_trap_set->trapz = (pTrapezoid)malloc( p_trap_set->bins *
888            sizeof(Trapezoid));
889    MALLOC_CHECK( p_trap_set->trapz ) ;
890
891    p_trap_set->minx =
892    p_trap_set->maxx = pgon[0][X] ;
893    p_trap_set->miny =
894    p_trap_set->maxy = pgon[0][Y] ;
895
896    for ( i = 1 ; i < numverts ; i++ ) {
897        if ( p_trap_set->minx > (vx0 = pgon[i][X]) ) {
898            p_trap_set->minx = vx0 ;
899        } else if ( p_trap_set->maxx < vx0 ) {
900            p_trap_set->maxx = vx0 ;
901        }
902
903        if ( p_trap_set->miny > (vy0 = pgon[i][Y]) ) {
904            p_trap_set->miny = vy0 ;
905        } else if ( p_trap_set->maxy < vy0 ) {
906            p_trap_set->maxy = vy0 ;
907        }
908    }
909
910    /* add a little to the bounds to ensure everything falls inside area */
911    p_trap_set->miny -= EPSILON * (p_trap_set->maxy-p_trap_set->miny) ;
912    p_trap_set->maxy += EPSILON * (p_trap_set->maxy-p_trap_set->miny) ;
913
914    p_trap_set->ydelta =
915            (p_trap_set->maxy-p_trap_set->miny) / (double)p_trap_set->bins ;
916    p_trap_set->inv_ydelta = 1.0 / p_trap_set->ydelta ;
917
918    /* find how many locations to allocate for each bin */
919    for ( i = 0 ; i < p_trap_set->bins ; i++ ) {
920        bin_tot[i] = 0 ;
921    }
922
923    vtx0 = pgon[numverts-1] ;
924    for ( i = 0 ; i < numverts ; i++ ) {
925        vtx1 = pgon[i] ;
926
927        /* skip if Y's identical (edge has no effect) */
928        if ( vtx0[Y] != vtx1[Y] ) {
929
930            if ( vtx0[Y] < vtx1[Y] ) {
931                vtxa = vtx0 ;
932                vtxb = vtx1 ;
933            } else {
934                vtxa = vtx1 ;
935                vtxb = vtx0 ;
936            }
937            ba = (int)(( vtxa[Y]-p_trap_set->miny ) * p_trap_set->inv_ydelta) ;
938            fbb = ( vtxb[Y] - p_trap_set->miny ) * p_trap_set->inv_ydelta ;
939            bb = (int)fbb ;
940            /* if high vertex ends on a boundary, don't go into next boundary */
941            if ( fbb - (double)bb == 0.0 ) {
942                bb-- ;
943            }
944
945            /* mark the bins with this edge */
946            for ( j = ba ; j <= bb ; j++ ) {
947                bin_tot[j]++ ;
948            }
949        }
950
951        vtx0 = vtx1 ;
952    }
953
954    /* allocate the bin contents and fill in some basics */
955    for ( i = 0 ; i < p_trap_set->bins ; i++ ) {
956        p_trap_set->trapz[i].edge_set =
957                (pEdge*)malloc( bin_tot[i] * sizeof(pEdge) ) ;
958        MALLOC_CHECK( p_trap_set->trapz[i].edge_set ) ;
959        for ( j = 0 ; j < bin_tot[i] ; j++ ) {
960            p_trap_set->trapz[i].edge_set[j] =
961                (pEdge)malloc( sizeof(Edge) ) ;
962            MALLOC_CHECK( p_trap_set->trapz[i].edge_set[j] ) ;
963        }
964
965        /* start these off at some awful values; refined below */
966        p_trap_set->trapz[i].minx = p_trap_set->maxx ;
967        p_trap_set->trapz[i].maxx = p_trap_set->minx ;
968        p_trap_set->trapz[i].count = 0 ;
969    }
970
971    /* now go through list yet again, putting edges in bins */
972    vtx0 = pgon[numverts-1] ;
973    id = numverts-1 ;
974    for ( i = 0 ; i < numverts ; i++ ) {
975        vtx1 = pgon[i] ;
976
977        /* we can skip edge if Y's are equal */
978        if ( vtx0[Y] != vtx1[Y] ) {
979            if ( vtx0[Y] < vtx1[Y] ) {
980                vtxa = vtx0 ;
981                vtxb = vtx1 ;
982            } else {
983                vtxa = vtx1 ;
984                vtxb = vtx0 ;
985            }
986            fba = ( vtxa[Y] - p_trap_set->miny ) * p_trap_set->inv_ydelta ;
987            ba = (int)fba ;
988            fbb = ( vtxb[Y] - p_trap_set->miny ) * p_trap_set->inv_ydelta ;
989            bb = (int)fbb ;
990            /* if high vertex ends on a boundary, don't go into it */
991            if ( fbb == (double)bb ) {
992                bb-- ;
993            }
994
995            vx0 = vtxa[X] ;
996            dy = vtxa[Y] - vtxb[Y] ;
997            slope = p_trap_set->ydelta * ( vtxa[X] - vtxb[X] ) / dy ;
998
999            /* set vx1 in case loop is not entered */
1000            vx1 = vx0 ;
1001            full_cross = 0 ;
1002
1003            for ( j = ba ; j < bb ; j++, vx0 = vx1 ) {
1004                /* could increment vx1, but for greater accuracy recompute it */
1005                vx1 = vtxa[X] + ( (double)(j+1) - fba ) * slope ;
1006
1007                count = p_trap_set->trapz[j].count++ ;
1008                p_trap_set->trapz[j].edge_set[count]->id = id ;
1009                p_trap_set->trapz[j].edge_set[count]->full_cross = full_cross;
1010                TrapBound( j, count, vx0, vx1, p_trap_set ) ;
1011                full_cross = 1 ;
1012            }
1013
1014            /* at last bin - fill as above, but with vx1 = vtxb[X] */
1015            vx0 = vx1 ;
1016            vx1 = vtxb[X] ;
1017            count = p_trap_set->trapz[bb].count++ ;
1018            p_trap_set->trapz[bb].edge_set[count]->id = id ;
1019            /* the last bin is never a full crossing */
1020            p_trap_set->trapz[bb].edge_set[count]->full_cross = 0 ;
1021            TrapBound( bb, count, vx0, vx1, p_trap_set ) ;
1022        }
1023
1024        vtx0 = vtx1 ;
1025        id = i ;
1026    }
1027
1028    /* finally, sort the bins' contents by minx */
1029    for ( i = 0 ; i < p_trap_set->bins ; i++ ) {
1030        qsort( p_trap_set->trapz[i].edge_set, p_trap_set->trapz[i].count,
1031                sizeof(pEdge), CompareEdges ) ;
1032    }
1033}
1034
1035void TrapBound( j, count, vx0, vx1, p_trap_set )
1036int     j, count ;
1037double  vx0, vx1 ;
1038pTrapezoidSet   p_trap_set ;
1039{
1040double  xt ;
1041
1042    if ( vx0 > vx1 ) {
1043        xt = vx0 ;
1044        vx0 = vx1 ;
1045        vx1 = xt ;
1046    }
1047
1048    if ( p_trap_set->trapz[j].minx > vx0 ) {
1049        p_trap_set->trapz[j].minx = vx0 ;
1050    }
1051    if ( p_trap_set->trapz[j].maxx < vx1 ) {
1052        p_trap_set->trapz[j].maxx = vx1 ;
1053    }
1054    p_trap_set->trapz[j].edge_set[count]->minx = vx0 ;
1055    p_trap_set->trapz[j].edge_set[count]->maxx = vx1 ;
1056}
1057
1058/* used by qsort to sort */
1059int CompareEdges( u, v )
1060pEdge   *u, *v ;
1061{
1062    if ( (*u)->minx == (*v)->minx ) {
1063        return( 0 ) ;
1064    } else {
1065        return( (*u)->minx < (*v)->minx ? -1 : 1 ) ;
1066    }
1067}
1068
1069int TrapezoidTest( pgon, numverts, p_trap_set, point )
1070double  pgon[][2] ;
1071int     numverts ;
1072pTrapezoidSet   p_trap_set ;
1073double  point[2] ;
1074{
1075int     j, b, count, id ;
1076double  tx, ty, *vtx0, *vtx1 ;
1077pEdge   *pp_bin ;
1078pTrapezoid      p_trap ;
1079int     inside_flag ;
1080
1081    inside_flag = 0 ;
1082
1083    /* first, is point inside bounding rectangle? */
1084    if ( ( ty = point[Y] ) < p_trap_set->miny ||
1085         ty >= p_trap_set->maxy ||
1086         ( tx = point[X] ) < p_trap_set->minx ||
1087         tx >= p_trap_set->maxx ) {
1088
1089        /* outside of box */
1090        return( 0 ) ;
1091    }
1092
1093    /* what bin are we in? */
1094    b = ( ty - p_trap_set->miny ) * p_trap_set->inv_ydelta ;
1095
1096    /* find if we're inside this bin's bounds */
1097    if ( tx < (p_trap = &p_trap_set->trapz[b])->minx ||
1098         tx > p_trap->maxx ) {
1099
1100        /* outside of box */
1101        return( 0 ) ;
1102    }
1103
1104    /* now search bin for crossings */
1105    pp_bin = p_trap->edge_set ;
1106    count = p_trap->count ;
1107    for ( j = 0 ; j < count ; j++, pp_bin++ ) {
1108        if ( tx < (*pp_bin)->minx ) {
1109
1110            /* all remaining edges are to right of point, so test them */
1111            do {
1112                if ( (*pp_bin)->full_cross ) {
1113                    inside_flag = !inside_flag ;
1114                } else {
1115                    id = (*pp_bin)->id ;
1116                    if ( ( ty <= pgon[id][Y] ) !=
1117                            ( ty <= pgon[(id+1)%numverts][Y] ) ) {
1118
1119                        /* point crosses edge in Y, so must cross */
1120                        inside_flag = !inside_flag ;
1121                    }
1122                }
1123                pp_bin++ ;
1124            } while ( ++j < count ) ;
1125            goto Exit;
1126
1127        } else if ( tx < (*pp_bin)->maxx ) {
1128            /* edge is overlapping point in X, check it */
1129            id = (*pp_bin)->id ;
1130            vtx0 = pgon[id] ;
1131            vtx1 = pgon[(id+1)%numverts] ;
1132
1133            if ( (*pp_bin)->full_cross ||
1134                 ( ty <= vtx0[Y] ) != ( ty <= vtx1[Y] ) ) {
1135
1136                /* edge crosses in Y, so have to do full crossings test */
1137                if ( (vtx0[X] -
1138                    (vtx0[Y] - ty )*
1139                        ( vtx1[X]-vtx0[X])/(vtx1[Y]-vtx0[Y])) >= tx ) {
1140                    inside_flag = !inside_flag ;
1141                }
1142            }
1143
1144        } /* else edge is to left of point, ignore it */
1145    }
1146
1147    Exit:
1148    return( inside_flag ) ;
1149}
1150
1151void TrapezoidCleanup( p_trap_set )
1152pTrapezoidSet   p_trap_set ;
1153{
1154int     i, j, count ;
1155
1156    for ( i = 0 ; i < p_trap_set->bins ; i++ ) {
1157        /* all of these should have bin sets, but check just in case */
1158        if ( p_trap_set->trapz[i].edge_set ) {
1159            count = p_trap_set->trapz[i].count ;
1160            for ( j = 0 ; j < count ; j++ ) {
1161                if ( p_trap_set->trapz[i].edge_set[j] ) {
1162                    free( p_trap_set->trapz[i].edge_set[j] ) ;
1163                }
1164            }
1165            free( p_trap_set->trapz[i].edge_set ) ;
1166        }
1167    }
1168    free( p_trap_set->trapz ) ;
1169}
1170
1171/* ======= Grid algorithm ================================================= */
1172
1173/* Impose a grid upon the polygon and test only the local edges against the
1174 * point.
1175 *
1176 * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices,
1177 * grid resolution _resolution_ and a pointer to a grid structure _p_gs_.
1178 * Call testing procedure with a pointer to this array and test point _point_,
1179 * returns 1 if inside, 0 if outside.
1180 * Call cleanup with pointer to grid structure to free space.
1181 */
1182
1183/* Strategy for setup:
1184 *   Get bounds of polygon, allocate grid.
1185 *   "Walk" each edge of the polygon and note which edges have been crossed
1186 *     and what cells are entered (points on a grid edge are always considered
1187 *     to be above that edge).  Keep a record of the edges overlapping a cell.
1188 *     For cells with edges, determine if any cell border has no edges passing
1189 *     through it and so can be used for shooting a test ray.
1190 *     Keep track of the parity of the x (horizontal) grid cell borders for
1191 *     use in determining whether the grid corners are inside or outside.
1192 */
1193void GridSetup( pgon, numverts, resolution, p_gs )
1194double  pgon[][2] ;
1195int     numverts ;
1196int     resolution ;
1197pGridSet        p_gs ;
1198{
1199double  *vtx0, *vtx1, *vtxa, *vtxb, *p_gl ;
1200int     i, j, gc_clear_flags ;
1201double  vx0, vx1, vy0, vy1, gxdiff, gydiff, eps ;
1202pGridCell       p_gc, p_ngc ;
1203double  xdiff, ydiff, tmax, inv_x, inv_y, xdir, ydir, t_near, tx, ty ;
1204double  tgcx, tgcy ;
1205int     gcx, gcy, sign_x ;
1206int     y_flag, io_state ;
1207
1208    p_gs->xres = p_gs->yres = resolution ;
1209    p_gs->tot_cells = p_gs->xres * p_gs->yres ;
1210    p_gs->glx = (double *)malloc( (p_gs->xres+1) * sizeof(double));
1211    MALLOC_CHECK( p_gs->glx ) ;
1212    p_gs->gly = (double *)malloc( (p_gs->yres+1) * sizeof(double));
1213    MALLOC_CHECK( p_gs->gly ) ;
1214    p_gs->gc = (pGridCell)malloc( p_gs->tot_cells * sizeof(GridCell));
1215    MALLOC_CHECK( p_gs->gc ) ;
1216
1217    p_gs->minx =
1218    p_gs->maxx = pgon[0][X] ;
1219    p_gs->miny =
1220    p_gs->maxy = pgon[0][Y] ;
1221
1222    /* find bounds of polygon */
1223    for ( i = 1 ; i < numverts ; i++ ) {
1224        vx0 = pgon[i][X] ;
1225        if ( p_gs->minx > vx0 ) {
1226            p_gs->minx = vx0 ;
1227        } else if ( p_gs->maxx < vx0 ) {
1228            p_gs->maxx = vx0 ;
1229        }
1230
1231        vy0 = pgon[i][Y] ;
1232        if ( p_gs->miny > vy0 ) {
1233            p_gs->miny = vy0 ;
1234        } else if ( p_gs->maxy < vy0 ) {
1235            p_gs->maxy = vy0 ;
1236        }
1237    }
1238
1239    /* add a little to the bounds to ensure everything falls inside area */
1240    gxdiff = p_gs->maxx - p_gs->minx ;
1241    gydiff = p_gs->maxy - p_gs->miny ;
1242    p_gs->minx -= EPSILON * gxdiff ;
1243    p_gs->maxx += EPSILON * gxdiff ;
1244    p_gs->miny -= EPSILON * gydiff ;
1245    p_gs->maxy += EPSILON * gydiff ;
1246
1247    /* avoid roundoff problems near corners by not getting too close to them */
1248    eps = 1e-9 * ( gxdiff + gydiff ) ;
1249
1250    /* use the new bounds to compute cell widths */
1251    TryAgain:
1252    p_gs->xdelta =
1253            (p_gs->maxx-p_gs->minx) / (double)p_gs->xres ;
1254    p_gs->inv_xdelta = 1.0 / p_gs->xdelta ;
1255
1256    p_gs->ydelta =
1257            (p_gs->maxy-p_gs->miny) / (double)p_gs->yres ;
1258    p_gs->inv_ydelta = 1.0 / p_gs->ydelta ;
1259
1260    for ( i = 0, p_gl = p_gs->glx ; i < p_gs->xres ; i++ ) {
1261        *p_gl++ = p_gs->minx + i * p_gs->xdelta ;
1262    }
1263    /* make last grid corner precisely correct */
1264    *p_gl = p_gs->maxx ;
1265
1266    for ( i = 0, p_gl = p_gs->gly ; i < p_gs->yres ; i++ ) {
1267        *p_gl++ = p_gs->miny + i * p_gs->ydelta ;
1268    }
1269    *p_gl = p_gs->maxy ;
1270
1271    for ( i = 0, p_gc = p_gs->gc ; i < p_gs->tot_cells ; i++, p_gc++ ) {
1272        p_gc->tot_edges = 0 ;
1273        p_gc->gc_flags = 0x0 ;
1274        p_gc->gr = NULL ;
1275    }
1276
1277    /* loop through edges and insert into grid structure */
1278    vtx0 = pgon[numverts-1] ;
1279    for ( i = 0 ; i < numverts ; i++ ) {
1280        vtx1 = pgon[i] ;
1281
1282        if ( vtx0[Y] < vtx1[Y] ) {
1283            vtxa = vtx0 ;
1284            vtxb = vtx1 ;
1285        } else {
1286            vtxa = vtx1 ;
1287            vtxb = vtx0 ;
1288        }
1289
1290        /* Set x variable for the direction of the ray */
1291        xdiff = vtxb[X] - vtxa[X] ;
1292        ydiff = vtxb[Y] - vtxa[Y] ;
1293        tmax = sqrt( xdiff * xdiff + ydiff * ydiff ) ;
1294
1295        /* if edge is of 0 length, ignore it (useless edge) */
1296        if ( tmax == 0.0 ) goto NextEdge ;
1297
1298        xdir = xdiff / tmax ;
1299        ydir = ydiff / tmax ;
1300
1301        gcx = (int)(( vtxa[X] - p_gs->minx ) * p_gs->inv_xdelta) ;
1302        gcy = (int)(( vtxa[Y] - p_gs->miny ) * p_gs->inv_ydelta) ;
1303
1304        /* get information about slopes of edge, etc */
1305        if ( vtxa[X] == vtxb[X] ) {
1306            sign_x = 0 ;
1307            tx = HUGE ;
1308        } else {
1309            inv_x = tmax / xdiff ;
1310            tx = p_gs->xdelta * (double)gcx + p_gs->minx - vtxa[X] ;
1311            if ( vtxa[X] < vtxb[X] ) {
1312                sign_x = 1 ;
1313                tx += p_gs->xdelta ;
1314                tgcx = p_gs->xdelta * inv_x ;
1315            } else {
1316                sign_x = -1 ;
1317                tgcx = -p_gs->xdelta * inv_x ;
1318            }
1319            tx *= inv_x ;
1320        }
1321
1322        if ( vtxa[Y] == vtxb[Y] ) {
1323            ty = HUGE ;
1324        } else {
1325            inv_y = tmax / ydiff ;
1326            ty = (p_gs->ydelta * (double)(gcy+1) + p_gs->miny - vtxa[Y])
1327                * inv_y ;
1328            tgcy = p_gs->ydelta * inv_y ;
1329        }
1330
1331        p_gc = &p_gs->gc[gcy*p_gs->xres+gcx] ;
1332
1333        vx0 = vtxa[X] ;
1334        vy0 = vtxa[Y] ;
1335
1336        t_near = 0.0 ;
1337
1338        do {
1339            /* choose the next boundary, but don't move yet */
1340            if ( tx <= ty ) {
1341                gcx += sign_x ;
1342
1343                ty -= tx ;
1344                t_near += tx ;
1345                tx = tgcx ;
1346
1347                /* note which edge is hit when leaving this cell */
1348                if ( t_near < tmax ) {
1349                    if ( sign_x > 0 ) {
1350                        p_gc->gc_flags |= GC_R_EDGE_HIT ;
1351                        vx1 = p_gs->glx[gcx] ;
1352                    } else {
1353                        p_gc->gc_flags |= GC_L_EDGE_HIT ;
1354                        vx1 = p_gs->glx[gcx+1] ;
1355                    }
1356
1357                    /* get new location */
1358                    vy1 = t_near * ydir + vtxa[Y] ;
1359                } else {
1360                    /* end of edge, so get exact value */
1361                    vx1 = vtxb[X] ;
1362                    vy1 = vtxb[Y] ;
1363                }
1364
1365                y_flag = FALSE ;
1366
1367            } else {
1368
1369                gcy++ ;
1370
1371                tx -= ty ;
1372                t_near += ty ;
1373                ty = tgcy ;
1374
1375                /* note top edge is hit when leaving this cell */
1376                if ( t_near < tmax ) {
1377                    p_gc->gc_flags |= GC_T_EDGE_HIT ;
1378                    /* this toggles the parity bit */
1379                    p_gc->gc_flags ^= GC_T_EDGE_PARITY ;
1380
1381                    /* get new location */
1382                    vx1 = t_near * xdir + vtxa[X] ;
1383                    vy1 = p_gs->gly[gcy] ;
1384                } else {
1385                    /* end of edge, so get exact value */
1386                    vx1 = vtxb[X] ;
1387                    vy1 = vtxb[Y] ;
1388                }
1389
1390                y_flag = TRUE ;
1391            }
1392
1393            /* check for corner crossing, then mark the cell we're in */
1394            if ( !AddGridRecAlloc( p_gc, vx0, vy0, vx1, vy1, eps ) ) {
1395                /* warning, danger - we have just crossed a corner.
1396                 * There are all kinds of topological messiness we could
1397                 * do to get around this case, but they're a headache.
1398                 * The simplest recovery is just to change the extents a bit
1399                 * and redo the meshing, so that hopefully no edges will
1400                 * perfectly cross a corner.  Since it's a preprocess, we
1401                 * don't care too much about the time to do it.
1402                 */
1403
1404                /* clean out all grid records */
1405                for ( i = 0, p_gc = p_gs->gc
1406                    ; i < p_gs->tot_cells
1407                    ; i++, p_gc++ ) {
1408
1409                    if ( p_gc->gr ) {
1410                        free( p_gc->gr ) ;
1411                    }
1412                }
1413
1414                /* make the bounding box ever so slightly larger, hopefully
1415                 * changing the alignment of the corners.
1416                 */
1417                p_gs->minx -= EPSILON * gxdiff * 0.24 ;
1418                p_gs->miny -= EPSILON * gydiff * 0.10 ;
1419
1420                /* yes, it's the dreaded goto - run in fear for your lives! */
1421                goto TryAgain ;
1422            }
1423
1424            if ( t_near < tmax ) {
1425                /* note how we're entering the next cell */
1426                /* TBD: could be done faster by incrementing index in the
1427                 * incrementing code, above */
1428                p_gc = &p_gs->gc[gcy*p_gs->xres+gcx] ;
1429
1430                if ( y_flag ) {
1431                    p_gc->gc_flags |= GC_B_EDGE_HIT ;
1432                    /* this toggles the parity bit */
1433                    p_gc->gc_flags ^= GC_B_EDGE_PARITY ;
1434                } else {
1435                    p_gc->gc_flags |=
1436                        ( sign_x > 0 ) ? GC_L_EDGE_HIT : GC_R_EDGE_HIT ;
1437                }
1438            }
1439
1440            vx0 = vx1 ;
1441            vy0 = vy1 ;
1442        }
1443        /* have we gone further than the end of the edge? */
1444        while ( t_near < tmax ) ;
1445
1446        NextEdge:
1447        vtx0 = vtx1 ;
1448    }
1449
1450    /* the grid is all set up, now set up the inside/outside value of each
1451     * corner.
1452     */
1453    p_gc = p_gs->gc ;
1454    p_ngc = &p_gs->gc[p_gs->xres] ;
1455
1456    /* we know the bottom and top rows are all outside, so no flag is set */
1457    for ( i = 1; i < p_gs->yres ; i++ ) {
1458        /* start outside */
1459        io_state = 0x0 ;
1460
1461        for ( j = 0; j < p_gs->xres ; j++ ) {
1462
1463            if ( io_state ) {
1464                /* change cell left corners to inside */
1465                p_gc->gc_flags |= GC_TL_IN ;
1466                p_ngc->gc_flags |= GC_BL_IN ;
1467            }
1468
1469            if ( p_gc->gc_flags & GC_T_EDGE_PARITY ) {
1470                io_state = !io_state ;
1471            }
1472
1473            if ( io_state ) {
1474                /* change cell right corners to inside */
1475                p_gc->gc_flags |= GC_TR_IN ;
1476                p_ngc->gc_flags |= GC_BR_IN ;
1477            }
1478
1479            p_gc++ ;
1480            p_ngc++ ;
1481        }
1482    }
1483
1484    p_gc = p_gs->gc ;
1485    for ( i = 0; i < p_gs->tot_cells ; i++ ) {
1486
1487        /* reverse parity of edge clear (1==edge clear) */
1488        gc_clear_flags = p_gc->gc_flags ^ GC_ALL_EDGE_CLEAR ;
1489        if ( gc_clear_flags & GC_L_EDGE_CLEAR ) {
1490            p_gc->gc_flags |= GC_AIM_L ;
1491        } else
1492        if ( gc_clear_flags & GC_B_EDGE_CLEAR ) {
1493            p_gc->gc_flags |= GC_AIM_B ;
1494        } else
1495        if ( gc_clear_flags & GC_R_EDGE_CLEAR ) {
1496            p_gc->gc_flags |= GC_AIM_R ;
1497        } else
1498        if ( gc_clear_flags & GC_T_EDGE_CLEAR ) {
1499            p_gc->gc_flags |= GC_AIM_T ;
1500        } else {
1501            /* all edges have something on them, do full test */
1502            p_gc->gc_flags |= GC_AIM_C ;
1503        }
1504        p_gc++ ;
1505    }
1506}
1507
1508int AddGridRecAlloc( p_gc, xa, ya, xb, yb, eps )
1509pGridCell       p_gc ;
1510double  xa,ya,xb,yb,eps ;
1511{
1512pGridRec        p_gr ;
1513double          slope, inv_slope ;
1514
1515    if ( Near(ya, yb, eps) ) {
1516        if ( Near(xa, xb, eps) ) {
1517            /* edge is 0 length, so get rid of it */
1518            return( FALSE ) ;
1519        } else {
1520            /* horizontal line */
1521            slope = HUGE ;
1522            inv_slope = 0.0 ;
1523        }
1524    } else {
1525        if ( Near(xa, xb, eps) ) {
1526            /* vertical line */
1527            slope = 0.0 ;
1528            inv_slope = HUGE ;
1529        } else {
1530            slope = (xb-xa)/(yb-ya) ;
1531            inv_slope = (yb-ya)/(xb-xa) ;
1532        }
1533    }
1534
1535    p_gc->tot_edges++ ;
1536    if ( p_gc->tot_edges <= 1 ) {
1537        p_gc->gr = (pGridRec)malloc( sizeof(GridRec) ) ;
1538    } else {
1539        p_gc->gr = (pGridRec)realloc( p_gc->gr,
1540                p_gc->tot_edges * sizeof(GridRec) ) ;
1541    }
1542    MALLOC_CHECK( p_gc->gr ) ;
1543    p_gr = &p_gc->gr[p_gc->tot_edges-1] ;
1544
1545    p_gr->slope = slope ;
1546    p_gr->inv_slope = inv_slope ;
1547
1548    p_gr->xa = xa ;
1549    p_gr->ya = ya ;
1550    if ( xa <= xb ) {
1551        p_gr->minx = xa ;
1552        p_gr->maxx = xb ;
1553    } else {
1554        p_gr->minx = xb ;
1555        p_gr->maxx = xa ;
1556    }
1557    if ( ya <= yb ) {
1558        p_gr->miny = ya ;
1559        p_gr->maxy = yb ;
1560    } else {
1561        p_gr->miny = yb ;
1562        p_gr->maxy = ya ;
1563    }
1564
1565    /* P2 - P1 */
1566    p_gr->ax = xb - xa ;
1567    p_gr->ay = yb - ya ;
1568
1569    return( TRUE ) ;
1570}
1571
1572/* Test point against grid and edges in the cell (if any).  Algorithm:
1573 *    Check bounding box; if outside then return.
1574 *    Check cell point is inside; if simple inside or outside then return.
1575 *    Find which edge or corner is considered to be the best for testing and
1576 *        send a test ray towards it, counting the crossings.  Add in the
1577 *        state of the edge or corner the ray went to and so determine the
1578 *        state of the point (inside or outside).
1579 */
1580int GridTest( p_gs, point )
1581register pGridSet       p_gs ;
1582double  point[2] ;
1583{
1584int     j, count, init_flag ;
1585pGridCell       p_gc ;
1586pGridRec        p_gr ;
1587double  tx, ty, xcell, ycell, bx,by,cx,cy, cornerx, cornery ;
1588double  alpha, beta, denom ;
1589unsigned short  gc_flags ;
1590int     inside_flag ;
1591
1592    /* first, is point inside bounding rectangle? */
1593    if ( ( ty = point[Y] ) < p_gs->miny ||
1594         ty >= p_gs->maxy ||
1595         ( tx = point[X] ) < p_gs->minx ||
1596         tx >= p_gs->maxx ) {
1597
1598        /* outside of box */
1599        inside_flag = FALSE ;
1600    } else {
1601
1602        /* what cell are we in? */
1603        ycell = ( ty - p_gs->miny ) * p_gs->inv_ydelta ;
1604        xcell = ( tx - p_gs->minx ) * p_gs->inv_xdelta ;
1605        p_gc = &p_gs->gc[((int)ycell)*p_gs->xres + (int)xcell] ;
1606
1607        /* is cell simple? */
1608        count = p_gc->tot_edges ;
1609        if ( count ) {
1610            /* no, so find an edge which is free. */
1611            gc_flags = p_gc->gc_flags ;
1612            p_gr = p_gc->gr ;
1613            switch( gc_flags & GC_AIM ) {
1614            case GC_AIM_L:
1615                /* left edge is clear, shoot X- ray */
1616                /* note - this next statement requires that GC_BL_IN is 1 */
1617                inside_flag = gc_flags & GC_BL_IN ;
1618                for ( j = count+1 ; --j ; p_gr++ ) {
1619                    /* test if y is between edges */
1620                    if ( ty >= p_gr->miny && ty < p_gr->maxy ) {
1621                        if ( tx > p_gr->maxx ) {
1622                            inside_flag = !inside_flag ;
1623                        } else if ( tx > p_gr->minx ) {
1624                            /* full computation */
1625                            if ( ( p_gr->xa -
1626                                ( p_gr->ya - ty ) * p_gr->slope ) < tx ) {
1627                                inside_flag = !inside_flag ;
1628                            }
1629                        }
1630                    }
1631                }
1632                break ;
1633
1634            case GC_AIM_B:
1635                /* bottom edge is clear, shoot Y+ ray */
1636                /* note - this next statement requires that GC_BL_IN is 1 */
1637                inside_flag = gc_flags & GC_BL_IN ;
1638                for ( j = count+1 ; --j ; p_gr++ ) {
1639                    /* test if x is between edges */
1640                    if ( tx >= p_gr->minx && tx < p_gr->maxx ) {
1641                        if ( ty > p_gr->maxy ) {
1642                            inside_flag = !inside_flag ;
1643                        } else if ( ty > p_gr->miny ) {
1644                            /* full computation */
1645                            if ( ( p_gr->ya - ( p_gr->xa - tx ) *
1646                                    p_gr->inv_slope ) < ty ) {
1647                                inside_flag = !inside_flag ;
1648                            }
1649                        }
1650                    }
1651                }
1652                break ;
1653
1654            case GC_AIM_R:
1655                /* right edge is clear, shoot X+ ray */
1656                inside_flag = (gc_flags & GC_TR_IN) ? 1 : 0 ;
1657
1658                /* TBD: Note, we could have sorted the edges to be tested
1659                 * by miny or somesuch, and so be able to cut testing
1660                 * short when the list's miny > point.y .
1661                 */
1662                for ( j = count+1 ; --j ; p_gr++ ) {
1663                    /* test if y is between edges */
1664                    if ( ty >= p_gr->miny && ty < p_gr->maxy ) {
1665                        if ( tx <= p_gr->minx ) {
1666                            inside_flag = !inside_flag ;
1667                        } else if ( tx <= p_gr->maxx ) {
1668                            /* full computation */
1669                            if ( ( p_gr->xa -
1670                                ( p_gr->ya - ty ) * p_gr->slope ) >= tx ) {
1671                                inside_flag = !inside_flag ;
1672                            }
1673                        }
1674                    }
1675                }
1676                break ;
1677
1678            case GC_AIM_T:
1679                /* top edge is clear, shoot Y+ ray */
1680                inside_flag = (gc_flags & GC_TR_IN) ? 1 : 0 ;
1681                for ( j = count+1 ; --j ; p_gr++ ) {
1682                    /* test if x is between edges */
1683                    if ( tx >= p_gr->minx && tx < p_gr->maxx ) {
1684                        if ( ty <= p_gr->miny ) {
1685                            inside_flag = !inside_flag ;
1686                        } else if ( ty <= p_gr->maxy ) {
1687                            /* full computation */
1688                            if ( ( p_gr->ya - ( p_gr->xa - tx ) *
1689                                    p_gr->inv_slope ) >= ty ) {
1690                                inside_flag = !inside_flag ;
1691                            }
1692                        }
1693                    }
1694                }
1695                break ;
1696
1697            case GC_AIM_C:
1698                /* no edge is clear, bite the bullet and test
1699                 * against the bottom left corner.
1700                 * We use Franklin Antonio's algorithm (Graphics Gems III).
1701                 */
1702                /* TBD: Faster yet might be to test against the closest
1703                 * corner to the cell location, but our hope is that we
1704                 * rarely need to do this testing at all.
1705                 */
1706                inside_flag = ((gc_flags & GC_BL_IN) == GC_BL_IN) ;
1707                init_flag = TRUE ;
1708
1709                /* get lower left corner coordinate */
1710                cornerx = p_gs->glx[(int)xcell] ;
1711                cornery = p_gs->gly[(int)ycell] ;
1712                for ( j = count+1 ; --j ; p_gr++ ) {
1713
1714                    /* quick out test: if test point is
1715                     * less than minx & miny, edge cannot overlap.
1716                     */
1717                    if ( tx >= p_gr->minx && ty >= p_gr->miny ) {
1718
1719                        /* quick test failed, now check if test point and
1720                         * corner are on different sides of edge.
1721                         */
1722                        if ( init_flag ) {
1723                            /* Compute these at most once for test */
1724                            /* P3 - P4 */
1725                            bx = tx - cornerx ;
1726                            by = ty - cornery ;
1727                            init_flag = FALSE ;
1728                        }
1729                        denom = p_gr->ay * bx - p_gr->ax * by ;
1730                        if ( denom != 0.0 ) {
1731                            /* lines are not collinear, so continue */
1732                            /* P1 - P3 */
1733                            cx = p_gr->xa - tx ;
1734                            cy = p_gr->ya - ty ;
1735                            alpha = by * cx - bx * cy ;
1736                            if ( denom > 0.0 ) {
1737                                if ( alpha < 0.0 || alpha >= denom ) {
1738                                    /* test edge not hit */
1739                                    goto NextEdge ;
1740                                }
1741                                beta = p_gr->ax * cy - p_gr->ay * cx ;
1742                                if ( beta < 0.0 || beta >= denom ) {
1743                                    /* polygon edge not hit */
1744                                    goto NextEdge ;
1745                                }
1746                            } else {
1747                                if ( alpha > 0.0 || alpha <= denom ) {
1748                                    /* test edge not hit */
1749                                    goto NextEdge ;
1750                                }
1751                                beta = p_gr->ax * cy - p_gr->ay * cx ;
1752                                if ( beta > 0.0 || beta <= denom ) {
1753                                    /* polygon edge not hit */
1754                                    goto NextEdge ;
1755                                }
1756                            }
1757                            inside_flag = !inside_flag ;
1758                        }
1759
1760                    }
1761                    NextEdge: ;
1762                }
1763                break ;
1764            }
1765        } else {
1766            /* simple cell, so if lower left corner is in,
1767             * then cell is inside.
1768             */
1769            inside_flag = p_gc->gc_flags & GC_BL_IN ;
1770        }
1771    }
1772
1773    return( inside_flag ) ;
1774}
1775
1776void GridCleanup( p_gs )
1777pGridSet        p_gs ;
1778{
1779int     i ;
1780pGridCell       p_gc ;
1781
1782    for ( i = 0, p_gc = p_gs->gc
1783        ; i < p_gs->tot_cells
1784        ; i++, p_gc++ ) {
1785
1786        if ( p_gc->gr ) {
1787            free( p_gc->gr ) ;
1788        }
1789    }
1790    free( p_gs->glx ) ;
1791    free( p_gs->gly ) ;
1792    free( p_gs->gc ) ;
1793}
1794
1795/* ======= Exterior (convex only) algorithm =============================== */
1796
1797/* Test the edges of the convex polygon against the point.  If the point is
1798 * outside any edge, the point is outside the polygon.
1799 *
1800 * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices,
1801 * which returns a pointer to a plane set array.
1802 * Call testing procedure with a pointer to this array, _numverts_, and
1803 * test point _point_, returns 1 if inside, 0 if outside.
1804 * Call cleanup with pointer to plane set array to free space.
1805 *
1806 * RANDOM can be defined for this test.
1807 * CONVEX must be defined for this test; it is not usable for general polygons.
1808 */
1809
1810#ifdef  CONVEX
1811/* make exterior plane set */
1812pPlaneSet ExteriorSetup( pgon, numverts )
1813double  pgon[][2] ;
1814int     numverts ;
1815{
1816int     p1, p2, flip_edge ;
1817pPlaneSet       pps, pps_return ;
1818#ifdef  RANDOM
1819int     i, ind ;
1820PlaneSet        ps_temp ;
1821#endif
1822
1823    pps = pps_return =
1824            (pPlaneSet)malloc( numverts * sizeof( PlaneSet )) ;
1825    MALLOC_CHECK( pps ) ;
1826
1827    /* take cross product of vertex to find handedness */
1828    flip_edge = (pgon[0][X] - pgon[1][X]) * (pgon[1][Y] - pgon[2][Y] ) >
1829                (pgon[0][Y] - pgon[1][Y]) * (pgon[1][X] - pgon[2][X] ) ;
1830
1831    /* Generate half-plane boundary equations now for faster testing later.
1832     * vx & vy are the edge's normal, c is the offset from the origin.
1833     */
1834    for ( p1 = numverts-1, p2 = 0 ; p2 < numverts ; p1 = p2, p2++, pps++ ) {
1835        pps->vx = pgon[p1][Y] - pgon[p2][Y] ;
1836        pps->vy = pgon[p2][X] - pgon[p1][X] ;
1837        pps->c = pps->vx * pgon[p1][X] + pps->vy * pgon[p1][Y] ;
1838
1839        /* check sense and reverse plane edge if need be */
1840        if ( flip_edge ) {
1841            pps->vx = -pps->vx ;
1842            pps->vy = -pps->vy ;
1843            pps->= -pps->c ;
1844        }
1845    }
1846
1847#ifdef  RANDOM
1848    /* Randomize the order of the edges to improve chance of early out */
1849    /* There are better orders, but the default order is the worst */
1850    for ( i = 0, pps = pps_return
1851        ; i < numverts
1852        ; i++ ) {
1853
1854        ind = (int)(RAN01() * numverts ) ;
1855        if ( ( ind < 0 ) || ( ind >= numverts ) ) {
1856            fprintf( stderr,
1857                "Yikes, the random number generator is returning values\n" ) ;
1858            fprintf( stderr,
1859                "outside the range [0.0,1.0), so please fix the code!\n" ) ;
1860            ind = 0 ;
1861        }
1862
1863        /* swap edges */
1864        ps_temp = *pps ;
1865        *pps = pps_return[ind] ;
1866        pps_return[ind] = ps_temp ;
1867    }
1868#endif
1869
1870    return( pps_return ) ;
1871}
1872
1873/* Check point for outside of all planes */
1874/* note that we don't need "pgon", since it's been processed into
1875 * its corresponding PlaneSet.
1876 */
1877int ExteriorTest( p_ext_set, numverts, point )
1878pPlaneSet       p_ext_set ;
1879int     numverts ;
1880double  point[2] ;
1881{
1882register PlaneSet       *pps ;
1883register int    p0 ;
1884register double tx, ty ;
1885int     inside_flag ;
1886
1887    tx = point[X] ;
1888    ty = point[Y] ;
1889
1890    for ( p0 = numverts+1, pps = p_ext_set ; --p0 ; pps++ ) {
1891
1892        /* test if the point is outside this edge */
1893        if ( pps->vx * tx + pps->vy * ty > pps->c ) {
1894            return( 0 ) ;
1895        }
1896    }
1897    /* if we make it to here, we were inside all edges */
1898    return( 1 ) ;
1899}
1900
1901void ExteriorCleanup( p_ext_set )
1902pPlaneSet       p_ext_set ;
1903{
1904    free( p_ext_set ) ;
1905}
1906#endif
1907
1908/* ======= Inclusion (convex only) algorithm ============================== */
1909
1910/* Create an efficiency structure (see Preparata) for the convex polygon which
1911 * allows binary searching to find which edge to test the point against.  This
1912 * algorithm is O(log n).
1913 *
1914 * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices,
1915 * which returns a pointer to an inclusion anchor structure.
1916 * Call testing procedure with a pointer to this structure and test point
1917 * _point_, returns 1 if inside, 0 if outside.
1918 * Call cleanup with pointer to inclusion anchor structure to free space.
1919 *
1920 * CONVEX must be defined for this test; it is not usable for general polygons.
1921 */
1922
1923#ifdef  CONVEX
1924/* make inclusion wedge set */
1925pInclusionAnchor InclusionSetup( pgon, numverts )
1926double  pgon[][2] ;
1927int     numverts ;
1928{
1929int     pc, p1, p2, flip_edge ;
1930double  ax,ay, qx,qy, wx,wy, len ;
1931pInclusionAnchor pia ;
1932pInclusionSet   pis ;
1933
1934    /* double the first edge to avoid needing modulo during test search */
1935    pia = (pInclusionAnchor)malloc( sizeof( InclusionAnchor )) ;
1936    MALLOC_CHECK( pia ) ;
1937    pis = pia->pis =
1938            (pInclusionSet)malloc( (numverts+1) * sizeof( InclusionSet )) ;
1939    MALLOC_CHECK( pis ) ;
1940
1941    pia->hi_start = numverts - 1 ;
1942
1943    /* get average point to make wedges from */
1944    qx = qy = 0.0 ;
1945    for ( p2 = 0 ; p2 < numverts ; p2++ ) {
1946        qx += pgon[p2][X] ;
1947        qy += pgon[p2][Y] ;
1948    }
1949    pia->qx = qx /= (double)numverts ;
1950    pia->qy = qy /= (double)numverts ;
1951
1952    /* take cross product of vertex to find handedness */
1953    pia->flip_edge = flip_edge =
1954                (pgon[0][X] - pgon[1][X]) * (pgon[1][Y] - pgon[2][Y] ) >
1955                (pgon[0][Y] - pgon[1][Y]) * (pgon[1][X] - pgon[2][X] ) ;
1956
1957
1958    ax = pgon[0][X] - qx ;
1959    ay = pgon[0][Y] - qy ;
1960    len = sqrt( ax * ax + ay * ay ) ;
1961    if ( len == 0.0 ) {
1962        fprintf( stderr, "sorry, polygon for inclusion test is defective\n" ) ;
1963        exit(1) ;
1964    }
1965    pia->ax = ax /= len ;
1966    pia->ay = ay /= len ;
1967
1968    /* loop through edges, and double last edge */
1969    for ( pc = p1 = 0, p2 = 1
1970        ; pc <= numverts
1971        ; pc++, p1 = p2, p2 = (++p2)%numverts, pis++ ) {
1972
1973        /* wedge border */
1974        wx = pgon[p1][X] - qx ;
1975        wy = pgon[p1][Y] - qy ;
1976        len = sqrt( wx * wx + wy * wy ) ;
1977        wx /= len ;
1978        wy /= len ;
1979
1980        /* cosine of angle from anchor border to wedge border */
1981        pis->dot = ax * wx + ay * wy ;
1982        /* sign from cross product */
1983        if ( ( ax * wy > ay * wx ) == flip_edge ) {
1984            pis->dot = -2.0 - pis->dot ;
1985        }
1986
1987        /* edge */
1988        pis->ex = pgon[p1][Y] - pgon[p2][Y] ;
1989        pis->ey = pgon[p2][X] - pgon[p1][X] ;
1990        pis->ec = pis->ex * pgon[p1][X] + pis->ey * pgon[p1][Y] ;
1991
1992        /* check sense and reverse plane eqns if need be */
1993        if ( flip_edge ) {
1994            pis->ex = -pis->ex ;
1995            pis->ey = -pis->ey ;
1996            pis->ec = -pis->ec ;
1997        }
1998    }
1999    /* set first angle a little > 1.0 and last < -3.0 just to be safe. */
2000    pia->pis[0].dot = -3.001 ;
2001    pia->pis[numverts].dot = 1.001 ;
2002
2003    return( pia ) ;
2004}
2005
2006/* Find wedge point is in by binary search, then test wedge */
2007int InclusionTest( pia, point )
2008pInclusionAnchor        pia ;
2009double  point[2] ;
2010{
2011register double tx, ty, len, dot ;
2012int     inside_flag, lo, hi, ind ;
2013pInclusionSet   pis ;
2014
2015    tx = point[X] - pia->qx ;
2016    ty = point[Y] - pia->qy ;
2017    len = sqrt( tx * tx + ty * ty ) ;
2018    /* check if point is exactly at anchor point (which is inside polygon) */
2019    if ( len == 0.0 ) return( 1 ) ;
2020    tx /= len ;
2021    ty /= len ;
2022
2023    /* get dot product for searching */
2024    dot = pia->ax * tx + pia->ay * ty ;
2025    if ( ( pia->ax * ty > pia->ay * tx ) == pia->flip_edge ) {
2026        dot = -2.0 - dot ;
2027    }
2028
2029    /* binary search through angle list and find matching angle pair */
2030    lo = 0 ;
2031    hi = pia->hi_start ;
2032    while ( lo <= hi ) {
2033        ind = (lo+hi)/ 2 ;
2034        if ( dot < pia->pis[ind].dot ) {
2035            hi = ind - 1 ;
2036        } else if ( dot > pia->pis[ind+1].dot ) {
2037            lo = ind + 1 ;
2038        } else {
2039            goto Foundit ;
2040        }
2041    }
2042    /* should never reach here, but just in case... */
2043    fprintf( stderr,
2044            "Hmmm, something weird happened - bad dot product %lg\n", dot);
2045
2046    Foundit:
2047
2048    /* test if the point is outside the wedge's exterior edge */
2049    pis = &pia->pis[ind] ;
2050    inside_flag = ( pis->ex * point[X] + pis->ey * point[Y] <= pis->ec ) ;
2051
2052    return( inside_flag ) ;
2053}
2054
2055void InclusionCleanup( p_inc_anchor )
2056pInclusionAnchor p_inc_anchor ;
2057{
2058    free( p_inc_anchor->pis ) ;
2059    free( p_inc_anchor ) ;
2060}
2061#endif
2062
2063
2064/* ======= Crossings Multiply algorithm =================================== */
2065
2066/*
2067 * This version is usually somewhat faster than the original published in
2068 * Graphics Gems IV; by turning the division for testing the X axis crossing
2069 * into a tricky multiplication test this part of the test became faster,
2070 * which had the additional effect of making the test for "both to left or
2071 * both to right" a bit slower for triangles than simply computing the
2072 * intersection each time.  The main increase is in triangle testing speed,
2073 * which was about 15% faster; all other polygon complexities were pretty much
2074 * the same as before.  On machines where division is very expensive (not the
2075 * case on the HP 9000 series on which I tested) this test should be much
2076 * faster overall than the old code.  Your mileage may (in fact, will) vary,
2077 * depending on the machine and the test data, but in general I believe this
2078 * code is both shorter and faster.  This test was inspired by unpublished
2079 * Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson.
2080 * Related work by Samosky is in:
2081 *
2082 * Samosky, Joseph, "SectionView: A system for interactively specifying and
2083 * visualizing sections through three-dimensional medical image data",
2084 * M.S. Thesis, Department of Electrical Engineering and Computer Science,
2085 * Massachusetts Institute of Technology, 1993.
2086 *
2087 */
2088
2089/* Shoot a test ray along +X axis.  The strategy is to compare vertex Y values
2090 * to the testing point's Y and quickly discard edges which are entirely to one
2091 * side of the test ray.  Note that CONVEX and WINDING code can be added as
2092 * for the CrossingsTest() code; it is left out here for clarity.
2093 *
2094 * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
2095 * _point_, returns 1 if inside, 0 if outside.
2096 */
2097int CrossingsMultiplyTest( pgon, numverts, point )
2098double  pgon[][2] ;
2099int     numverts ;
2100double  point[2] ;
2101{
2102register int    j, yflag0, yflag1, inside_flag ;
2103register double ty, tx, *vtx0, *vtx1 ;
2104
2105    tx = point[X] ;
2106    ty = point[Y] ;
2107
2108    vtx0 = pgon[numverts-1] ;
2109    /* get test bit for above/below X axis */
2110    yflag0 = ( vtx0[Y] >= ty ) ;
2111    vtx1 = pgon[0] ;
2112
2113    inside_flag = 0 ;
2114    for ( j = numverts+1 ; --j ; ) {
2115
2116        yflag1 = ( vtx1[Y] >= ty ) ;
2117        /* Check if endpoints straddle (are on opposite sides) of X axis
2118         * (i.e. the Y's differ); if so, +X ray could intersect this edge.
2119         * The old test also checked whether the endpoints are both to the
2120         * right or to the left of the test point.  However, given the faster
2121         * intersection point computation used below, this test was found to
2122         * be a break-even proposition for most polygons and a loser for
2123         * triangles (where 50% or more of the edges which survive this test
2124         * will cross quadrants and so have to have the X intersection computed
2125         * anyway).  I credit Joseph Samosky with inspiring me to try dropping
2126         * the "both left or both right" part of my code.
2127         */
2128        if ( yflag0 != yflag1 ) {
2129            /* Check intersection of pgon segment with +X ray.
2130             * Note if >= point's X; if so, the ray hits it.
2131             * The division operation is avoided for the ">=" test by checking
2132             * the sign of the first vertex wrto the test point; idea inspired
2133             * by Joseph Samosky's and Mark Haigh-Hutchinson's different
2134             * polygon inclusion tests.
2135             */
2136            if ( ((vtx1[Y]-ty) * (vtx0[X]-vtx1[X]) >=
2137                    (vtx1[X]-tx) * (vtx0[Y]-vtx1[Y])) == yflag1 ) {
2138                inside_flag = !inside_flag ;
2139            }
2140        }
2141
2142        /* Move to the next pair of vertices, retaining info as possible. */
2143        yflag0 = yflag1 ;
2144        vtx0 = vtx1 ;
2145        vtx1 += 2 ;
2146    }
2147
2148    return( inside_flag ) ;
2149}
Note: See TracBrowser for help on using the repository browser.