#ifndef lint
static char *SccsId = "@(#)scan.c 4.9 (TU-Delft) 05/14/93";
#endif /* lint */
/**********************************************************

Name/Version      : space/4.9

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

Author(s)         : A.J. van Genderen
		  : 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 "include/config.h"
#include "include/type.h"
#include "aux/aux.h"
#include "scan.h"

extern bool_t optVerbose;
extern bool_t prePass2;
extern bool_t optPrick;
extern bool_t optReadNetTerm;
extern bool_t optNoCore;
int slicingOn;

private edge_t * initScan ();
private void delete_e ();
private void insert ();
private void bundle ();
private void unbundle ();
private void checkSR ();

# ifdef FAST
# define insert(newEdge, edge) { \
    newEdge -> bwd = edge -> bwd; \
    newEdge -> fwd = edge -> bwd -> fwd; \
    edge -> bwd -> fwd = newEdge; \
    edge -> bwd = newEdge; \
}

# define delete_e(edge) {\
    register edge_t * e = edge; \
    e -> bwd -> fwd = e -> fwd; \
    e -> fwd -> bwd = e -> bwd; \
    disposeEdge (e); \
}
# endif /* FAST */

/*  smallerAtX - return 1 if e2 <x e1, 0 otherwise */
#ifdef MANHATTAN

#define smallerAtX(e1, e2) \
    (e2 -> xl == thisX && e2 -> yl < thisY)

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

#define TestIntersection(e1, e2) /* nothing */

#else /* Non Manhattan */

#define smallerAtX(e1, e2) \
    (e2 -> xl == thisX \
    && (   e2 -> yl < thisY \
       || (e2 -> yl == thisY && e1 -> xr > thisX && compareSlope (e2, <,  e1))))

/* 
 * Comment added NvdM, 891213
 * the comparison with e1 -> xr is (probably!!!) necessary because
 * the ordering in the stateruler can become wrong
 * in cases where an edge under +45 straddles the scanline
 * in say, (x,y) and an edge under -45 ends in (x,y).
 * This can, however give other problems because horizontal
 * edges ending and starting at (x,y) will not be bundled.
 */
#define equalAtX(e1, e2) \
    (e2 -> xl == thisX && e2 -> yl == thisY && \
    compareSlope (e1, ==,  e2) && e1 -> xr > thisX)

#define TestIntersection(e1, e2) {\
    if (compareSlope (e1, !=,  e2)) testIntersection(e1, e2); \
}
#endif /* MANHATTAN */

extern bool_t       optInfo;

static coor_t here = -INF;
static char cell[100];
static coor_t xl, xr;
static int scale;
static int flag = 0;

void setContext (c, s, l, r)
char * c;
int    s;
coor_t l;
coor_t r;
{
    strncpy (cell, c, 99);
    cell[100] = '\0';
    xl = l;
    xr = r;
    scale = s;
}

void catchAlarm ()
{
    flag++;
}

void whereAmI () {

    here = Max (here, xl);
    here = Min (here, xr);


    message ("%s, x = %d (%d%%)\n", cell, here / scale, 
	(100 * (here - xl))/(xr - xl));
}


void scan ()
{
    register edge_t * edge;
    register edge_t * newEdge = fetchEdge ();
             edge_t * head    = initScan ();
    register coor_t thisX     = newEdge -> xl;
    register coor_t thisY;
    register mask_t          color;
    register coor_t nextX     = INF;
             coor_t xr;
    int meshVer = 0;
    terminal_t      * newTerm = fetchTerm ();

#   ifdef DEBUG
    static int no_split = -1;
#   endif /* DEBUG */


#   ifdef DEBUG
    if (no_split == -1)
	no_split = paramLookupB ("no_split", "off") ? 1 : 0;
#   endif /* DEBUG */

    while (thisX < INF) {
	here = thisX;

	Debug (fprintf (stderr, "thisX=%d\n", thisX));

	scanInfo.xpos++;


	edge = head -> fwd;
	color = 0;
	slicingOn = 0;
	while (edge -> yr < INF 
	    || newEdge -> xl == thisX || newTerm -> x == thisX) {

#           ifndef MANHATTAN
	    if (edge -> xi == thisX)
		edge = split (edge);
#           endif /* MANHATTAN */

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

	    thisY = Y (edge, thisX);

	    if (smallerAtX (edge, newEdge)) {
		insert (newEdge, edge);
		edge = newEdge, newEdge = fetchEdge ();
		thisY = Y (edge, thisX);
	    }

#           ifndef MANHATTAN
	    xr = edge -> xr;
#           endif /* MANHATTAN */

	    while (equalAtX (edge, newEdge)) {
		bundle (newEdge, edge);
		newEdge = fetchEdge ();
	    }

#           ifndef MANHATTAN
	    if (edge -> xr > xr) {
		TestIntersection (edge, edge -> fwd);
		TestIntersection (edge, edge -> bwd);
	    }
#           endif /* MANHATTAN */

	    while (newTerm -> x == thisX && newTerm -> y <= thisY) {
		tileAddTerm (edge -> bwd, newTerm);
		newTerm = fetchTerm ();
	    }

	    scanInfo.srl++;

	    if (edge -> xr == thisX) {
		tileDeleteEdge (edge, color);
		edge = edge -> fwd;
		delete_e (edge -> bwd);
		TestIntersection (edge, edge -> bwd);
	    }
	    else {
		color ^= edge -> color;
		if (edge -> xl == thisX) {
		    TestIntersection (edge, edge -> bwd);
		    tileInsertEdge (edge, color);

		}
		else {
#                   ifndef MANHATTAN
		    if (edge -> bwd -> xl == thisX)
			TestIntersection (edge, edge -> bwd);
#                   endif /* MANHATTAN */

                    tileCrossEdge (thisX, edge, color, 0, 0);

		}

#               ifndef MANHATTAN
		if (edge -> xi < nextX) nextX = edge -> xi;
#               endif /* MANHATTAN */
		if (edge -> xc < nextX) nextX = edge -> xc;

		edge = edge -> fwd;
	    }

	    if (flag) {
		flag = 0;
		whereAmI ();
	    }
	}

	ASSERT (color == 0);
	ASSERT (nextX > thisX && newEdge -> xl > thisX && newTerm -> x > thisX);
	tileAdvanceScan (edge, thisX);

	Debug2 (checkSR (head, thisX));

	ASSERT (nextX > thisX && newEdge -> xl > thisX);
	if (nextX > newTerm -> x)  nextX = newTerm -> x;
	if (nextX > newEdge -> xl) nextX = newEdge -> xl;


	ASSERT (nextX > thisX);
	thisX = nextX;
	nextX = INF;
    }
    here = INF;


    tileStopScan (head);

    /* Remove head and tail of stateruler.
     * These can not be retained, since the tiles
     * have a cons array depending on resistance extraction.
     * With display mode, resistance extraction can be turned
     * on or off.
     */
    disposeEdge (head -> fwd);
    disposeEdge (head);
}

private edge_t * initScan () 	/* init head and tail of stateruler */
{
    edge_t * createEdge ();
    tile_t * createTile ();

    edge_t * head = createEdge (-INF, -INF, INF, -INF, 0);
    edge_t * tail = createEdge (-INF,  INF, INF,  INF, 0);

    head -> fwd = head -> bwd = tail;
    tail -> fwd = tail -> bwd = head;

    head -> tile = createTile (-INF, -INF, INF, -INF,
		    0, Null (tile_t *), Null (tile_t *));
    head -> tile -> tl = head -> tile -> tr =  INF;

    tail -> tile = createTile (-INF, INF, INF, INF,
		    0, Null (tile_t *), Null (tile_t *));
    tail -> tile -> tl = tail -> tile -> tr = -INF;

    return (head);
}

#ifndef delete_e
private void delete_e (edge)		/* delete edge from scanline */
edge_t * edge;
{
    Debug (printEdge ("delete", edge));

    edge -> bwd -> fwd = edge -> fwd;
    edge -> fwd -> bwd = edge -> bwd;
    disposeEdge (edge);
}
#endif

#ifndef insert
private void insert (newEdge, edge)		/* insert newEdge below edge */
edge_t * newEdge, *edge;
{

    Debug (printEdge ("insert", newEdge));
    Debug (printEdge ("below", edge));

    newEdge -> bwd = edge -> bwd;
    newEdge -> fwd = edge -> bwd -> fwd;
    edge -> bwd -> fwd = newEdge;
    edge -> bwd = newEdge;
}
#endif

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

    Debug (printEdge ("bundle", newEdge));
    Debug (printEdge ("with",  edge));

    ASSERT (compareSlope (edge, ==, newEdge));
    ASSERT (newEdge -> xr == newEdge -> xc);

    if (e -> xr == newEdge -> xl) {
	ASSERT (e -> bundle == Null (edge_t *));
	e -> xr = newEdge -> xr;
	e -> yr = newEdge -> yr;
	e -> xc = newEdge -> xc;
	e -> color = newEdge -> color;
	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 -> color |= newEdge -> color;
    }

    /* 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 (edge_t *)
	    || 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 -> color |= e -> bundle -> color;

	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;
	m = newEdge -> color, newEdge -> color = e -> color, e -> color |= m;
	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 void unbundle (edge)	/* delete overlapping edge */
edge_t * edge;
{
    edge_t * b = edge -> bundle;

    Debug (printEdge ("unbundle", edge));

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

#ifdef DEBUG
private void checkSR (head, x)
edge_t * head;
coor_t x;
{
    edge_t * e;
    for (e = head -> fwd; e != head -> bwd; e = e -> fwd) {
	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) && compareSlope (e -> fwd, >, e)));
    }
}
#endif /* DEBUG */
