static char *SccsId = "@(#)scan.c 4.5 (TU-Delft) 04/16/93";
/**********************************************************

Name/Version      : makegln/4.5

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author            : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       : S. de Graaf
Modification date : 20-Jul-1990


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1988. All rights reserved.
**********************************************************/
#include "config.h"
#include <stdio.h>
#include "aux/aux.h"
#include "makegln.h"

static struct {
    int xpos;			/* # x-positions */
    int srl;			/* stateruler length */
    int edges;
} scanInfo;

/*  smallerAtX - return 1 if e2 <x e1, 0 otherwise */
#define smallerAtX(e1, e2) \
(e2 -> xl == thisX \
&& (e2 -> yl < Y(e1, thisX) \
   || (e2 -> yl == Y(e1, thisX) && e1 -> xr > thisX && e2 -> slope < e1 -> slope)))
#define smallerAtX1(e1, e2) \
(e2 -> xl == thisX \
&& (e2 -> yl < Y(e1, thisX) \
   || (e2 -> yl == Y(e1, thisX) && e2 -> slope < e1 -> slope)))
   

#define equalAtX(e1, e2) \
(e2 -> xl == thisX && e2 -> yl == Y(e1, thisX) && e2 -> slope == e1 -> slope)

extern edge_t     * initScan  ();
extern edge_t     * fetchEdge ();
extern edge_t     * split     ();
extern bool_t       optInfo;
extern bool_t       optSortOnly;
extern int scale;

private void insert ();
private void bundle ();

void scan ()
{
    register edge_t * edge;
    register edge_t * newEdge = fetchEdge ();
             edge_t * head    = initScan ();
    register coor_t thisX     = newEdge -> xl;
             coor_t nextX     = INF;
             coor_t xr;

    if (optSortOnly) {
	while (thisX < INF) {
	    outputEdge (newEdge);
	    disposeEdge (newEdge);
	    newEdge = fetchEdge ();
	    thisX = newEdge -> xl;
	}
	return;
    }

    while (thisX < INF) {

#ifdef DEBUG
	if (DEBUG) fprintf (stderr, "thisX=%g\n", (double) thisX / scale);
#endif DEBUG

	scanInfo.xpos++;

	edge = head -> fwd;

	while (edge -> yr < INF || newEdge -> xl == thisX) {

	    if (edge -> xi == thisX)
		edge = split (edge);

	    if ((edge -> xc == thisX) && (edge -> bundle != NULL))
		unbundle (edge);

	    if (smallerAtX (edge, newEdge)) {
		insert (newEdge, edge);
		edge = newEdge, newEdge = fetchEdge ();
		scanInfo.edges++;
	    }

	    /*
	    if (equalAtX (edge, newEdge) && smallerAtX (edge -> fwd, newEdge)) {
	    */
	    if (equalAtX (edge, newEdge)) {
		if (smallerAtX1 (edge -> fwd, newEdge)
		||  edge -> fwd -> xr == thisX) {
		    xr = edge -> xr;
		    do {
			bundle (newEdge, edge);
			newEdge = fetchEdge ();
			scanInfo.edges++;
		    } while (equalAtX (edge, newEdge));


		    if (edge -> xr > xr) {
			testIntersection (thisX, edge, edge -> fwd);
			testIntersection (thisX, edge, edge -> bwd);
		    }
		}
	    }

	    scanInfo.srl++;

	    if (edge -> xr == thisX) {
		glnUpdate (edge, thisX);
		edge = edge -> fwd, delete (edge -> bwd);
		testIntersection (thisX, edge, edge -> bwd);
	    }
	    else {
	        if (edge -> xl == thisX) {
		    glnUpdate (edge, thisX);
		    testIntersection (thisX, edge, edge -> bwd);
		}
		else {
		    glnUpdate (edge, thisX);
		    if (edge -> bwd -> xl == thisX)
			testIntersection (thisX, edge, edge -> bwd);
		}
		
		if (edge -> xi < nextX) nextX = edge -> xi;
		if (edge -> xc < nextX) nextX = edge -> xc;
		if (edge -> xr < nextX) nextX = edge -> xr;
		edge = edge -> fwd;
	    }
	}

#ifdef DEBUG
	if (DEBUG) {
	    fprintf (stderr, "checking stateruler\n");
	    checkSR (head, thisX);
	}
	else checkSR (head, thisX);
#endif DEBUG

	ASSERT (nextX > thisX && newEdge -> xl > thisX);
	scanAdvance (thisX);
	if (nextX < newEdge -> xl) thisX = nextX;
	else                       thisX = newEdge -> xl;
	nextX = INF;
    }
}

private
edge_t * initScan () 
{
    edge_t * createEdge ();
    static edge_t * head = NULL;
    static edge_t * tail = NULL;

    if (head != NULL) {
	ASSERT (head -> fwd == tail && head -> bwd == tail);
	ASSERT (tail -> fwd == head && tail -> bwd == head);
	return (head);
    }

    head = createEdge (-INF, -INF, INF, -INF, 0, 0);
    tail = createEdge (-INF,  INF, INF,  INF, 0, 0);
    head -> fwd = head -> bwd = tail;
    tail -> fwd = tail -> bwd = head;
    return (head);
}

private
delete (edge)		/* delete edge from scanline */
edge_t * edge;
{
#ifdef DEBUG
    if (DEBUG) printEdge ("delete", edge);
#endif DEBUG
    edge -> bwd -> fwd = edge -> fwd;
    edge -> fwd -> bwd = edge -> bwd;
    disposeEdge (edge);
}

private void insert (newEdge, edge)	/* insert newEdge below edge */
edge_t * newEdge, *edge;
{
#ifdef DEBUG
    if (DEBUG) printEdge ("insert", newEdge);
    if (DEBUG) printEdge ("below", edge);
#endif DEBUG
    newEdge -> bwd = edge -> bwd;
    newEdge -> fwd = edge -> bwd -> fwd;
    edge -> bwd -> fwd = newEdge;
    edge -> bwd = newEdge;
}

private void bundle (newEdge, edge)		/* insert overlapping edge */
edge_t * newEdge, * edge;
{
    edge_t * e = edge, * e1 = edge;
    int    s;

#ifdef DEBUG
    if (DEBUG) printEdge ("bundle", newEdge);
    if (DEBUG) printEdge ("with",  edge);
#endif DEBUG

    ASSERT (edge -> slope == newEdge -> slope);
    ASSERT (newEdge -> xr == newEdge -> xc);

    if (e -> xr == newEdge -> xl) {
	ASSERT (e -> bundle == NULL);
	e -> xr = newEdge -> xr;
	e -> yr = newEdge -> yr;
	e -> xc = newEdge -> xc;
	e -> sign = newEdge -> sign;
	disposeEdge (newEdge);
	goto post;
    }

    if (newEdge -> xr > edge -> xr)
	edge -> xr = newEdge -> xr, edge -> yr = newEdge -> yr;

    while (e1 && e1 -> xc <= newEdge -> xr) {
	e = e1, e1 = e1 -> bundle;
	e -> sign += newEdge -> sign;
    }

    /* e is the last edge in the bundle list with e->xc <= newEdge->xr
     * if such an edge exist, and the first edge otherwise
     */
	    
    ASSERT (e == edge || (e -> xc <= newEdge -> xr &&
	    (e -> bundle == NULL || e -> bundle -> xc > newEdge -> xr)));

    if (e -> xc == newEdge -> xr) {
	disposeEdge (newEdge);
    }

    else if (e -> xc < newEdge -> xr) {
	/* insert newEdge after e */
	if (e -> bundle) 		/* if it is not last */
	    newEdge -> sign += e -> bundle -> sign;

	newEdge -> bundle = e -> bundle;
	e -> bundle = newEdge;
    }

    else {
	ASSERT (e == edge);	 /* e is first edge */
	ASSERT (newEdge -> xr < edge -> xc);
	newEdge -> xc = e -> xc;
	e -> xc = newEdge -> xr;
	s = newEdge -> sign, newEdge -> sign = e -> sign, e -> sign += s;

	newEdge -> bundle = e -> bundle, e -> bundle = newEdge;
    }

    post:
#ifdef DEBUG
    for (e = edge; e -> bundle; e = e -> bundle) {
	ASSERT (e -> xc < e -> bundle -> xc);
    }
    ASSERT (e -> xc == edge -> xr);
#endif DEBUG
    return;
}

private
unbundle (edge)		/* delete overlapping edge */
edge_t * edge;
{
    edge_t * b = edge -> bundle;

#ifdef DEBUG
    if (DEBUG) printEdge ("unbundle", edge);
#endif DEBUG

    edge -> signLeft = edge -> sign;
    edge -> sign   = b -> sign;
    edge -> xc     = b -> xc;
    edge -> bundle = b -> bundle;
    disposeEdge (b);
}

#ifdef DEBUG
checkSR (head, x)
edge_t * head;
int x;
{
    edge_t * e;
    int sign = 0;;
    for (e = head -> fwd; e != head -> bwd; e = e -> fwd) {
	sign += e -> sign;
	if (DEBUG) printEdge ("edge", e);
	ASSERT (e -> xr > x);
	ASSERT (e -> xl <= x);
	ASSERT (Y (e -> fwd, x) > Y (e, x) ||
	   (Y (e -> fwd, x) == Y (e, x) && e -> fwd -> slope > e -> slope));
    }
    ASSERT (sign == 0);
}
#endif DEBUG

scanPrintInfo (fp)
FILE *fp;
{
    fprintf (fp, "\tnumber of x pos.    : %d\n", scanInfo.xpos);
    fprintf (fp, "\taverage sr length   : %d\n",
	scanInfo.xpos ? scanInfo.srl/scanInfo.xpos : 0);
    fprintf (fp, "\taccumul. sr length  : %d\n", scanInfo.srl);
    fprintf (fp, "\ttotal # input edges : %d\n", scanInfo.edges);
}
