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

Name/Version      : space/4.7

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"

static tile_t * freeTile = Null (tile_t *);
extern tile_t * createTile ();

extern int slicingOn;
extern bool_t optResMesh;
extern bool_t prePass1;
extern mask_t resBitmask;
extern double max_tan_slice_y;


/*
 * private functions
 */
private void TR ();
private void BR ();
private void TL ();
private void inject ();

#undef FAST
#ifdef FAST
#define TL(t_l, t_r, tile, t_left) \
    tile -> tl = t_l; \
    tile -> tr = t_r; \
    if (t_left) enumPair (t_left, tile, 'v')

#define BR(x_r, b_r, tile, t_bot) \
    tile -> xr = x_r; \
    tile -> br = b_r; \
    if (t_bot && t_bot -> xl < x_r) enumPair (t_bot, tile, 'h')
#endif /* FAST */

static coor_t XR = -INF;
void setXr (xr)
coor_t xr;
{
    XR = xr;
}

/* tileInsertEdge (edge, color)
 * pre:  edge is just inserted in scanline
 * post: tiles around this edge are updated
 */

void tileInsertEdge (edge, color)
edge_t * edge;
mask_t color;
{
    coor_t thisX = edge -> xl,		/* current X value */
	   thisY = edge -> yl,		/* current Y value */
	   prevY;

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


    if (freeTile == Null (tile_t *)) {
	prevY = Y (edge -> bwd, thisX);
	BR (thisX, prevY, edge -> bwd -> tile, edge -> bwd -> bwd -> tile);
	freeTile = edge -> bwd -> tile;
	edge -> bwd -> tile = createTile (
	    thisX, prevY, XR, Y (edge -> bwd, XR),
	    freeTile -> color, edge -> bwd -> bwd -> tile, freeTile);

#ifdef ENUMPOINT
	/* now there is one tile below the point thisX, thisY */
	if (edge -> bwd -> bwd -> tile -> xl < thisX)
	    enumPoint (thisX, prevY,
		edge -> bwd -> bwd -> tile,
		edge -> bwd -> bwd -> tile,
		edge -> bwd -> tile,
		freeTile);
#endif /* ENUMPOINT */
    }

    TL (thisY, Y (edge, XR), edge -> bwd -> tile, freeTile);

    edge -> tile = createTile (thisX, thisY, XR, Y(edge, XR),
	color, edge -> bwd -> tile, freeTile);
    ASSERT (color == (edge -> bwd -> tile -> color ^ edge -> color));

#ifdef ENUMPOINT
    enumPoint (thisX, thisY,
	freeTile, edge -> bwd -> tile, edge -> tile, freeTile);
#endif /* ENUMPOINT */

}

/* tileDeleteEdge (edge, color)
 * pre:  edge is just to be deleted from scanline (but is not so already).
 *       edge forms the top-right point of the tile below
 *       and the bottom-right point of the tile above the edge.
 * post: if there is a free tile, it is finished 
 *       tile connected to this edge becomes free,
 */

void tileDeleteEdge (edge, color)
edge_t * edge;
mask_t color;
{
    coor_t thisX = edge -> xr,
	   thisY = edge -> yr,
	   prevY;

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


    if (freeTile == Null (tile_t *)) {
	prevY = Y (edge -> bwd, thisX);
	BR (thisX, prevY, edge -> bwd -> tile, edge -> bwd -> bwd -> tile);
	freeTile = edge -> bwd -> tile;
	if (thisX < XR) {
	    /* the tile will have coordinates that assure
	     * that the slope of its edges is correct,
	     * in order not to confuse the lateral coupling
	     * cap computations.
	     */
	    edge -> bwd -> tile = createTile (
		thisX, prevY, XR, Y (edge -> bwd, XR),
		freeTile -> color, edge -> bwd -> bwd -> tile, freeTile);
	}
	else {
	    /* this case is special: here the right most space
	     * tile is created.
	     * Make sure it extends to inifinity.
	     */
	    edge -> bwd -> tile = createTile (
		thisX, prevY, INF, INF,
		freeTile -> color, edge -> bwd -> bwd -> tile, freeTile);
	}

#ifdef ENUMPOINT
	if (edge -> bwd -> bwd -> tile -> xl < thisX) {
	    enumPoint (thisX, prevY,
		edge -> bwd -> bwd -> tile,
		edge -> bwd -> bwd -> tile,
		edge -> bwd -> tile,
		freeTile);
	}
#endif /* ENUMPOINT */
    }

    ASSERT (edge -> bwd -> tile -> color == color);

#ifdef ENUMPOINT
    enumPoint (thisX, thisY, 
	freeTile, edge -> bwd -> tile, edge -> bwd -> tile, edge -> tile);
#endif /* ENUMPOINT */

    TR (thisY, freeTile, edge -> bwd -> tile, edge -> tile);

    BR (thisX, thisY, edge -> tile, Null (tile_t *));

    freeTile = edge -> tile;

}

/* tileCrossEdge (thisX, edge, color, split, left)
 * pre:  edge is crossed in scanline
 *       edge -> xl < thisX < edge -> xr
 * post: if there is a free tile, it is finished.
 *
 *       The scanline intersects the edge, there are at least two tiles,
 *       1 above and 1 below the edge, but each of them may be splitted
 *       because the color to the left and right of the scanline may be
 *       different.
 */

void tileCrossEdge (thisX, edge, color, split, left)
coor_t thisX;
edge_t * edge;
mask_t color;
int split;
coor_t left;
{
    coor_t thisY;
    int twoTilesAbove;

#ifdef ENUMPOINT
    tile_t * tbl;		/* bot-left  tile of x,y */
    tile_t * tbr;		/* bot-right tile of x,y */
    tile_t * ttr;		/* top-right tile of x,y */
    tile_t * ttl;		/* top-left  tile of x,y */
    tbl = edge -> bwd -> tile;
    tbr = edge -> bwd -> tile;
    ttr = edge -> tile;
    ttl = edge -> tile;
#endif /* ENUMPOINT */

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


    if (freeTile != Null (tile_t *)) {
	/* two tiles below edge */
#ifdef ENUMPOINT
	tbl = freeTile;
#endif /* ENUMPOINT */
        thisY = Y (edge, thisX);

	TR (thisY, freeTile, edge -> bwd -> tile, edge -> tile);
	freeTile = Null (tile_t *);
	TL (thisY, Y (edge, XR), edge -> bwd -> tile, Null (tile_t *));
    }

    if (edge -> tile -> color != color 
    || (slicingOn == 1 && (color & resBitmask))           /* AvG */
    || (split == 1 && edge -> tile -> xl <= left)) {
	/* two tiles above edge */
	thisY = Y (edge, thisX);

	BR (thisX, thisY, edge -> tile, edge -> bwd -> tile);
	freeTile = edge -> tile;

	edge -> tile = createTile (thisX, thisY, XR, Y (edge, XR),
	    color, edge -> bwd -> tile, freeTile);
	ASSERT (color == (edge -> bwd -> tile -> color ^ edge -> color));
#ifdef ENUMPOINT
	ttr = edge -> tile;
#endif /* ENUMPOINT */
    }

#ifdef ENUMPOINT
    if (tbl != tbr || ttr != ttl)
	enumPoint (thisX, thisY, tbl, tbr, ttr, ttl);
#endif /* ENUMPOINT */

}

extern bool_t optRes;

void tileAddTerm (edge, term)
edge_t     * edge;
terminal_t * term;
{
    coor_t thisX = term -> x;
    coor_t thisY = Y (edge, thisX);

    Debug (printEdge ("tileAddTerm", edge));
    ASSERT (thisX >= edge -> tile -> xl && thisX <= edge -> tile -> xr);
    ASSERT (term -> y >= thisY && term -> y <= Y(edge -> fwd, thisX));


#   if 0
    if (!optRes) {
	/* NvdM 891215, this is not ok.
	 * Split a terminal only in case of resistance extraction.
	 * Not otherwise, since this is not useful and
	 * not doing it gives slightly  better meshes
	 * for 3d extraction.
	 */

	term -> next = edge -> tile -> terms;
	edge -> tile -> terms = term;
	return;
    }
#   endif /* 0 */

    if (freeTile == Null (tile_t *)) {
	BR (thisX, thisY, edge -> tile, edge -> bwd -> tile);
	freeTile = edge -> tile;
	edge -> tile = createTile (thisX, thisY, XR, Y (edge, XR),
	    freeTile -> color, edge -> bwd -> tile, freeTile);

#ifdef ENUMPOINT
	if (edge -> bwd -> tile -> xl < thisX)
	    enumPoint (thisX, thisY,
		edge -> bwd -> tile, edge -> bwd -> tile,
		edge -> tile, freeTile);
#endif /* ENUMPOINT */
    }
    ASSERT (freeTile -> xr == thisX);

    term -> next = freeTile -> terms;
    freeTile -> terms = term;

}


void tileAdvanceScan (edge, thisX)
edge_t * edge;
coor_t thisX;
{
    tile_t * t;
    ASSERT (edge -> yr == INF);
    if (freeTile) {
	disposeTile (freeTile), freeTile = Null (tile_t *);
    }
}

void tileStopScan (head)
edge_t * head;
{
   head -> tile -> xl = -INF;
}


#ifndef TL
/* ARGSUSED */
private void TL (tl, tr, tile, t_left)
coor_t tl;
tile_t * tile, * t_left;
{
    ASSERT (tl >= tile -> bl);
    tile -> tl = tl;
    /* tile -> tr = tr; */
    Debug (printTile ("TL tile", tile));
    if (t_left) enumPair (t_left, tile, 'v');
}
#endif /* TL */

#ifndef BR
private void BR (xr, br, tile, t_bot)
tile_t * tile, * t_bot;
coor_t xr, br;
{
    Debug (printTile ("BR tile", tile));
    ASSERT (xr > tile -> xl);
    ASSERT (freeTile == Null (tile_t *));
    tile -> xr = xr, tile -> br = br;
    if (t_bot && t_bot -> xl < xr)
	enumPair (t_bot, tile, 'h');
}
#endif /* BR */

private void TR (tr, tile, t_right, t_top)
coor_t tr;
tile_t * tile, * t_right, * t_top;
{
    ASSERT (tile == freeTile);
    tile -> tr = tr;

    Debug (printTile ("finish tile", tile));

    if (t_top -> xl < tile -> xr)       /* AvG */
	enumPair (tile, t_top, 'h');  
    enumPair (tile, t_right, 'v');      /* placed after tile, t_top, AvG */
    enumTile (tile);

    clearTile (tile);
    disposeTile (tile);

    freeTile = Null (tile_t *);
}


