/*
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 "mem.h"
#include "hedges.h"
#include "render.h"
#define DELETED -2
Halfedge *ELleftend, *ELrightend;
static Freelist hfl;
static int ELhashsize;
static Halfedge **ELhash;
static int ntry, totalsearch;
void ELcleanup()
{
freeinit(&hfl, sizeof **ELhash);
free (ELhash);
ELhash = NULL;
}
void
ELinitialize()
{
int i;
freeinit(&hfl, sizeof **ELhash);
ELhashsize = 2 * sqrt_nsites;
if (ELhash == NULL)
ELhash = N_GNEW (ELhashsize, Halfedge *);
for(i=0; i<ELhashsize; i +=1) ELhash[i] = (Halfedge *)NULL;
ELleftend = HEcreate( (Edge *)NULL, 0);
ELrightend = HEcreate( (Edge *)NULL, 0);
ELleftend -> ELleft = (Halfedge *)NULL;
ELleftend -> ELright = ELrightend;
ELrightend -> ELleft = ELleftend;
ELrightend -> ELright = (Halfedge *)NULL;
ELhash[0] = ELleftend;
ELhash[ELhashsize-1] = ELrightend;
}
Site *
hintersect(Halfedge *el1, Halfedge *el2)
{
Edge *e1,*e2, *e;
Halfedge *el;
double d, xint, yint;
int right_of_site;
Site *v;
e1 = el1 -> ELedge;
e2 = el2 -> ELedge;
if(e1 == (Edge*)NULL || e2 == (Edge*)NULL)
return ((Site *) NULL);
if (e1->reg[1] == e2->reg[1]) return ((Site *) NULL);
d = e1->a * e2->b - e1->b * e2->a;
if (-1.0e-10<d && d<1.0e-10) return ((Site *) NULL);
xint = (e1->c*e2->b - e2->c*e1->b)/d;
yint = (e2->c*e1->a - e1->c*e2->a)/d;
if( (e1->reg[1]->coord.y < e2->reg[1]->coord.y) ||
(e1->reg[1]->coord.y == e2->reg[1]->coord.y &&
e1->reg[1]->coord.x < e2->reg[1]->coord.x) )
{ el = el1; e = e1;}
else
{ el = el2; e = e2;};
right_of_site = xint >= e -> reg[1] -> coord.x;
if ((right_of_site && el -> ELpm == le) ||
(!right_of_site && el -> ELpm == re)) return ((Site *) NULL);
v = getsite ();
v -> refcnt = 0;
v -> coord.x = xint;
v -> coord.y = yint;
return(v);
}
/* returns 1 if p is to right of halfedge e */
int
right_of(Halfedge *el, Point *p)
{
Edge *e;
Site *topsite;
int right_of_site, above, fast;
double dxp, dyp, dxs, t1, t2, t3, yl;
e = el -> ELedge;
topsite = e -> reg[1];
right_of_site = p -> x > topsite -> coord.x;
if(right_of_site && el -> ELpm == le) return(1);
if(!right_of_site && el -> ELpm == re) return (0);
if (e->a == 1.0)
{ dyp = p->y - topsite->coord.y;
dxp = p->x - topsite->coord.x;
fast = 0;
if ((!right_of_site & (e->b<0.0)) | (right_of_site & (e->b>=0.0)) )
{ above = dyp>= e->b*dxp;
fast = above;
}
else
{ above = p->x + p->y*e->b > e-> c;
if(e->b<0.0) above = !above;
if (!above) fast = 1;
};
if (!fast)
{ dxs = topsite->coord.x - (e->reg[0])->coord.x;
above = e->b * (dxp*dxp - dyp*dyp) <
dxs*dyp*(1.0+2.0*dxp/dxs + e->b*e->b);
if(e->b<0.0) above = !above;
};
}
else /*e->b==1.0 */
{ yl = e->c - e->a*p->x;
t1 = p->y - yl;
t2 = p->x - topsite->coord.x;
t3 = yl - topsite->coord.y;
above = t1*t1 > t2*t2 + t3*t3;
};
return (el->ELpm==le ? above : !above);
}
Halfedge *
HEcreate(Edge *e, char pm)
{
Halfedge *answer;
answer = (Halfedge *) getfree(&hfl);
answer -> ELedge = e;
answer -> ELpm = pm;
answer -> PQnext = (Halfedge *) NULL;
answer -> vertex = (Site *) NULL;
answer -> ELrefcnt = 0;
return(answer);
}
void
ELinsert(Halfedge *lb, Halfedge *new)
{
new -> ELleft = lb;
new -> ELright = lb -> ELright;
(lb -> ELright) -> ELleft = new;
lb -> ELright = new;
}
/* Get entry from hash table, pruning any deleted nodes */
static Halfedge *
ELgethash(int b)
{
Halfedge *he;
if(b<0 || b>=ELhashsize) return((Halfedge *) NULL);
he = ELhash[b];
if (he == (Halfedge *) NULL ||
he -> ELedge != (Edge *) DELETED ) return (he);
/* Hash table points to deleted half edge. Patch as necessary. */
ELhash[b] = (Halfedge *) NULL;
if ((he -> ELrefcnt -= 1) == 0) makefree(he, &hfl);
return ((Halfedge *) NULL);
}
Halfedge *
ELleftbnd(Point *p)
{
int i, bucket;
Halfedge *he;
/* Use hash table to get close to desired halfedge */
bucket = (p->x - xmin)/deltax * ELhashsize;
if(bucket<0) bucket =0;
if(bucket>=ELhashsize) bucket = ELhashsize - 1;
he = ELgethash(bucket);
if(he == (Halfedge *) NULL)
{ for(i=1; 1 ; i += 1)
{ if ((he=ELgethash(bucket-i)) != (Halfedge *) NULL) break;
if ((he=ELgethash(bucket+i)) != (Halfedge *) NULL) break;
};
totalsearch += i;
};
ntry += 1;
/* Now search linear list of halfedges for the corect one */
if (he==ELleftend || (he != ELrightend && right_of(he,p)))
{do {he = he -> ELright;} while (he!=ELrightend && right_of(he,p));
he = he -> ELleft;
}
else
do {he = he -> ELleft;} while (he!=ELleftend && !right_of(he,p));
/* Update hash table and reference counts */
if(bucket > 0 && bucket <ELhashsize-1)
{ if(ELhash[bucket] != (Halfedge *) NULL)
ELhash[bucket] -> ELrefcnt -= 1;
ELhash[bucket] = he;
ELhash[bucket] -> ELrefcnt += 1;
};
return (he);
}
/* This delete routine can't reclaim node, since pointers from hash
table may be present. */
void
ELdelete(Halfedge *he)
{
(he -> ELleft) -> ELright = he -> ELright;
(he -> ELright) -> ELleft = he -> ELleft;
he -> ELedge = (Edge *)DELETED;
}
Halfedge *
ELright(Halfedge *he)
{
return (he -> ELright);
}
Halfedge *
ELleft(Halfedge *he)
{
return (he -> ELleft);
}
Site *
leftreg(Halfedge *he)
{
if(he -> ELedge == (Edge *)NULL) return(bottomsite);
return( he -> ELpm == le ?
he -> ELedge -> reg[le] : he -> ELedge -> reg[re]);
}
Site *
rightreg(Halfedge *he)
{
if(he -> ELedge == (Edge *)NULL) return(bottomsite);
return( he -> ELpm == le ?
he -> ELedge -> reg[re] : he -> ELedge -> reg[le]);
}
|