static char *SccsId = "@(#)input.c 4.8 (TU-Delft) 06/25/93";
/**********************************************************

Name/Version      : makegln/4.8

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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "dmincl.h"
#include "aux/aux.h"
#include "makegln.h"

static int scale;

#define Scale(x)      ((coor_t) (scale * (x)))
#define RoundScale(x) ((coor_t) ((x) > 0 ? (scale * (x) + 0.5) : (scale * (x) - 0.5)))

extern bool_t optNoDelete;

private void polyEdge ();
private void polySkip ();
private void polySort ();
private void readBxx ();
private void readNxx ();
private void readTerminals ();

extern  void sortEdge ();

readEdges (cellKey, mask, masktype, scaleFactor)
DM_CELL * cellKey;
char * mask;
int masktype;
int scaleFactor;
{
    scale = scaleFactor;

    readBxx (cellKey, mask);
    readNxx (cellKey, mask);
    if (masktype == DM_INTCON_MASK)
	readTerminals (cellKey, mask);

}

private void readBxx (cellKey, mask)
DM_CELL * cellKey;
char * mask;
{
    void sortEdge ();
    DM_STREAM * stream;

    stream = dmOpenStream (cellKey, mprintf ("%s_bxx", mask), "r");

    while (dmGetDesignData (stream, GEO_BOXLAY) > 0) {

	if (gboxlay.chk_type != 0) continue; /* for space extract!!! */

	sortEdge (Scale (gboxlay.xl),
		  Scale (gboxlay.yb),
		  Scale (gboxlay.xr),
		  Scale (gboxlay.yb), 0, START);

	sortEdge (Scale (gboxlay.xl),
		  Scale (gboxlay.yt),
		  Scale (gboxlay.xr),
		  Scale (gboxlay.yt), 0, STOP);
    }

    dmCloseStream (stream, COMPLETE);

    if (optNoDelete == FALSE)
	dmUnlink (cellKey, mprintf ("%s_bxx", mask));
}

private void readNxx (cellKey, mask)
DM_CELL * cellKey;
char * mask;
{
    DM_STREAM * stream;
    void        polyEdge ();
    void        polySort ();
    void        polySkip ();
    int         noXy;
    int         skip;
    slope_t     slope;
    coor_t      x0, y0, x1, y1, x2, y2;
    struct      stat st_buf;
    int rounded = 0;

    /* Return immediately if nxx file does not exist
     */
    if (dmStat (cellKey, mprintf ("%s_nxx", mask), &st_buf) == -1)
	return;

    stream = dmOpenStream (cellKey, mprintf ("%s_nxx", mask), "r");

    while (dmGetDesignData (stream, GEO_NXX_INI) > 0) {
	noXy = gnxx_ini.no_xy;

	/* skip unknown and unsupported element types and give a warning
	 */
	switch (gnxx_ini.elmt) {
	    case POLY_NOR:
	    case RECT_NOR:
		 break; /* these are OK */

	    case SBOX_NOR:
	    case WIRE_NOR: /* break;  /* these are NOT OK */
		while (--noXy >= 0)
		    dmGetDesignData (stream, GEO_NXX_XY);
		say ("Warning: cell %s, mask %s, element of type %d skipped",
		    cellKey -> cell, mask, gnxx_ini.elmt);
		continue;

	    case CIRCLE_NOR:
		while (--noXy >= 0)
		    dmGetDesignData (stream, GEO_NXX_XY);
		say ("Warning: cell %s, mask %s, circle element skipped",
		    cellKey -> cell, mask);
		continue;

	    default:
		while (--noXy >= 0)
		    dmGetDesignData (stream, GEO_NXX_XY);
		say ("Warning: cell %s, mask %s, unknown element: %d",
		    cellKey -> cell, mask, gnxx_ini.elmt);
		continue;
	}

	dmGetDesignData (stream, GEO_NXX_XY);
	x0 = x1 = RoundScale (gnxx_xy.x);
	y0 = y1 = RoundScale (gnxx_xy.y);

	if (rounded == 0 
	&& (   (Scale (gnxx_xy.x) != x1)
	    || (Scale (gnxx_xy.y) != y1))) {

	    say ("Warning: cell %s, mask %s: feature(s) not on grid, rounded",
			cellKey -> cell, mask);
	    rounded = 1;
	}

	skip = 0;

	while (noXy-- > 0) {
	    if (noXy > 0) {
		dmGetDesignData (stream, GEO_NXX_XY);
		x2 = RoundScale (gnxx_xy.x);
		y2 = RoundScale (gnxx_xy.y);
		if (rounded == 0 
		&& (   (Scale (gnxx_xy.x) != x2)
		    || (Scale (gnxx_xy.y) != y2))) {
		    say ("Warning: cell %s, mask %s: feature(s) not on grid, rounded",
				cellKey -> cell, mask);
		    rounded = 1;
		}
	    }
	    else {
		x2 = x0;
		y2 = y0;
	    }
	    if (x2 == x1) {
		y1 = y2;
		continue;		/* vertical edge, skip it */
	    }

	    if (y2 == y1)
		slope = 0;
	    else if (y2 - y1 == x2 - x1)
		slope = 1;
	    else if (y2 - y1 == x1 - x2)
		slope = -1;
	    else {
		if (skip == 0) {
	    say ("Warning: cell %s, mask %s: non-45 degree feature(s), skipped",
			cellKey -> cell, mask);
		    /*
		    say ("Element type: %d", gnxx_ini.elmt);
		    */
		    skip = 1;
		}
	    }

#if 0
	    slope = (slope_t) ((y2 - y1) / (x2 - x1)); !!!
#endif

	    if (x2 > x1) {		/* START */
		polyEdge (x1, y1, x2, y2, slope, START);
	    }
	    else {			/* STOP */
		polyEdge (x2, y2, x1, y1, slope, STOP);
	    }

	    x1 = x2;
	    y1 = y2;
	}

	if (!skip)
	    polySort ();
	else
	    polySkip ();
    }

    dmCloseStream (stream, COMPLETE);

    if (optNoDelete == FALSE)
	dmUnlink (cellKey, mprintf ("%s_nxx", mask));
}

private void readTerminals (cellKey, mask)
DM_CELL * cellKey;
char * mask;
{
    DM_STREAM * stream;
    void sortEdge ();

    stream = dmOpenStream (cellKey, mprintf ("t_%s_bxx", mask), "r");

    while (dmGetDesignData (stream, GEO_BOXLAY) > 0) {

	sortEdge (Scale (gboxlay.xl),
		  Scale (gboxlay.yb),
		  Scale (gboxlay.xr),
		  Scale (gboxlay.yb), 0, START);

	sortEdge (Scale (gboxlay.xl),
		  Scale (gboxlay.yt),
		  Scale (gboxlay.xr),
		  Scale (gboxlay.yt), 0, STOP);
    }

    dmCloseStream (stream, COMPLETE);
}


static _edge_t * eBuf = NULL;
static int       eCnt = 0;

private void polyEdge (xl, yl, xr, yr, slope, sign)
coor_t xl, yl, xr, yr;
slope_t slope;
int sign;
{
    static int      eSize = 0;
    _edge_t * e;

    if (eCnt >= eSize) {
	unsigned to = eSize == 0 ? 100 : 2 * eSize;
	eBuf = GROW (_edge_t, eBuf, eSize, to);
	eSize = to;
    }

    e = eBuf + eCnt++;

    e -> xl = xl, e -> xr = xr;
    e -> yl = yl, e -> yr = yr;
    e -> slope = slope;
    e -> sign = sign;

}

private void polySort ()
{
    register int i;
    register _edge_t * min = eBuf;

    for (i = 1; i < eCnt; i++) {
	if (smaller (eBuf + i, min))
	    min = eBuf + i;
    }

    if (min -> sign == STOP) {
	for (i = 0; i < eCnt; i++) {
	    if (eBuf[i].sign == STOP)
		eBuf[i].sign  = START;
	    else
		eBuf[i].sign  = STOP;
	}
    }

    ASSERT (min -> sign == START);

    for (i = 0; i < eCnt; i++) {
	sortEdge (eBuf[i].xl, eBuf[i].yl, eBuf[i].xr, eBuf[i].yr,
		  eBuf[i].slope, eBuf[i].sign);
    }

    eCnt = 0;
}


private void polySkip ()
{
#ifdef DEBUG
    register _edge_t * e;
    int i;
    double slope;
    say ("xl, xr, yl, yr, slope");
    for (i = 0; i < eCnt; i++) {
	e = eBuf + i;

	if ( e -> xr == e -> xl) 
	    slope = 999999;
	else 
	    slope = (double) (e -> yr - e -> yl) / (double) (e -> xr - e -> xl);

	fprintf (stderr, "%d %d %d %d %g\n",
	    e -> xl, e -> xr, e -> yl, e -> yr, slope);
    }
#endif DEBUG

    eCnt = 0;
}
