static char *SccsId = "@(#)scan.c 4.2 (TU-Delft) 5/1/92";
/**********************************************************

Name/Version      : mplot/4.2

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

Author            : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       :
Modification date :


        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 <stdio.h>
#include "config.h"
#include "plot.h"
#include "aux/aux.h"

extern edge_t     * initScan ();
extern edge_t     * fetch    ();
extern edge_t     * find     ();

scan ()
{
    edge_t * edge,
           * head    = initScan (),
           * newEdge = fetch (),
	   * fwdEdge,
           * vert    = NULL,
	   * e1,
	   * e2;
    int    black     = 0;
    coor_t thisX     = newEdge -> xl,
	   thisY,
	   nextX     = INF;

    while (thisX < INF) {
#ifdef DEBUG
	if (DEBUG) fprintf (stderr, "thisX=%d\n", thisX);
#endif DEBUG
	edge = head -> fwd;
	ASSERT (vert == NULL);
	ASSERT (black == 0);
	while (edge -> yr < INF || newEdge -> xl == thisX) {

	    thisY = Y (edge, thisX);

	    if (newEdge -> xl == thisX && newEdge -> yl < thisY) {
		insert (newEdge, edge);

		black ^= 1;

		if (!vert)
		    vert = newEdge;
		else {
		    merge (find (vert), newEdge);
		    if (black) vert -> link = newEdge;
		    else       newEdge -> link = vert;
		    vert = NULL;
		}

		nextX = Min (nextX, newEdge -> xr);
		newEdge = fetch ();
	    }

	    else if (edge -> xr == thisX) {
		fwdEdge = edge -> fwd;
		delete (edge);

		if (!vert)
		    vert = edge;
		else {
		    e1 = find (edge);
		    e2 = find (vert);
		    if (e1 != e2) {
			merge (e1, e2);
			if (black) edge -> link = vert;
			else       vert -> link = edge;
		    }
		    else {
			if (black) plotContour (vert);	/* contour of hole */
			else       plotContour (edge);	/* external contour */
		    }
		    vert = NULL;
		}
		edge = fwdEdge;
	    }

	    else {
		nextX = Min (nextX, edge -> xr);
		edge = edge -> fwd;
		black ^= 1;
	    }
	}
#ifdef DEBUG
	if (DEBUG) {
	    fprintf (stderr, "checking stateruler\n");
	    checkSR (head, thisX);
	}
#endif DEBUG

	thisX = Min (nextX, newEdge -> xl);
	nextX = INF;
    }
}

static edge_t * initScan () 
{
    static edge_t _head, _tail;
    edge_t * head = &_head, * tail = &_tail;

    head -> xl = -INF; head -> xr =  INF;
    head -> yl = -INF; head -> yr = -INF;
    tail -> xl = -INF; tail -> xr =  INF;
    tail -> yl =  INF; tail -> yr =  INF;
    head -> fwd = head -> bwd = tail;
    tail -> fwd = tail -> bwd = head;

    return (head);
}

static 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;
}

static 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;
}

static edge_t * find (edge)	/* find contour of which edge is part */
edge_t * edge;
{
    edge_t * t, * i = edge;
    while (edge -> contour)		/* find the root */
	edge = edge -> contour;
    while (i -> contour) {		/* compress */
	t = i; i = i -> contour; t -> contour = edge;
    }
    ASSERT (edge -> contour == NULL);	/* edge is a root */
    return (edge);
}

static merge (e1, e2)		/* merge two contours */
edge_t * e1, *e2;
{
    /* should do union by size */
    ASSERT (e1 -> contour == NULL);	/* e1 is a root */
    ASSERT (e2 -> contour == NULL);	/* e2 is a root */
    ASSERT (e1 != e2);
    e2 -> contour = e1;
}

#ifdef DEBUG
checkSR (head, x)
edge_t * head;
int x;
{
    edge_t * e = head -> fwd;
    while (e != head -> bwd) {
	ASSERT (Y (e -> fwd, x) >= Y (e, x));
	e = e -> fwd;
    }
}
#endif DEBUG
