#include <stdio.h>
#include <math.h>
#include "grf4.h"

#include "../h/cdefs.h"
#include "chull.h"
#include "../rci/link.h"

int debug = 1;

typedef struct _event {
	struct _event *next;
	struct _event *prev;
#define HIDE_EVENT	1
#define EXPOSE_EVENT	2
	int type;
	float r;
} EVENT;

typedef struct _pedge {
	struct _pedge *next;
	struct _pedge *prev;
	float x, y;
	int visible;

	int intersect;
#define INTO	1
#define OUT	2
	float rInto;
	float rOut;

	EVENT *events;

	  } PEDGE;

typedef struct {
	PEDGE *edges;
	int n;

	float xmax, xmin;
	float ymax, ymin;
	  } SCR_POLYGON;


static setEpsilon();
static void computeCentroid ();
static pointInsidePolygon ();

initBoundingBox(p)
SCR_POLYGON *p;
{
	p->xmin = p->ymin = -1000000;
	p->xmax = p->ymax =  1000000;
}

SCR_POLYGON *randomPolygon();
SCR_POLYGON *specialPolygon();
SCR_POLYGON *fixedPoly2();
SCR_POLYGON *fixedPoly3();
SCR_POLYGON *fixedPoly4();
double frandom();
extern void *malloc();

char **argvec;

#define EPSILON	(1e-5)

PEDGE *edgePool = NULL;

#define P_DONT_INTERSECT	0
#define P_INTERSECT		1
#define P_POLY1_INSIDE		2
#define P_POLY2_INSIDE		3

static float scrEpsilon = EPSILON;

static setEpsilon(w,h)
float w, h;
{
	scrEpsilon = EPSILON*(w+h)*(w+h)/4;
}

PEDGE *newEdge()
{
	PEDGE *pe;
#define EBLKSIZE	512
	if (!edgePool)
	 { int k;
	   edgePool = (PEDGE*)malloc(EBLKSIZE*sizeof(PEDGE));
	   for (k=0; k<EBLKSIZE-1; k++)
	    { edgePool[k].next = &edgePool[k+1];
	    }
	 }
	pe = edgePool;
	pe->intersect = 0;
	edgePool = edgePool->next;
	return (pe);
}

freeEdge(pe)
PEDGE *pe;
{
	pe->next = edgePool;
	edgePool = pe;
}

EVENT* newEvent()
{
	return (EVENT*)calloc(1,sizeof(EVENT));
}

freeEdges(ps,pf)
PEDGE *ps, *pf;
{
	/* assumes that "pe" begins a NULL terminated list of edges */
	pf->next = edgePool;
	edgePool = ps;
}

PEDGE *newEdgeRing(n)
int n;
{
	PEDGE *ph, *pt, *pn;
	int k;

	if (n <= 0)
	 { return(NULL);
	 }
	ph = newEdge();
	ph->visible = 1;
	ph->events = 0;
	pt = ph;
	for (k=1; k<n; k++)
	 { pn = newEdge();
	   pt->next = pn;
	   pn->prev = pt;
	   pn->visible = 1;
	   pt = pn;
	 }
	ph->prev = pt;
	pt->next = ph;
	return (ph);
}

main(argc, argv)
int argc;
char **argv;
{
	int winw, winh, n;
	int cnt;
	int status;
	SCR_POLYGON *p1, *p2;
	PEDGE *fp, *fq, *ee, *ne;
	char *fileName = NULL;
	int doFuzz = 0;

	argvec = argv;

	argc--; argv++;
	while (argc > 0)
	 { if (ARGUMENT("-f"))
	    { argc--; argv++;
	      if (argc < 1)
	       { goto usage;
	       }
	      fileName = *argv;
	    }
	   else if (ARGUMENT("-fuzz"))
	    { doFuzz = 1;
	    }
	   else
	    { goto usage;
	    }
	   argc--; argv++;
	   continue;
usage:
	   fprintf (stderr, "Usage: %s [-f <pointFile>] [-fuzz]\n", argvec[0]);
	   exit(-1);
	 }

	if (fileName)
	 { if (readPointFile(fileName) < 0)
	    { fprintf (stderr, "%s: can't read point file %s\n",
				argvec[0], fileName);
	    }
	 }

	grf4Init (argvec[0], GRF_WHITE, GRF_BLACK, 0);
	grf4GetWindowSize (&winw, &winh);
/*	grf4Ortho (-30.0, 60.0, -30.0, 60.0, -1.0, 1.0, 1.0);*/
/*	setEpsilon((float)winw, (float)winh); */
#if 0
	if (grfXInit (590, 460, 550, 430, 0, &winw, &winh) < 0)
	 { fprintf (stderr, "couldn't init graphics\n");
	   exit (1);
	 }
#endif
	n = 5;
	cnt = 0;
	while (1)
	 { char c;
	   if (!fileName)
	    { PEDGE *ee;
	      p1 = randomPolygon(1.0,1.0,winw-2.0,winh-2.0,n);
	      p2 = randomPolygon(1.0,1.0,winw-2.0,winh-2.0,n);
	      printf ("p1: ");
	      ee = p1->edges;
	      do
	       { printf ("(%g %g) ", ee->x, ee->y);
		 ee = ee->prev;
	       }
	      while (ee != p1->edges);
	      printf ("\n");
	      printf ("p2: ");
	      ee = p2->edges;
	      do
	       { printf ("(%g %g) ", ee->x, ee->y);
		 ee = ee->prev;
	       }
	      while (ee != p2->edges);
	      printf ("\n");
	    }
	   else
	    { p1 = specialPolygon();
	      p2 = specialPolygon();

	      if (doFuzz && cnt > 2)
	       { fuzzPolygon(p1);
		 fuzzPolygon(p2);
	       }
	    }

	   cnt++;
	   grf4Clear();
	   printf ("---\n");
	   status = intrsectPolygons(p1,p2,1,&fp,&fq,0,0);
#if 1
	   
	   if (status)
	    { if (status == P_INTERSECT)
	       { printf ("intersect\n");
/*		 cutPolygon(p2,fq); */
	       }
	      else if (status == P_POLY1_INSIDE)
	       { printf ("poly1 inside\n");
	       }
	      else if (status == P_POLY2_INSIDE)
	       { PEDGE *ee;
		 printf ("poly2 inside\n");
		 ee = p2->edges;
		 do
		  { ee->visible = 0;
		    ee = ee->next;
		  }
		 while (ee != p2->edges);
	       }
	    }
	   else
	    { printf ("no intersection\n");
	    }
#endif
	   drawPoly(p1);
	   drawPoly(p2);
	   grf4Flush();
	   grf4Cycle();

#if 1
	   while ((c=getchar()) != '\n')
	    { if (c >= '3' && c <= '9')
	       { n = c-'0';
	       }
	    }
#endif
	   freePolygon(p1);
	   freePolygon(p2);
	 }
}

drawX(x,y)
float x, y;
{
	grf4Move2(x-5,y-5);
	grf4Draw2(x+5,y+5);
	grf4Move2(x-5,y+5);
	grf4Draw2(x+5,y-5);
}

drawBox(x,y)
float x, y;
{
	grf4Move2(x-5,y-5);
	grf4Draw2(x-5,y+5);
	grf4Draw2(x+5,y+5);
	grf4Draw2(x+5,y-5);
	grf4Draw2(x-5,y-5);
}

freePolygon(p)
SCR_POLYGON *p;
{
	p->edges->prev->next = 0;
	freeEdges(p->edges,p->edges->prev);
	FREE(p);
}

drawPoly(p)
SCR_POLYGON *p;
{
	PEDGE *e;

	grf4Move2 (p->edges->x, p->edges->y);
	for (e = p->edges->next; e != p->edges; e = e->next)
	 { if (e->visible)
	    { grf4Draw2 (e->x, e->y);
	    }
	   else
	    { grf4Move2 (e->x, e->y);
	    }
	 }
	if (e->visible) grf4Draw2 (e->x, e->y);
}

SCR_POLYGON *fixedPoly3()
{
	SCR_POLYGON *p;
	PEDGE *e, *last_e;

	p = ALLOC(SCR_POLYGON);

	p->n = 3;

	p->edges = newEdgeRing(p->n);

	p->edges[2].x = 50.0;
	p->edges[2].y = 50.0;

	p->edges[1].x = 150.0;
	p->edges[1].y = 50.0;

	p->edges[0].x = 150.0;
	p->edges[0].y = 100.0;

	initBoundingBox(p);

	return (p);
}

SCR_POLYGON *fixedPoly4()
{
	SCR_POLYGON *p;
	PEDGE *e, *last_e;

	p = ALLOC(SCR_POLYGON);

	p->n = 4;

	p->edges = newEdgeRing(p->n);

	p->edges[3].x = 75.0;
	p->edges[3].y = 25.0;

	p->edges[2].x = 125.0;
	p->edges[2].y = 25.0;

	p->edges[1].x = 125.0;
	p->edges[1].y = 100.0;

	p->edges[0].x = 75.0;
	p->edges[0].y = 100.0;
				
	initBoundingBox(p);

	return (p);
}


SCR_POLYGON *fixedPoly2()
{
	SCR_POLYGON *p;
	PEDGE *e, *last_e;

	p = ALLOC(SCR_POLYGON);

	p->n = 2;

	p->edges = newEdgeRing(p->n);

	p->edges[1].x = 75.0;
	p->edges[1].y = 25.0;

	p->edges[0].x = 75.0;
	p->edges[0].y = 100.0;

	initBoundingBox(p);

	return (p);
}


SCR_POLYGON *randomPolygon(x,y,w,h,maxn)
float x,y,w,h;
int maxn;
{
	SCR_POLYGON *p;
	PEDGE *e, *last_e;
	int k, npts;
	POINT2 *points;
	POINT2 *chull, *chp;

	p = ALLOC(SCR_POLYGON);

	/* take a bunch of points and then compute their convex hull */

	npts = maxn*maxn/2;
	points = (POINT2*)malloc(sizeof(POINT2)*npts);
	for (k=0; k<npts; k++)
	 { points[k].p.x = frandom(x,x+w);
	   points[k].p.y = frandom(y,y+h);
	 }
	p->n = convexHull (&chull, points, npts);

	/* now build the polygon from the convex hull. The convex
	   hull is returned in clockwise order, so we have to reverse
	   this. */

	p->edges = newEdgeRing(p->n);
	chp = chull;
	e = p->edges;
	do
	 { e->x = chp->p.x;
	   e->y = chp->p.y;
	   chp = chp->next;
	   e = e->prev;
	 }
	while (e != p->edges);
	FREE(chull);
	FREE(points);

	initBoundingBox(p);

	return (p);
}

#define MAXSPC	256

typedef struct _pspec {
	struct _pspec *next;
	int size;
	struct _pnts {
	   float x, y; } *pnts;
	  } PSPEC;

static PSPEC *pspecHead;
static PSPEC *pspecTail;

readPointFile(name)
char *name;
{
	FILE *fp;
	int k, size;
	PSPEC *ps;

	if ((fp = fopen(name,"r")) == NULL)
	 { fprintf(stderr, "Can't open file\n");
	   return(-1);
	 }

	fscanf (fp,"%f", &scrEpsilon);

	while (fscanf(fp,"%d", &size) != EOF)
	 { if (size > MAXSPC)
	    { fprintf(stderr, "Polygon size %d is too large\n", size);
	      return(-1);
	    }
	   ps = ALLOC(PSPEC);
	   ps->size = size;
	   ps->next = NULL;
	   if (!pspecHead)
	    { pspecHead = ps;
	      pspecTail = ps;
	    }
	   else
	    { pspecTail->next = ps;
	      pspecTail = ps;
	    }
	   ps->pnts = (struct _pnts*)malloc(size*sizeof(struct _pnts));
	   for (k=0; k<size; k++)
	    { if (fscanf(fp,"%f %f", &ps->pnts[k].x, &ps->pnts[k].y) != 2)
	       { fprintf(stderr, "Error reading points\n");
		 return(-1);
	       }
	    }
	 }	
	return(1);
}

SCR_POLYGON *specialPolygon()
{
	static PSPEC *pspec = NULL;
	SCR_POLYGON *p;
	PEDGE *e, *last_e;
	int k;

	p = ALLOC(SCR_POLYGON);

	if (!pspec)
	 { pspec = pspecHead;
	 }
	p->n = pspec->size;

	/* Build the polygon from the specified points. The defined
	   points are given in clockwise order, so we have to reverse
	   this. */

	p->edges = newEdgeRing(p->n);
	k = 0;
	e = p->edges;
	do
	 { e->x = pspec->pnts[k].x;
	   e->y = pspec->pnts[k].y;
	   k++;
	   e = e->prev;
	 }
	while (e != p->edges);
	pspec = pspec->next;

	initBoundingBox(p);

	return (p);
}

static void computeCentroid (xp, yp, pgn)
double *xp, *yp;
SCR_POLYGON *pgn;
{
	/* Compute the centroid of a polygon 'pgn'. */

	PEDGE *edg;
	register double x, y;

	x = y = 0;
	edg = pgn->edges;
	do
	 { x += edg->x;
	   y += edg->y;
	   edg = edg->next;
	 }
	while (edg != pgn->edges);

	*xp = x/pgn->n;
	*yp = y/pgn->n;
}

static pointInsidePolygon (x, y, pgn)
register double x, y;
SCR_POLYGON *pgn;
{
	/* Returns true if the point (x,y) is strictly inside the polygon 
	   'pgn'. */

	register PEDGE *eg1, *eg2;

	eg1 = pgn->edges;
	do
	 { eg2 = eg1->next;
	   if (((eg2->x-eg1->x)*(y-eg2->y) - 
		     (x-eg2->x)*(eg2->y-eg1->y)) <= 0.0)
	    { return(0);
	    }
	   eg1 = eg2;
	 }
	while (eg1 != pgn->edges);

	return(1);
}

/* Cross product between two vectors v1 and v2 is v1x*v2y-v2x*v1y */

/* SIDE(pt,e1,e2) computes (e2-e1)X(pt-e1).  

   This also means that:

   SIDE(pt,e1,e2) > 0 if e1,e2,pt form a LEFT turn;
   SIDE(pt,e1,e2) < 0 if e1,e2,pt form a RIGHT turn;
   SIDE(pt,e1,e2) = 0 if e1,e2,pt are colinear,

   and also that

   SIDE(pt,e1,e2) > 0 if pt is LEFT of (e2-e1);
   SIDE(pt,e1,e2) < 0 if pt is RIGHT of (e2-e1);
   SIDE(pt,e1,e2) = 0 if pt is colinear with (e2-e1)

*/   

#define SIDE(pt,e1,e2) \
	( ((e2)->x-(e1)->x)*((pt)->y-(e1)->y) - \
	  ((pt)->x-(e1)->x)*((e2)->y-(e1)->y) )	

#define NO_CROSSING	0
#define CROSSING	1
#define NO_INTERSECTION 2

float compSide (pt,e1,e2)
PEDGE *pt, *e1, *e2;
{
	register double ax, ay, bx, by;
	register float prod;
	float d;

	ax = e2->x - e1->x;
	ay = e2->y - e1->y;
	bx = pt->x - e1->x;
	by = pt->y - e1->y;
	prod = ax*by - ay*bx;
	d = ABS(ax) + ABS(ay) + scrEpsilon;
	if (ABS(prod)/d < scrEpsilon)
	 { return (0.0);
	 }
	else
	 { return (prod);
	 }
}

int debug;
int intersectionCount;

intrsectPolygons(poly1,poly2,draw,fp,fq,cntrXp,cntrYp)
SCR_POLYGON *poly1, *poly2;
int draw;
PEDGE **fp, **fq;
float *cntrXp, *cntrYp;
{
	PEDGE *p1, *q1;
	PEDGE *p2, *q2;
	float x, y, rq, rp, qCrossP;
	int outside = UNDEF;
	int loopCnt;
	int firstIntersection;
	PEDGE *firstP, *firstQ;
	int contact = 0;
	float sideP2, sideP1, sideQ2, sideQ1;
	double cntrX = 0; 
	double cntrY = 0;
	int icnt = 0;
	int rcode;
	int xstat;

	/* check the bounding boxes */

	if (poly1->xmax <= poly2->xmin || poly1->xmin >= poly2->xmax ||
	    poly1->ymax <= poly2->ymin || poly1->ymin >= poly2->ymax)
	 { return (P_DONT_INTERSECT);
	 }

	/* clear the intersection fields of each edge of each polygon */

	p2 = poly1->edges;
	do
	 { p2->intersect = 0;
	   p2 = p2->next;
	 }
	while (p2 != poly1->edges);

	p2 = poly2->edges;
	do
	 { p2->intersect = 0;
	   p2 = p2->next;
	 }
	while (p2 != poly2->edges);

	p2 = poly1->edges;
	q2 = poly2->edges;
	loopCnt = 0;
	firstIntersection = 0;

	intersectionCount = 0;

	do
	 { loopCnt++;

	   /* Check for intersection of both segments */

	   p1 = p2->prev;
	   q1 = q2->prev;

	   sideQ1 = compSide(q1,p1,p2);
	   sideP1 = compSide(p1,q1,q2);
	   sideQ2 = compSide(q2,p1,p2);
	   sideP2 = compSide(p2,q1,q2);
	   qCrossP = sideP2 - sideP1;

	   xstat = intrSeg (&rp, &rq, p2, q2, &contact, &outside);
	
	   if (debug)
	    { printf ("p2 = %g %g, q2 = %g %g, %s contact=%d outside=%s\n",
		       p2->x, p2->y, q2->x, q2->y,
		       (xstat == NO_INTERSECTION ? "NO INTERSECT" :
			xstat == CROSSING ? "CROSS" : "_"),
			contact, 
		       (outside == UNDEF ? "UNDEF" : 
			outside == 'q' ? "q" : "p"));
	    }

	   if (xstat == NO_INTERSECTION)
	    { return (P_DONT_INTERSECT);
	    }
	   else if (xstat == CROSSING)
	    { if (firstIntersection && 
		  ((p2==firstP && q2==firstQ) || (q2==firstP && p2==firstQ)))
	       { if (firstIntersection < loopCnt-1)
		  { if (cntrXp) *cntrXp = cntrX/icnt;
		    if (cntrYp) *cntrYp = cntrY/icnt;
		    if (icnt%2)
		     { printf ("ouch, no. intersections = %d\n", icnt);
		     }
		    intersectionCount = icnt;
		    return(P_INTERSECT);
		  }
	       }
	      else
	       { if (!firstIntersection)
		  { firstIntersection = loopCnt;
		    firstP = p2;
		    firstQ = q2;
		    if (fp) *fp = p2;
		    if (fq) *fq = q2;
		  }
		 if (outside == 'q')
		  { p1->intersect |= INTO;
		    q1->intersect |= OUT;
		    p1->rInto = rp;
		    q1->rOut = rq;
		  }
		 else /* outside == 'p' */
		  { p1->intersect |= OUT;
		    q1->intersect |= INTO;
		    p1->rOut = rp;
		    q1->rInto = rq;
		  }
		 x = q1->x + rq*(q2->x-q1->x);
		 y = q1->y + rq*(q2->y-q1->y);
		 
		 cntrX += x;
		 cntrY += y;
		 icnt++;
#if 1
		 if (draw) drawX (x,y);
		 if (draw) drawBox (x,y);
#endif
	       }
	    }
	   if (qCrossP > 0.0)
	    { if (sideP2 > 0.0)
	       { q2 = q2->next;
		 if (debug) printf ("advance Q\n");
	       }
	      else
	       { p2 = p2->next;
		 if (debug) printf ("advance P\n");
	       }
	    }
	   else if (qCrossP < 0.0)
	    { if (sideQ2 > 0.0)
	       { p2 = p2->next;
		 if (debug) printf ("advance P\n");
	       }
	      else
	       { q2 = q2->next;
		 if (debug) printf ("advance Q\n");
	       }
	    }
	   else /* Q and P are parallel */
	    { if (sideP2 < 0.0)
	       { p2 = p2->next;
		 if (debug) printf ("||, advance P\n");
	       }
	      else if (sideP2 > 0.0)
	       { q2 = q2->next;
		 if (debug) printf ("||, advance Q\n");
	       }
	      else if ( ((p2->x-p1->x)*(p2->x-q2->x) + 
			 (p2->y-p1->y)*(p2->y-q2->y)) < 0.0)
	       { p2 = p2->next;
		 if (debug) printf ("||, advance P\n");
	       }
	      else
	       { q2 = q2->next;
		 if (debug) printf ("||, advance Q\n");
	       }
	    }
	 }
	while (loopCnt <= 2*(poly1->n+poly2->n+1));
	if (debug) printf ("loop done\n");
	
	/* If we got this far, we know that either (1) there is
	   no intersection, (2) poly1 is contained in poly2, or
	   (3) poly2 is contained in poly1. */

	if (outside != UNDEF)
	 { /* Contact occured. If outside is 'q', the poly2 is
	      not contained in poly1, and vice versa. */

	   if (outside == 'p')
	    { computeCentroid (&cntrX, &cntrY, poly2);
	      if (pointInsidePolygon (cntrX, cntrY, poly1))
	       { rcode = P_POLY2_INSIDE;
	       }
	      else
	       { rcode = P_DONT_INTERSECT;
	       }
	    }
	   else
	    { computeCentroid (&cntrX, &cntrY, poly1);
	      if (pointInsidePolygon (cntrX, cntrY, poly2))
	       { rcode = P_POLY1_INSIDE;
	       }
	      else
	       { rcode = P_DONT_INTERSECT;
	       }
	    }
	 }
	else
	 { /* Contact did not occur. This implies that all vertices
	      of poly1 are completely inside poly2, or vice versa,
	      or there is not intersection. */

	   if (pointInsidePolygon (poly1->edges->x, poly1->edges->y, poly2))
	    { /* poly1 is completely inside poly2 */
	      computeCentroid (&cntrX, &cntrY, poly1);
	      rcode = P_POLY1_INSIDE;
	    }
	   else if (pointInsidePolygon (poly2->edges->x, poly2->edges->y, poly1))
	    { /* poly2 is completely inside poly1 */
	      computeCentroid (&cntrX, &cntrY, poly2);
	      rcode = P_POLY2_INSIDE;
	    }
	   else
	    { /* no intersection */
	      rcode = P_DONT_INTERSECT;
	    }
	 }
	if (cntrXp) *cntrXp = cntrX;
	if (cntrYp) *cntrYp = cntrY;
	return (rcode);
}

#define LOOK_AHEAD_P	1
#define LOOK_AHEAD_Q	2

intrSeg (rp, rq, p2, q2, contact, outside)
float *rp, *rq;
PEDGE *p2, *q2;
int *contact;
int *outside;
{
	/* Return 1 if polygon edges p2 and q2 intersect, and 0 otherwise.
	   If the edges *do* intersect, then the values rp and rq are each
	   set to the appropriate value from the interval [0,1] to indicate
	   where on each edge the intersection occurs.

	   Intersection only occurs when one edge actually passes over the
	   other. Sometimes, edges will come into contact but one will 
	   not actually cross the other. The variable 'contact' is set
	   when this occurs.

	   The variable 'outside' is set whenever we know which polygon
	   is outside the other. An intersect occurs whenever the value
	   if this variable is known to change.
	 */

	PEDGE *p1, *q1;
	float sideQ2, sideP2, sideQ1, sideP1;
	float r;
	int lookAhead;
	int oldOutside;

	p1 = p2->prev;
	q1 = q2->prev;

	sideQ1 = compSide(q1,p1,p2);	/* which side of P is q1 on */
	sideP1 = compSide(p1,q1,q2);	/* which side of Q is p1 on */
	sideQ2 = compSide(q2,p1,p2);	/* which side of P is q2 on */
	sideP2 = compSide(p2,q1,q2);	/* which side of Q is p2 on */

	if (*contact)
	 { /* if heads are coincident, then edges are coincident, so return */
	   if (sideP2 == 0.0 || sideQ2 == 0.0)
	    { if (sideP2 == 0.0 && sideQ2 == 0.0)
	       { if ((p2->x-p1->x)*(q2->x-q1->x)+
		     (p2->y-p1->y)*(q2->y-q1->y) < 0.0)
		  { return(NO_INTERSECTION);
		  }
	       }
	      return(NO_CROSSING);
	    }
	   *contact = 0;
	   oldOutside = *outside;
	   *outside = ((sideP2 < 0) ? 'p' : 'q');
	   if (oldOutside != UNDEF)
	    { if (*outside != oldOutside)
	       { *rq = (sideQ1 == 0.0) ? 0.0 : 
			ABS(sideQ1/(sideQ2-sideQ1));
		 *rp = (sideP1 == 0.0) ? 0.0 : 
			ABS(sideP1/(sideP2-sideP1));
		 return(CROSSING);
	       }
	    }
	   return(NO_CROSSING);
	 }
	if (sideQ1 == 0.0 || sideP1 == 0.0)
	 { /* then tails are coincident; */
	   if (sideP2 == 0.0)
	    { /* then edges are coincident. */
	      *contact = 1;
	    }
	   return(NO_CROSSING);
	 }

	/* Contact is also set if: 
	   1. The heads are coincident
	   2. P is incident onto Q
	   3. Q is incident onto P */

	if ((sideP2 == 0.0 && sideQ2 == 0.0) ||
	    (sideP2 == 0.0 && sideQ1*sideQ2 < 0) ||
	    (sideQ2 == 0.0 && sideP1*sideP2 < 0))
	 { *contact = 1;
	   *outside = ((sideP1 < 0) ? 'p' : 'q');
	   return (NO_CROSSING);
	 }
	else if (sideP2*sideP1 < 0 && sideQ1*sideQ2 < 0)
	 { *outside = ((sideP2 < 0) ? 'p' : 'q');
	   *rq = ABS(sideQ1/(sideQ2-sideQ1));
	   *rp = ABS(sideP1/(sideP2-sideP1));
	   return (CROSSING);
	 }
	else
	 { return (NO_CROSSING);
	 }
}

cutPolygon(p,start)
SCR_POLYGON *p;
PEDGE *start;
{
	register PEDGE *pe, *pi, *pp, *pl, *ps, *pf, *pn;
	float ri, xi, yi;
	float ro, xo, yo;
	float xf, yf;
	int cnt;
	int oldcnt;

	pe = start;
	if (pe->intersect & OUT)
	 { pi = NULL;
	 }
	else if (pe->intersect & INTO)
	 { pi = pe;
	   ri = pe->rInto;
	   xi = pe->prev->x + ri*(pe->x - pe->prev->x);
	   yi = pe->prev->y + ri*(pe->y - pe->prev->y);
	 }
	else
	 { fprintf(stderr, "cutPolygon(): start edge has no intersection\n");
	   exit(-1);
	 }
	cnt = 0;
	do
	 { pe = pe->next;
	   cnt++;
	   if (pe == 0)
	    { fprintf (stderr, "Error(1), pe->next = 0\n");
	    }
	   if (!pi && pe->intersect & INTO)
	    { pi = pe;
	      ri = pe->rInto;
	      xi = pe->prev->x + ri*(pe->x - pe->prev->x);
	      yi = pe->prev->y + ri*(pe->y - pe->prev->y);
	      oldcnt = cnt;
	    }
	   if (pi && pe->intersect & OUT)
	    { int oldcnt;
	      ro = pe->rOut;
	      xo = pe->prev->x + ro*(pe->x - pe->prev->x);
	      yo = pe->prev->y + ro*(pe->y - pe->prev->y);
	      xf = pe->x;
	      yf = pe->y;
	      if (((xo-xi)*(xo-xi) + (yo-yi)*(yo-yi)) > EPSILON*EPSILON)
	       { /* cut the edges between pi and po */

#define NEW_EDGE() \
	if (pp) \
	 { pn = pp; pp = pp->next; \
	 } \
	else \
	 { pn = newEdge(); \
	 } \
	pn->prev = pl; pl->next = pn; pl = pn; cnt++;

		 oldcnt = cnt;

		 ps = pi->prev;
		 pf = pe->next;
		 pp = pi;
		 pl = ps;
		 pe->next = NULL;
		 cnt--;
		 if (ri > 0.0)
		  { NEW_EDGE();
		    pn->visible = 1;
		    pn->x = xi;
		    pn->y = yi;
		  }
		 NEW_EDGE();
		 pn->visible = 0;
		 pn->x = xo;
		 pn->y = yo;
		 if (1.0-ro > EPSILON)
		  { NEW_EDGE();
		    pn->visible = 1;
		    pn->x = xf;
		    pn->y = yf;
		  }
		 pl->next = pf;
		 if (pf == 0)
		  { fprintf (stderr, "Error, pf = 0\n");
		  }
		 pf->prev = pl;
		 if (pp)
		  { freeEdges(pp,pe);
		  }
		 if (pe == start)
		  { start = pl;
		  }
		 if (pe == p->edges)
		  { p->edges = pl;
		  }
		 pe = pl;
	      	 if (pe == 0)
		  { fprintf (stderr, "Error, pe->next = 0\n");
		  }
	      	 if (pl->next == 0)
		  { fprintf (stderr, "Error, pl->next = 0\n");
		  }
	       }
	      pi = NULL;
	    }
	 }
	while (pe != start);
	p->n = cnt;	
}

fuzzPolygon(p)
SCR_POLYGON* p;
{
	PEDGE *ee;

	ee = p->edges;
	do
	 { ee->x += frandom(-0.01,0.01);
	   ee->y += frandom(-0.01,0.01);
	   ee=ee->next;
	 }
	while (ee != p->edges);
}
