/*
    This software may only be used by you under license from AT&T Corp.
    ("AT&T").  A copy of AT&T's Source Code Agreement is available at
    AT&T's Internet website having the URL:
    <http://www.research.att.com/sw/tools/graphviz/license/source.html>
    If you received this software without first entering into a license
    with AT&T, you have an infringing copy of this software and cannot use
    it without violating AT&T's intellectual property rights.
*/
#pragma prototyped
#include "neato.h"
#include "mem.h"
#include "info.h"
#include "edges.h"
#include <math.h>


double pxmin, pxmax, pymin, pymax;  /* clipping window */

static int nedges;
static Freelist efl;

void
edgeinit()
{
    freeinit(&efl, sizeof (Edge));
    nedges = 0;
}

Edge *
bisect(Site *s1, Site *s2)
{
    double dx,dy,adx,ady;
    Edge *newedge;

    newedge = (Edge *) getfree(&efl);

    newedge -> reg[0] = s1;
    newedge -> reg[1] = s2;
    ref(s1); 
    ref(s2);
    newedge -> ep[0] = (Site *) NULL;
    newedge -> ep[1] = (Site *) NULL;

    dx = s2->coord.x - s1->coord.x;
    dy = s2->coord.y - s1->coord.y;
    adx = dx>0 ? dx : -dx;
    ady = dy>0 ? dy : -dy;
    newedge -> c = s1->coord.x * dx + s1->coord.y * dy + (dx*dx + dy*dy)*0.5;
    if (adx>ady)
    {	newedge -> a = 1.0; newedge -> b = dy/dx; newedge -> c /= dx;}
    else
    {	newedge -> b = 1.0; newedge -> a = dx/dy; newedge -> c /= dy;};

    newedge -> edgenbr = nedges;
#ifdef STANDALONE
    out_bisector(newedge);
#endif
    nedges += 1;
    return(newedge);
}


static void
doSeg (Edge *e, double x1, double y1, double x2, double y2)
{
    addVertex (e->reg[0], x1, y1);
    addVertex (e->reg[0], x2, y2);
    addVertex (e->reg[1], x1, y1);
    addVertex (e->reg[1], x2, y2);
}
    
void
clip_line(Edge *e)
{
    Site *s1, *s2;
    double x1,x2,y1,y2;

    if(e -> a == 1.0 && e ->b >= 0.0) {    
        s1 = e -> ep[1];
        s2 = e -> ep[0];
    }
    else {
        s1 = e -> ep[0];
        s2 = e -> ep[1];
    }

    if(e -> a == 1.0) {
        if (s1!=(Site *)NULL) {
          y1 = s1->coord.y;
          if (y1 > pymax) return;
          else if (y1 >= pymin) x1 = s1->coord.x;
          else {
            y1 = pymin;
            x1 = e -> c - e -> b * y1;
          }
        }
        else {
          y1 = pymin;
          x1 = e -> c - e -> b * y1;
        }
            
        if (s2!=(Site *)NULL) {
          y2 = s2->coord.y;
          if(y2<pymin) return;
          else if (y2 <= pymax) x2 = s2->coord.x;
          else {
            y2 = pymax;
            x2 = e -> c - e -> b * y2;
          }
        }
        else {
          y2 = pymax;
          x2 = e -> c - e -> b * y2;
        }

        if (((x1> pxmax) & (x2>pxmax)) | ((x1<pxmin) & (x2<pxmin))) return;
        if(x1> pxmax)
        {    x1 = pxmax; y1 = (e -> c - x1)/e -> b;};
        if(x1<pxmin)
        {    x1 = pxmin; y1 = (e -> c - x1)/e -> b;};
        if(x2>pxmax)
        {    x2 = pxmax; y2 = (e -> c - x2)/e -> b;};
        if(x2<pxmin)
        {    x2 = pxmin; y2 = (e -> c - x2)/e -> b;};
    }
    else {
        if (s1!=(Site *)NULL) {
          x1 = s1->coord.x;
          if(x1>pxmax) return;
          else if (x1 >= pxmin) y1 = s1->coord.y;
          else {
            x1 = pxmin;
            y1 = e -> c - e -> a * x1;
          }
        }
        else {
          x1 = pxmin;
          y1 = e -> c - e -> a * x1;
        }

        if (s2!=(Site *)NULL) {
          x2 = s2->coord.x;
          if(x2<pxmin) return;
          else if (x2 <= pxmax) y2 = s2->coord.y;
          else {
            x2 = pxmax;
            y2 = e -> c - e -> a * x2;
          }
        }
        else {
          x2 = pxmax;
          y2 = e -> c - e -> a * x2;
        }

        if (((y1>pymax)&(y2>pymax)) | ((y1<pymin)&(y2<pymin))) return;
        if(y1> pymax)
        {    y1 = pymax; x1 = (e -> c - y1)/e -> a;};
        if(y1<pymin)
        {    y1 = pymin; x1 = (e -> c - y1)/e -> a;};
        if(y2>pymax)
        {    y2 = pymax; x2 = (e -> c - y2)/e -> a;};
        if(y2<pymin)
        {    y2 = pymin; x2 = (e -> c - y2)/e -> a;};
    }
    
    doSeg(e,x1,y1,x2,y2);
#ifdef STANDALONE
    if (doPS) line (x1,y1,x2,y2);
#endif
}

void
endpoint(Edge *e, int lr, Site *s)
{
    e -> ep[lr] = s;
    ref(s);
    if(e -> ep[re-lr] == (Site *) NULL) return;
    clip_line (e);
#ifdef STANDALONE
    out_ep(e);
#endif
    deref(e->reg[le]);
    deref(e->reg[re]);
    makefree(e, &efl);
}


