Raw File
polygon.c
/*
    polygon.c -- as incorporated in
    Gstat, a program for geostatistical modelling, prediction and simulation
    1992, 2003, by Edzer J. Pebesma

    Authors: Edzer J. Pebesma (E.Pebesma@geo.uu.nl)
             Steve Joyce  (steve.joyce@resgeom.slu.se)
             Konstantin Malakhanov (malakhanov@iwwl.rwth-aachen.de)
             
    This code (polygon handling part) was initially written by Edzer J. Pebesma. 
    Edges handling part is originally by Steve Joyce.

    Simplified and merged by Konstantin Malakhanov.

    InPoly function is Written by Joseph O'Rourke, contributions by 
	Min Xu, June 1997.
    Questions to orourke@cs.smith.edu.
    --------------------------------------------------------------------
    InPoly is Copyright 1998 by Joseph O'Rourke.  It may be freely 
    redistributed in its entirety provided that this copyright notice is 
    not removed.
    --------------------------------------------------------------------

    Edzer J. Pebesma (e.pebesma@geo.uu.nl)
    Department of physical geography, Utrecht University
    P.O. Box 80.115, 3508 TC Utrecht, The Netherlands

    Steve Joyce                            mailto:steve.joyce@resgeom.slu.se
    Remote Sensing Laboratory                 http://www.resgeom.slu.se
    Dept. of Forest Resource Mgmt. & Geomatics          Tel: +46 90 16 69 57
    Swedish University of Agricultural Sciences         Fax: +46 90 14 19 15 
    S-901 83 Umeĺ, Sweden
    
    Konstantin Malakhanov
    Institut for Hydraulic Engineering & Groundwater Mgmt., 
    RWTH Aachen, Germany,

    --------------------------------------------------------------------
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    (read also the files COPYING and Copyright) */

/*
 * polygon.c: point-in-polygon routine, if method=polygon;
 also edges handling for interpolation/simulation.
 Variogram modelling doesn't use this yet.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "defs.h"
#include "data.h"
#include "utils.h"
#include "debug.h"
#include "userio.h"
#include "read.h"
#include "polygon.h"
#include "glvars.h"

/* masks  segment crossing codes - based on SPJ */

#define CROSS   0x01
#define SPOINT1 0x02
#define SPOINT2 0x04
#define EPOINT1 0x08
#define EPOINT2 0x10

/* point-to-segment, point-to-polygon relations */
#define POLY_IN  0x01
#define POLY_OUT 0x02
#define POLY_EDGE (POLY_IN|POLY_OUT)
#define IWW 1

/* for linear combination of coordinates:*/
#define DELTA_AB(_p,_a,_b,_r) (_p).x = (_a).x + (_r) * ((_b).x - (_a).x);\
(_p).y = (_a).y + (_r) * ((_b).y - (_a).y);

static char InPoly(PLOT_POINT q, POLYGON *Poly);
static int CDECL dist_cmp(const DPOINT **ap, const DPOINT **bp);
unsigned char line_of_sight(const PLOT_POINT data, const PLOT_POINT target,
                            const POLYGON *p_obj);
static unsigned int segment_cross_check(PLOT_POINT p1, PLOT_POINT p2, PLOT_POINT p3, PLOT_POINT p4, double *r, double *s);
static unsigned int segment_parallel_check(PLOT_POINT a, PLOT_POINT b, PLOT_POINT c, PLOT_POINT d);
static int segment_between_check(PLOT_POINT a, PLOT_POINT b, PLOT_POINT c);
static unsigned int check_open_edges(const PLOT_POINT data, const int target_side,
                                     const PLOT_POINT target, const POLYGON *p_obj);
static void print_poly_log(POLYGON *edge);

static const char *fname = NULL;
/*------------------------------ POLYGONS ------------------------------*/
POLYGON *read_polygons(const char *filename, int *n_polys, double **iso_values) {
	FILE *f = NULL;
	int i = 0, j,n, line_size = 0, d, np, iww_nl=-1;
	char *line = NULL, *cp;
	POLYGON *pol = NULL;
    double val, *values = NULL;
    
	fname = filename;
	f = efopen(filename, "r");
/*	pol = (POLYGON *) emalloc(sizeof(POLYGON));*/
	get_line(&line, &line_size, f);
	if (strstr(line, "EXP") == line) { /* read arc-info e00 file */
		if ((cp = strchr(line + 7, ' ')) != NULL)
			*cp = '\0';
		cp = line + 7;
		printlog("reading e00 polygon coverage `%s'", cp);
		get_line(&line, &line_size, f); /* ARC  # */
		n = 0;
		while (n >= 0) {
			get_line(&line, &line_size, f);  /* ARC  # */
            /* I have no examples where ARC comes before EVERY line..*/
			if (sscanf(line, "%d%d%d%d%d%d%d", &n, &d, &d, &d, &d, &d, &np) != 7) 
				pr_warning("cannot read 7 integers from `%s'", line);
			if (n > 0) {
				i++;
				pol = erealloc(pol, i * sizeof(POLYGON));
				pol[i - 1] = read_n_points(f, np);
                /* we do not delete polygons of 2 points, as we are
                   not neccessary reading closed polygons*/
                   
				if (np <= 1) { /* remove the degenerate polygon */
					efree(pol[i - 1].p);
					i--;
				}
			}
		}
	} else { /* read `plot' file */
		printlog("reading plot file `%s'", filename);
		do {
			d=sscanf(line, "%d %lf", &np,&val);
            if (d==0 || d==EOF) {
#ifdef IWW            
                if (i==0 && d==0) { /* try IWW poly/isolines */
                    printlog(" IWW poly/isolines? 7 header lines + number of isolines:\n");
/*                    printlog("%d) %s",1,line) ;*/
                    for (j=1;j<=7;j++)
                    {
                        printlog("%d) %s",j,line) ;
                        if (get_line(&line, &line_size, f) ==NULL) 
                            ErrMsg(ER_READ,filename);
                    }
                    if (sscanf(line, "%d", &iww_nl) !=1)
                        ErrMsg(ER_RDINT,line);
                    else
                        continue; /* get next line with np etc.*/
                    
                } else
#endif                
                {
                    pr_warning("file: %s, line without data encountered \n", fname);
                    continue;
                }
            }
            
            if (np<=1) {
                printf(" (polyline size %d encountered)",np);
                continue;
            }
            
			i++;
			pol = erealloc(pol, i * sizeof(POLYGON));

            if (d==2) {
                values = erealloc(values, i * sizeof(double));
                values[i - 1]=val;
            }
            
            
			pol[i - 1] = read_n_points(f, np);
			if (np <= 1) { /* remove the degenerate polygon */
				efree(pol[i - 1].p);
				i--;
			}
		} while (get_line(&line, &line_size, f));
	}
	printlog(", %d polygons read\n", i);
#ifdef    IWW
    if (iww_nl != -1 && iww_nl != i)
        pr_warning("the given number of isolines differs from number of actual loaded.");
#endif
	*n_polys = i;
    if (iso_values)
		*iso_values=values;
    
	efclose(f);
	efree(line);
	return pol;
}

void report_edges(void) {
    int i, j, n, *ip;
    char delim;
    POLYGON **edges;

    delim = (DEBUG_NORMAL || DEBUG_DUMP ? ' ': '\n');
    edges = get_edges();
    if (DEBUG_NORMAL || DEBUG_DUMP || DEBUG_DATA) {
        ip=get_n_edges_polys();
        printlog("edges:");
        for (i = 0; i < get_n_edges(); i++) {
            n=ip[i];
            /* report edge files and number of edges per file */
            printlog("%c %s (%d edge(s))",delim,get_edges_name(i),n); 
            if (! DEBUG_DATA)
            	delim=',';
            
            if (DEBUG_DATA) { /* report every line */
                printlog("\n");
                for (j = 0; j<n; j++) { /*over edges in a file */
                    print_poly_log(&(edges[i][j]));
                }
            }
        }
        if (!DEBUG_DATA) 
        	/* fputc('\n',logfile); */
        	printlog("\n");
    }
}

static void print_poly_log(POLYGON *edge) {
    int i,n=edge->lines;
    printlog("%+d",n);

    /* fputc('\n',a_stream); */
    printlog("\n");

    for (i=0;i<n;i++)
        printlog("%g %g\n",edge->p[i].x,edge->p[i].y);

    /* fflush(a_stream); */
    return;
}

POLYGON read_n_points(FILE *f, int np) {
	static char *line = NULL;
	static int line_size;
	POLYGON pl;
	int n = 0;
	char *cp;

	pl.lines = np; /* check later that first == last */
	pl.p = (PLOT_POINT *) emalloc(np * sizeof(PLOT_POINT));
	while (n < np) {
		get_line(&line, &line_size, f);
        /* pr_warning("file: %s, line '%s' %d\n",fname,line,n); */
		cp = strtok(line, DELIMITERS);
		if (cp == NULL) {
            if (feof(f)) {
                pr_warning("file: %s, not enough data points (%d requested, %d found '%s' )\n", fname, np, n, line);
                ErrMsg(ER_READ, fname);
            } else {
                pr_warning("file: %s, line without data encountered (%d)\n", fname, n+1);
                continue;
            }
		}
		if (read_double(cp, &(pl.p[n].x)))
			ErrMsg(ER_RDFLT, cp);
		cp = strtok(NULL, DELIMITERS);
		if (read_double(cp, &(pl.p[n].y)))
			ErrMsg(ER_RDFLT, cp);
		n++;
		cp = strtok(NULL, DELIMITERS);
		if (cp != NULL) { /* four on a line */
			if (read_double(cp, &(pl.p[n].x)))
				ErrMsg(ER_RDFLT, cp);
			cp = strtok(NULL, DELIMITERS);
			if (read_double(cp, &(pl.p[n].y)))
				ErrMsg(ER_RDFLT, cp);
			n++;
		}
	}
    pl.close = (pl.p[0].x == pl.p[np-1].x && pl.p[0].y == pl.p[np-1].y);
    setup_poly_minmax(&pl);
    
	return pl;
}

int point_in_polygon(PLOT_POINT point, POLYGON *pl)
{
    if ((point.x < pl->mbr.min.x) || (point.x > pl->mbr.max.x) ||
        (point.y < pl->mbr.min.y) || (point.y > pl->mbr.max.y))
        return 0;
    else
        return InPoly(point, pl) != 'o';
    
}

/*
This code is described in "Computational Geometry in C" (Second Edition),
Chapter 7.  It is not written to be comprehensible without the 
explanation in that book.

For each query point q, InPoly returns one of four char's:
	i : q is strictly interior to P
	o : q is strictly exterior to P
	v : q is a vertex of P
	e : q lies on the relative interior of an edge of P
These represent mutually exclusive categories.
For an explanation of the code, see Chapter 7 of 
"Computational Geometry in C (Second Edition)."

Written by Joseph O'Rourke, contributions by Min Xu, June 1997.
Questions to orourke@cs.smith.edu.
--------------------------------------------------------------------
This code is Copyright 1998 by Joseph O'Rourke.  It may be freely 
redistributed in its entirety provided that this copyright notice is 
not removed.
--------------------------------------------------------------------
*/

/*
InPoly returns a char in {i,o,v,e}.  See above for definitions.
*/

static char InPoly(PLOT_POINT q, POLYGON *Poly)
{
    int n = Poly->lines;
    PLOT_POINT *P=Poly->p;
    
    int	 i, i1;      /* point index; i1 = i-1 mod n */
    double x;          /* x intersection of e with ray */
    double xx=q.x, yy=q.y;
    int	 Rcross = 0; /* number of right edge/ray crossings */
    int    Lcross = 0; /* number of left edge/ray crossings */

    /* For each edge e=(i-1,i), see if crosses ray. */
    for( i = 0; i < n; i++ ) {
        /* First see if q=(0,0) is a vertex. */
        if (( P[i].x - xx )==0 &&( P[i].y - yy )==0 ) return 'v';
        i1 = ( i + n - 1 ) % n;
        /* printf("e=(%d,%d)\t", i1, i); */
    
        /* if e "straddles" the x-axis... */
        /* The commented-out statement is logically equivalent to the one 
           following. */
        /* if( ( ( P[i].y > 0 ) && ( P[i1].y <= 0 ) ) ||
           ( ( P[i1].y > 0 ) && ( P[i] .y <= 0 ) ) ) { */
    
        if( (( P[i].y - yy ) > 0 ) != (( P[i1].y - yy ) > 0 ) ) {
      
            /* e straddles ray, so compute intersection with ray. */
            x = (( P[i].x - xx) *( P[i1].y - yy ) -( P[i1].x - xx ) *( P[i].y - yy )) /
                (P[i1].y - P[i].y );
            /* printf("straddles: x = %g\t", x); */
      
            /* crosses ray if strictly positive intersection. */
            if (x > 0) Rcross++;
        }
        /* printf("Right cross=%d\t", Rcross); */
    
        /* if e straddles the x-axis when reversed... */
        /* if( ( ( P[i] .y < 0 ) && ( P[i1].y >= 0 ) ) ||
           ( ( P[i1].y < 0 ) && ( P[i] .y >= 0 ) ) )  { */
    
        if ( (( P[i].y - yy ) < 0 ) != (( P[i1].y - yy ) < 0 ) ) { 
      
            /* e straddles ray, so compute intersection with ray. */
            x = (( P[i].x - xx) *( P[i1].y - yy ) -( P[i1].x - xx ) *( P[i].y - yy )) /
                (P[i1].y - P[i].y);
            /* printf("straddles: x = %g\t", x); */

            /* crosses ray if strictly positive intersection. */
            if (x < 0) Lcross++;
        }
        /* printf("Left cross=%d\n", Lcross); */
    }	
  
    /* q on the edge if left and right cross are not the same parity. */
    if( ( Rcross % 2 ) != (Lcross % 2 ) )
        return 'e';
  
    /* q inside iff an odd number of crossings. */
    if( (Rcross % 2) == 1 )
        return 'i';
    else	return 'o';
}



/*------------------------------ EDGES ------------------------------*/
void read_edges(void) 
{
    int i,n;
    int n_edges /* ,n_edges_total=0 */ ;
    POLYGON **edges;
    int *n_edges_polys;
    
    n = get_n_edges();
    if (n <= 0)
    	return;
    /* get at local */
    /* edges = get_edges(); */
    edges = emalloc(n*sizeof(POLYGON*));
    /* n_edges_polys = get_n_edges_polys(); */
    n_edges_polys = emalloc(n*sizeof(int));

    /* ... read data in .. */
    for (i=0; i<n;  i++) { /* over all files */
        edges[i]=read_polygons(get_edges_name(i),&n_edges, NULL); 
/*         n_edges_total+=n_edges; */
        n_edges_polys[i]=n_edges;
    }
    /* ... and set back */
    set_edges(edges);
    set_n_edges_polys(n_edges_polys);
/*     set_n_edges(n_edges_total); */
    
}

void check_edges(DATA *d, const DPOINT *where) {
#define BAD FLT_MAX    
    /* Goes as follows : in the list d->sel set u.dist2 to
       BAD==FLT_MAX for the points failed through line-of-sight
       test. Then sort d->sel by u.dist2 and decrease d->n_sel by the
       number of points with u.dist2==BAD */
    
    int i,j,n_sel_edges,n;
    int p_i_p_result;
    char InPolyRes;
    int culled;
    unsigned int bad;
    int *n_edges_polys;
    POLYGON **edges;
    POLYGON *current_edge;
    PLOT_POINT p, p_where;
    static POLYGON **sel_edges = NULL;
    static int *point_edge_rel = NULL; 
    static int n_alloc_edges = 0;
    
	n = get_n_edges();
    if (n <= 0) 
		return;
    /* get at local */
    edges = get_edges();
    n_edges_polys = get_n_edges_polys();
    p_where.x=where->x;
    p_where.y=where->y;
    
    /* make a list of all relevant edges */
    n_sel_edges = 0;
    /* find relevant edges and also check if *where is inside/outside
       of edge for closed polynoms or which subdivision *where in for open edges */
    
    for (i=0; i<n; i++) { /* over files */
        for (j=0; j<n_edges_polys[i]; j++) {
            current_edge=&(edges[i][j]);
            
            /* check if edge extents are in vicinity of estimation point */
            /* basically we'll check it if point is in box+sel_rad (on both sides) */ 
            /* from check_edges of SPJ */
            
            if ((where->x > current_edge->mbr.min.x - d->sel_rad)       /*ltx */
                && (where->x  < current_edge->mbr.max.x + d->sel_rad)   /*rbx */
                && (where->y > current_edge->mbr.min.y - d->sel_rad)    /*rby */
                && (where->y  < current_edge->mbr.max.y + d->sel_rad))  /*lty*/
            {
                
#define IN_OUT(_a) ((_a) == 'i' ? POLY_IN : ((_a) == 'o' ? POLY_OUT : POLY_EDGE))

                if (current_edge->close) {
                    InPolyRes=InPoly(p_where, current_edge);
                    p_i_p_result=IN_OUT(InPolyRes);
                    /* don't use, if target on edge */
                    if (p_i_p_result == POLY_EDGE) continue;
                } else { /* do nothing at the moment, any ideas are welcome:
                            malakhanov@iwwl.rwth-aachen.de
                         */
                    p_i_p_result = POLY_IN;
                    
                }
                if (n_sel_edges+1>n_alloc_edges) {
                   n_alloc_edges = n_sel_edges+1;
                   sel_edges      = erealloc(sel_edges,n_alloc_edges*sizeof(POLYGON*));
                   point_edge_rel = erealloc(point_edge_rel,n_alloc_edges*sizeof(int)); 
                }
                
                sel_edges[n_sel_edges]=current_edge;
                point_edge_rel[n_sel_edges]=p_i_p_result;
                n_sel_edges++;       
            }
        }
    }
    if (n_sel_edges==0) 
		return; /* no relevant edges */

    culled=0;

    /* loop over all so far selected points */
    for (i=0; i<d->n_sel; i++) {
        p.x = d->sel[i]->x;
        p.y = d->sel[i]->y;
        
        for (j=0; j<n_sel_edges; j++) { /* over all selected edges */
            if ( sel_edges[j]->close) {
                /* InPolyRes=point_in_polygon(p,  sel_edges[j]); */
                InPolyRes = InPoly(p, sel_edges[j]);
                p_i_p_result = IN_OUT(InPolyRes);
                if (p_i_p_result == POLY_EDGE) continue; 
                bad = (p_i_p_result != point_edge_rel[j]);
            } else {
                /* check line-of-sight between data and target point for this edge */
                bad = check_open_edges(p, point_edge_rel[j], p_where, sel_edges[j]);
            }
            if (bad) {
                d->sel[i]->u.dist2 = BAD;
                culled++;
                break;
            }
        }
    } /* end of loop over all selected points */

    /* now look how bad (good) it was: */
    if (culled == 0) 
		return;
    /* otherwise sort d->sel by dist2 (u.dist2 is smaller then BAD, so it comes out first:*/
    qsort(d->sel, (size_t) d->n_sel, sizeof(DPOINT *),
          (int CDECL (*)(const void *,const void *)) dist_cmp);
    /* and set d->n_sel to the number of GOOD ones */
    d->n_sel -= culled;
    return;
}
#undef IN_OUT
#undef BAD

/* the rest is modified from SPJ: */
unsigned char line_of_sight(const PLOT_POINT data, const PLOT_POINT target,
                            const POLYGON *p_obj) {
    int i;
    unsigned int code;
    unsigned int crossings = 0;
    
	/* go through each segment to find out if it crosses line between data-target */
	for(i=0; i<p_obj->lines-1; i++) { /*we have really lines points */
        code = segment_cross_check(data, target, p_obj->p[i], p_obj->p[i+1], NULL, NULL);

        if (code==CROSS) { /* a simple intersection between data-target and the segment */
            crossings++;
            continue;
        }
        if ((code&SPOINT1) || (code&EPOINT1)) return 0; /* data or target at the edge
                                                           skip this edge completly */
        
	}
    return(crossings);
}

/*
  ----------------------------------------------------------------------
  http://www.cis.ohio-state.edu/hypertext/faq/usenet/graphics/algorithms-faq/faq.html
  Subject 1.03: How do I find intersections of 2 2D line segments?

    This problem can be extremely easy or extremely difficult depends
    on your applications.  If all you want is the intersection point,
    the following should work:

    Let A,B,C,D be 2-space position vectors.  Then the directed line
    segments AB & CD are given by:

        AB=A+r(B-A), r in [0,1]
        CD=C+s(D-C), s in [0,1]

    If AB & CD intersect, then

        A+r(B-A)=C+s(D-C), or

        Ax+r(Bx-Ax)=Cx+s(Dx-Cx)
        Ay+r(By-Ay)=Cy+s(Dy-Cy)  for some r,s in [0,1]

    Solving the above for r and s yields

            (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
        r = -----------------------------  (eqn 1)
            (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)

            (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
        s = -----------------------------  (eqn 2)
            (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)

    Let P be the position vector of the intersection point, then

        P=A+r(B-A) or

        Px=Ax+r(Bx-Ax)
        Py=Ay+r(By-Ay)

    By examining the values of r & s, you can also determine some
    other limiting conditions:

        If 0<=r<=1 & 0<=s<=1, intersection exists
            r<0 or r>1 or s<0 or s>1 line segments do not intersect

        If the denominator in eqn 1 is zero, AB & CD are parallel
        If the numerator in eqn 1 is also zero, AB & CD are coincident

    If the intersection point of the 2 lines are needed (lines in this
    context mean infinite lines) regardless whether the two line
    segments intersect, then

        If r>1, P is located on extension of AB
        If r<0, P is located on extension of BA
        If s>1, P is located on extension of CD
        If s<0, P is located on extension of DC

    Also note that the denominators of eqn 1 & 2 are identical.

    References:

    [O'Rourke (C)] pp. 249-51
[Gems III] pp. 199-202 "Faster Line Segment Intersection,"
*/
static unsigned int segment_cross_check(PLOT_POINT A, PLOT_POINT B, 
		PLOT_POINT C, PLOT_POINT D, double *R, double *S) {
    double uan,ubn,d,r,s;
    unsigned int code = 0;
/* calculates if two line segments cross  and checks if the crossing point is at 
   the start or endpoint of the segments */
    if (B.x == A.x && B.y == A.y) return code;
    
    d = (D.y-C.y)*(B.x-A.x) - (D.x-C.x)*(B.y-A.y);
  

    if (fabs(d)<FLT_MIN)  /* parallel OR coincident*/
        return segment_parallel_check(A,  B,  C,  D);
        
    uan = ((D.x-C.x)*(A.y-C.y) - (D.y-C.y)*(A.x-C.x)); /* for r */
    ubn = ((B.x-A.x)*(A.y-C.y) - (B.y-A.y)*(A.x-C.x)); /* for s */

    r=uan/d;
    s=ubn/d;
    if (R) *R=r;
    if (S) *S=s;
    
    /*  line segments do not intersect between (A,B) & (C,D)*/
    if ((r < 0.0) || (r > 1.0) || (s < 0.0) || (s > 1.0)) return code;
    
    code |= CROSS; /* lines cross somewhere between endpoints */
    
    if (r == 0.0 ) {
        /* intersection at start of segment 1 */
        code |= SPOINT1;
    } else if (r == 1.0) {
        /* cross at endpoint of line 1 */
        code |= EPOINT1;
    }


    if (s == 0.0) {
        /* intersection at start of segment 2 */
        code |= SPOINT2;
    } else if (s == 1.0) {
        /* cross at endpoint of line 2 */
        code |= EPOINT2;
    }
    
    return code;
    
}

/* check special case of lines through (A,B) and (C,D) being parallel */
static unsigned int segment_parallel_check(PLOT_POINT A, PLOT_POINT B, 
		PLOT_POINT C, PLOT_POINT D) {

    unsigned int code = 0;
    /* remember, A- data point, B- target, C - segment start, D -segment end */
    /* first check A,B,C on one line or parallel */
    if ((B.x - A.x)*(C.y - A.y) != (C.x - A.x)*(B.y - A.y))
        return code; /* not on one line, i.e. are parallel */

    if ( segment_between_check( C, D, A ) )  /* data  at polyline */
        code |= SPOINT1;
    
    if ( segment_between_check( C, D, B ) )  /* target  at polyline */
        code |= EPOINT1;
    
    if ( segment_between_check( A, B, C) )  /* data  at polyline */
        code |= SPOINT2;
    
    if ( segment_between_check( A, B, D ) )  /* target  at polyline */
        code |= EPOINT2;
    
    if (code) code|=CROSS;
    
    return code;
    
    
}

/* check the c is between a and b */
static int segment_between_check(PLOT_POINT a, PLOT_POINT b, PLOT_POINT c) {
    if ( a.x != b.x )
        return ((a.x <= c.x) && (c.x <= b.x)) ||
            ((a.x >= c.x) && (c.x >= b.x));
    else
        return ((a.y <= c.y) && (c.y <= b.y)) ||
            ((a.y >= c.y) && (c.y >= b.y));
}

/*
  ----------------------------------------------------------------------
  http://www.cis.ohio-state.edu/hypertext/faq/usenet/graphics/algorithms-faq/faq.html
  Subject 1.02: How do I find the distance from a point to a line?


    Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By).
    The length of the line segment AB is L:

        L= sqrt( (Bx-Ax)^2 + (By-Ay)^2 ) .

    Let P be the point of perpendicular projection of C onto AB.
    Let r be a parameter to indicate P's location along the line
    containing AB, with the following meaning:

          r=0      P = A
          r=1      P = B
          r<0      P is on the backward extension of AB
          r>1      P is on the forward extension of AB
          0<r<1    P is interior to AB

    Compute r with this:

            (Ay-Cy)(Ay-By)-(Ax-Cx)(Bx-Ax)
        r = -----------------------------
                        L^2

    The point P can then be found:

        Px = Ax + r(Bx-Ax)
        Py = Ay + r(By-Ay)

    And the distance from A to P = r*L.

    Use another parameter s to indicate the location along PC, with the 
    following meaning:
           s<0      C is left of AB
           s>0      C is right of AB
           s=0      C is on AB

    Compute s as follows:

            (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
        s = -----------------------------
                        L^2


    Then the distance from C to P = s*L.


*/

static int CDECL dist_cmp(const DPOINT **pa, const DPOINT **pb) {
/* ANSI qsort() conformant dist_cmp */

	if ( (*pa)->u.dist2 < (*pb)->u.dist2 )
		return -1;
	if  ( (*pa)->u.dist2 > (*pb)->u.dist2 )
		return 1;
    return 0;
    
} 

static unsigned int check_open_edges(const PLOT_POINT data, const int target_side,
                                     const PLOT_POINT target, const POLYGON *p_obj) {
    
    int los=line_of_sight(data,target,p_obj);
    
    return (los % 2);
}


void setup_poly_minmax(POLYGON *pl) {
    int i, n=pl->lines;
    double minx,maxx,miny,maxy;
    
    minx=miny=DBL_MAX;
    maxx=maxy=-DBL_MAX;
    
    for (i=0;i<n;i++) {
        minx = MIN(minx, pl->p[i].x);
        miny = MIN(miny, pl->p[i].y);
        maxx = MAX(maxx, pl->p[i].x);
        maxy = MAX(maxy, pl->p[i].y);
    }
    pl->mbr.min.x = minx;
    pl->mbr.min.y = miny;
    pl->mbr.max.x = maxx;
    pl->mbr.max.y = maxy;
}


#undef CROSS  
#undef SPOINT1
#undef SPOINT2
#undef EPOINT1
#undef EPOINT2
#undef POLY_IN 
#undef POLY_OUT
#undef POLY_EDGE
#undef IWW
back to top