#ifndef lint
static char *SccsId = "@(#)swire.c 4.3 (TU-Delft) 12/11/91";
#endif
#ifdef apollo
#include "/sys5/usr/include/math.h"
#else
#include <math.h>
#endif
#include <stdio.h>
#include "defs.h"

/* should be defined in defs.h instead of in incl.h */
#define Round(x) (((x) > 0) ? ((x)+0.5) : ((x)-0.5))

/* sqrt (2.0) -> M_SQRT2  */

extern int  width;
extern int  nr_coor;		/* Note an X, Y pair is counted as 2 */
extern int  lay_code;
extern int  pathtype;
extern int  int_val[];
extern double   resolution;

static int  ese_int_val[256];	/* this should be a #define */
static int  ese_nr_coor;
static int  ese_width;

void    quadragon ();
void    stop_or_end_of_wire ();
int     segment_of_wire ();
int     ese_swire ();
void    put_coor_on_grid ();
double  distance ();

void
quadragon (layer_code, x1, Y1, x2, y2, x3, y3, x4, y4)
int     layer_code;
double  x1, Y1, x2, y2, x3, y3, x4, y4;
{
    lay_code = layer_code;

    put_coor_on_grid (&x1, &Y1);
    put_coor_on_grid (&x2, &y2);
    put_coor_on_grid (&x3, &y3);
    put_coor_on_grid (&x4, &y4);

    _quadragon (x1, Y1, x2, y2, x3, y3, x4, y4);
}

int
ese_swire ()
{
    int     i, x1, Y1, x2, y2, x3, y3;
    double  dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6, dy6;
    double  atan2 ();

 /* copy array */
    ese_nr_coor = nr_coor;
    for (i = 0; i < ese_nr_coor; i++) {
	ese_int_val[i] = (int) Round (int_val[i] * resolution);
    }
    ese_width = (int) Round (width * resolution);

 /* Check for 45 degree and progress */
    for (i = 2; i < ese_nr_coor; i += 2) {
	x1 = ese_int_val[i - 2];
	Y1 = ese_int_val[i - 1];
	x2 = ese_int_val[i];
	y2 = ese_int_val[i + 1];

	if (x1 != x2 && Y1 != y2 && x1 - x2 != Y1 - y2 && x1 - x2 != y2 - Y1) {
	    PE "*** Error: Not a 45 degree angle design\n");
	/* pr_exit( W, 35, 0 ); */
	    return (1);
	}
	if (x1 == x2 && Y1 == y2) {
	    PE "*** Error: No increment in wire\n");
	/* pr_exit( W, 24, 0 ); */
	    return (1);
	}
    }

    x1 = ese_int_val[0];
    Y1 = ese_int_val[1];
    x2 = ese_int_val[2];
    y2 = ese_int_val[3];

    stop_or_end_of_wire (x1, Y1, x2, y2, &dx1, &dy1, &dx2, &dy2);

    for (i = 4; i < ese_nr_coor; i += 2) {
	x1 = ese_int_val[i - 4];
	Y1 = ese_int_val[i - 3];
	x2 = ese_int_val[i - 2];
	y2 = ese_int_val[i - 1];
	x3 = ese_int_val[i];
	y3 = ese_int_val[i + 1];

	if (pathtype == 1) {
	    stop_or_end_of_wire (x2, y2, x1, Y1, &dx3, &dy3, &dx4, &dy4);
	    quadragon (lay_code, dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4);
	    stop_or_end_of_wire (x2, y2, x3, y3, &dx1, &dy1, &dx2, &dy2);
	}
	else {
	/* If there is a bend in the wire */
	    if (segment_of_wire (x1, Y1, x2, y2, x3, y3,
		    &dx3, &dy3, &dx4, &dy4, &dx5, &dy5, &dx6, &dy6)) {
		quadragon (lay_code, dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4);
		dx2 = dx5;
		dy2 = dy5;
		dx1 = dx6;
		dy1 = dy6;
	    }
	}
    }

    x1 = ese_int_val[ese_nr_coor - 4];
    Y1 = ese_int_val[ese_nr_coor - 3];
    x2 = ese_int_val[ese_nr_coor - 2];
    y2 = ese_int_val[ese_nr_coor - 1];

    stop_or_end_of_wire (x2, y2, x1, Y1, &dx3, &dy3, &dx4, &dy4);
    quadragon (lay_code, dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4);
    return (0);
}

void
stop_or_end_of_wire (x1, Y1, x2, y2, dx1, dy1, dx2, dy2)
int     x1, Y1, x2, y2;
double *dx1, *dy1, *dx2, *dy2;
{
    double  dx3, dy3, dx4, dy4;
    double  vx = 0.0, vy = 0.0;
    double  wx, wy;
    double  length;

 /* Calculate the basic vector direction */
    if (x2 - x1) vx = (x2 - x1) / abs (x2 - x1);
    if (y2 - Y1) vy = (y2 - Y1) / abs (y2 - Y1);

 /* Make the length of vector 1 */
    length = sqrt (vx * vx + vy * vy);
    vx /= length;
    vy /= length;

 /* Offset plus basic vector rotated 90 degree's */
    *dx1 = x1 - vy * ese_width / 2;
    *dy1 = Y1 + vx * ese_width / 2;

 /* Offset plus basic vector rotated 270 degree's */
    *dx2 = x1 + vy * ese_width / 2;
    *dy2 = Y1 - vx * ese_width / 2;

    if (pathtype == 1) {
	wx = vx * ese_width / (2 * M_SQRT2 + 2);
	wy = vy * ese_width / (2 * M_SQRT2 + 2);

	*dx1 -= wx;
	*dy1 -= wy;
	*dx2 -= wx;
	*dy2 -= wy;

	wx *= M_SQRT2;
	wy *= M_SQRT2;

	dx3 = *dx2 - wx - wy;
	dy3 = *dy2 - wy + wx;
	dx4 = *dx1 - wx + wy;
	dy4 = *dy1 - wy - wx;

	quadragon (lay_code, *dx1, *dy1, *dx2, *dy2, dx3, dy3, dx4, dy4);
    }
    else
	if (pathtype == 2) {
	    *dx1 -= (vx * ese_width / 2);
	    *dy1 -= (vy * ese_width / 2);
	    *dx2 -= (vx * ese_width / 2);
	    *dy2 -= (vy * ese_width / 2);
	}
}

int
segment_of_wire (x1, Y1, x2, y2, x3, y3,
            dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4)
int     x1, Y1, x2, y2, x3, y3;
double *dx1, *dy1, *dx2, *dy2, *dx3, *dy3, *dx4, *dy4;
{
    double  vx  = 0.0, vy  = 0.0;
    double  vx1 = 0.0, vy1 = 0.0;
    double  vx2 = 0.0, vy2 = 0.0;
    double  length;

 /* Calculate the basic vector direction */
    if (x1 - x2) vx1 = (x1 - x2) / abs (x1 - x2);
    if (Y1 - y2) vy1 = (Y1 - y2) / abs (Y1 - y2);

 /* Make the length of vector 1 */
    length = sqrt (vx1 * vx1 + vy1 * vy1);
    vx1 /= length;
    vy1 /= length;

 /* Calculate the basic vector direction */
    if (x3 - x2) vx2 = (x3 - x2) / abs (x3 - x2);
    if (y3 - y2) vy2 = (y3 - y2) / abs (y3 - y2);

 /* Make the length of vector 1 */
    length = sqrt (vx2 * vx2 + vy2 * vy2);
    vx2 /= length;
    vy2 /= length;

    vx = vx1 + vx2;
    vy = vy1 + vy2;

 /* There is no bend */
    if (vx == 0.0 && vy == 0.0) return (0);

 /* Give it the proper lenght this is not 1 !!! */
    length = (vx1 * vx2 + vy1 * vy2) * (vx1 * vx2 + vy1 * vy2)
					* (M_SQRT2 - 1) * 2.0 + 1.0;
    vx *= length;
    vy *= length;

 /* Corner is offsett plus plus basic vector */
    *dx1 = x2 + vx * ese_width / 2;
    *dy1 = y2 + vy * ese_width / 2;
    *dx3 = x2 - vx * ese_width / 2;
    *dy3 = y2 - vy * ese_width / 2;

 /* The direction of the corners from the offset */
    if ((vx1 * vy2 - vy1 * vx2) > 0.0) {
	*dx2 = *dx1 + vy1 * ese_width;
	*dy2 = *dy1 - vx1 * ese_width;
	*dx4 = *dx1 - vy2 * ese_width;
	*dy4 = *dy1 + vx2 * ese_width;

	quadragon (lay_code, *dx1, *dy1, *dx2, *dy2, *dx3, *dy3, *dx4, *dy4);

	*dx3 = *dx1;
	*dy3 = *dy1;
    }
    else {
	*dx2 = *dx1 - vy1 * ese_width;
	*dy2 = *dy1 + vx1 * ese_width;
	*dx4 = *dx1 + vy2 * ese_width;
	*dy4 = *dy1 - vx2 * ese_width;

	quadragon (lay_code, *dx1, *dy1, *dx2, *dy2, *dx3, *dy3, *dx4, *dy4);

	*dx3 = *dx4;
	*dy3 = *dy4;
	*dx4 = *dx1;
	*dy4 = *dy1;
	*dx1 = *dx2;
	*dy1 = *dy2;
	*dx2 = *dx4;
	*dy2 = *dy4;
    }
    return (1); /* Succesfull return */
}

double
distance (x1, Y1, x2, y2)
double  x1, Y1, x2, y2;
{
    return (sqrt ((x2 - x1) * (x2 - x1) + (y2 - Y1) * (y2 - Y1)));
}

void
put_coor_on_grid (dx, dy)
double *dx, *dy;
{
/* This is the area where the coordinate is in */
    int     Xmin = (int) floor (*dx * 4.0);
    int     Ymin = (int) floor (*dy * 4.0);
    int     Xmax = (int) floor (*dx * 4.0) + 1;
    int     Ymax = (int) floor (*dy * 4.0) + 1;

    double  dis = 2.0;		/* two is a big number here */
    double  tx, ty;

/* check if coordinate is OK */
    if ((abs (Xmin) & 1) == (abs (Ymin) & 1) &&
	    dis > distance ((double) Xmin, (double) Ymin, *dx * 4, *dy * 4)) {
	dis = distance ((double) Xmin, (double) Ymin, *dx * 4, *dy * 4);
	tx = Xmin / 4.0;
	ty = Ymin / 4.0;
    }
    if ((abs (Xmin) & 1) == (abs (Ymax) & 1) &&
	    dis > distance ((double) Xmin, (double) Ymax, *dx * 4, *dy * 4)) {
	dis = distance ((double) Xmin, (double) Ymax, *dx * 4, *dy * 4);
	tx = Xmin / 4.0;
	ty = Ymax / 4.0;
    }
    if ((abs (Xmax) & 1) == (abs (Ymin) & 1) &&
	    dis > distance ((double) Xmax, (double) Ymin, *dx * 4, *dy * 4)) {
	dis = distance ((double) Xmax, (double) Ymin, *dx * 4, *dy * 4);
	tx = Xmax / 4.0;
	ty = Ymin / 4.0;
    }
    if ((abs (Xmax) & 1) == (abs (Ymax) & 1) &&
	    dis > distance ((double) Xmax, (double) Ymax, *dx * 4, *dy * 4)) {
	dis = distance ((double) Xmax, (double) Ymax, *dx * 4, *dy * 4);
	tx = Xmax / 4.0;
	ty = Ymax / 4.0;
    }

    *dx = tx;
    *dy = ty;
}
