Graphviz  2.29.20120524.0446
lib/neatogen/hedges.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #include "mem.h"
00015 #include "hedges.h"
00016 #include "render.h"
00017 
00018 
00019 #define DELETED -2
00020 
00021 Halfedge *ELleftend, *ELrightend;
00022 
00023 static Freelist hfl;
00024 static int ELhashsize;
00025 static Halfedge **ELhash;
00026 static int ntry, totalsearch;
00027 
00028 void ELcleanup()
00029 {
00030     freeinit(&hfl, sizeof **ELhash);
00031     free(ELhash);
00032     ELhash = NULL;
00033 }
00034 
00035 void ELinitialize()
00036 {
00037     int i;
00038 
00039     freeinit(&hfl, sizeof **ELhash);
00040     ELhashsize = 2 * sqrt_nsites;
00041     if (ELhash == NULL)
00042         ELhash = N_GNEW(ELhashsize, Halfedge *);
00043     for (i = 0; i < ELhashsize; i += 1)
00044         ELhash[i] = (Halfedge *) NULL;
00045     ELleftend = HEcreate((Edge *) NULL, 0);
00046     ELrightend = HEcreate((Edge *) NULL, 0);
00047     ELleftend->ELleft = (Halfedge *) NULL;
00048     ELleftend->ELright = ELrightend;
00049     ELrightend->ELleft = ELleftend;
00050     ELrightend->ELright = (Halfedge *) NULL;
00051     ELhash[0] = ELleftend;
00052     ELhash[ELhashsize - 1] = ELrightend;
00053 }
00054 
00055 
00056 Site *hintersect(Halfedge * el1, Halfedge * el2)
00057 {
00058     Edge *e1, *e2, *e;
00059     Halfedge *el;
00060     double d, xint, yint;
00061     int right_of_site;
00062     Site *v;
00063 
00064     e1 = el1->ELedge;
00065     e2 = el2->ELedge;
00066     if (e1 == (Edge *) NULL || e2 == (Edge *) NULL)
00067         return ((Site *) NULL);
00068     if (e1->reg[1] == e2->reg[1])
00069         return ((Site *) NULL);
00070 
00071     d = e1->a * e2->b - e1->b * e2->a;
00072     if (-1.0e-10 < d && d < 1.0e-10)
00073         return ((Site *) NULL);
00074 
00075     xint = (e1->c * e2->b - e2->c * e1->b) / d;
00076     yint = (e2->c * e1->a - e1->c * e2->a) / d;
00077 
00078     if ((e1->reg[1]->coord.y < e2->reg[1]->coord.y) ||
00079         (e1->reg[1]->coord.y == e2->reg[1]->coord.y &&
00080          e1->reg[1]->coord.x < e2->reg[1]->coord.x)) {
00081         el = el1;
00082         e = e1;
00083     } else {
00084         el = el2;
00085         e = e2;
00086     };
00087     right_of_site = xint >= e->reg[1]->coord.x;
00088     if ((right_of_site && el->ELpm == le) ||
00089         (!right_of_site && el->ELpm == re))
00090         return ((Site *) NULL);
00091 
00092     v = getsite();
00093     v->refcnt = 0;
00094     v->coord.x = xint;
00095     v->coord.y = yint;
00096     return (v);
00097 }
00098 
00099 /* returns 1 if p is to right of halfedge e */
00100 int right_of(Halfedge * el, Point * p)
00101 {
00102     Edge *e;
00103     Site *topsite;
00104     int right_of_site, above, fast;
00105     double dxp, dyp, dxs, t1, t2, t3, yl;
00106 
00107     e = el->ELedge;
00108     topsite = e->reg[1];
00109     right_of_site = p->x > topsite->coord.x;
00110     if (right_of_site && el->ELpm == le)
00111         return (1);
00112     if (!right_of_site && el->ELpm == re)
00113         return (0);
00114 
00115     if (e->a == 1.0) {
00116         dyp = p->y - topsite->coord.y;
00117         dxp = p->x - topsite->coord.x;
00118         fast = 0;
00119         if ((!right_of_site & (e->b < 0.0)) |
00120             (right_of_site & (e->b >= 0.0))) {
00121             above = dyp >= e->b * dxp;
00122             fast = above;
00123         } else {
00124             above = p->x + p->y * e->b > e->c;
00125             if (e->b < 0.0)
00126                 above = !above;
00127             if (!above)
00128                 fast = 1;
00129         };
00130         if (!fast) {
00131             dxs = topsite->coord.x - (e->reg[0])->coord.x;
00132             above = e->b * (dxp * dxp - dyp * dyp) <
00133                 dxs * dyp * (1.0 + 2.0 * dxp / dxs + e->b * e->b);
00134             if (e->b < 0.0)
00135                 above = !above;
00136         };
00137     } else {                    /*e->b==1.0 */
00138         yl = e->c - e->a * p->x;
00139         t1 = p->y - yl;
00140         t2 = p->x - topsite->coord.x;
00141         t3 = yl - topsite->coord.y;
00142         above = t1 * t1 > t2 * t2 + t3 * t3;
00143     };
00144     return (el->ELpm == le ? above : !above);
00145 }
00146 
00147 Halfedge *HEcreate(Edge * e, char pm)
00148 {
00149     Halfedge *answer;
00150     answer = (Halfedge *) getfree(&hfl);
00151     answer->ELedge = e;
00152     answer->ELpm = pm;
00153     answer->PQnext = (Halfedge *) NULL;
00154     answer->vertex = (Site *) NULL;
00155     answer->ELrefcnt = 0;
00156     return (answer);
00157 }
00158 
00159 
00160 void ELinsert(Halfedge * lb, Halfedge * new)
00161 {
00162     new->ELleft = lb;
00163     new->ELright = lb->ELright;
00164     (lb->ELright)->ELleft = new;
00165     lb->ELright = new;
00166 }
00167 
00168 /* Get entry from hash table, pruning any deleted nodes */
00169 static Halfedge *ELgethash(int b)
00170 {
00171     Halfedge *he;
00172 
00173     if (b < 0 || b >= ELhashsize)
00174         return ((Halfedge *) NULL);
00175     he = ELhash[b];
00176     if (he == (Halfedge *) NULL || he->ELedge != (Edge *) DELETED)
00177         return (he);
00178 
00179 /* Hash table points to deleted half edge.  Patch as necessary. */
00180     ELhash[b] = (Halfedge *) NULL;
00181     if ((he->ELrefcnt -= 1) == 0)
00182         makefree(he, &hfl);
00183     return ((Halfedge *) NULL);
00184 }
00185 
00186 Halfedge *ELleftbnd(Point * p)
00187 {
00188     int i, bucket;
00189     Halfedge *he;
00190 
00191 /* Use hash table to get close to desired halfedge */
00192     bucket = (p->x - xmin) / deltax * ELhashsize;
00193     if (bucket < 0)
00194         bucket = 0;
00195     if (bucket >= ELhashsize)
00196         bucket = ELhashsize - 1;
00197     he = ELgethash(bucket);
00198     if (he == (Halfedge *) NULL) {
00199         for (i = 1; 1; i += 1) {
00200             if ((he = ELgethash(bucket - i)) != (Halfedge *) NULL)
00201                 break;
00202             if ((he = ELgethash(bucket + i)) != (Halfedge *) NULL)
00203                 break;
00204         };
00205         totalsearch += i;
00206     };
00207     ntry += 1;
00208 /* Now search linear list of halfedges for the corect one */
00209     if (he == ELleftend || (he != ELrightend && right_of(he, p))) {
00210         do {
00211             he = he->ELright;
00212         } while (he != ELrightend && right_of(he, p));
00213         he = he->ELleft;
00214     } else
00215         do {
00216             he = he->ELleft;
00217         } while (he != ELleftend && !right_of(he, p));
00218 
00219 /* Update hash table and reference counts */
00220     if (bucket > 0 && bucket < ELhashsize - 1) {
00221         if (ELhash[bucket] != (Halfedge *) NULL)
00222             ELhash[bucket]->ELrefcnt -= 1;
00223         ELhash[bucket] = he;
00224         ELhash[bucket]->ELrefcnt += 1;
00225     };
00226     return (he);
00227 }
00228 
00229 
00230 /* This delete routine can't reclaim node, since pointers from hash
00231    table may be present.   */
00232 void ELdelete(Halfedge * he)
00233 {
00234     (he->ELleft)->ELright = he->ELright;
00235     (he->ELright)->ELleft = he->ELleft;
00236     he->ELedge = (Edge *) DELETED;
00237 }
00238 
00239 
00240 Halfedge *ELright(Halfedge * he)
00241 {
00242     return (he->ELright);
00243 }
00244 
00245 Halfedge *ELleft(Halfedge * he)
00246 {
00247     return (he->ELleft);
00248 }
00249 
00250 
00251 Site *leftreg(Halfedge * he)
00252 {
00253     if (he->ELedge == (Edge *) NULL)
00254         return (bottomsite);
00255     return (he->ELpm == le ? he->ELedge->reg[le] : he->ELedge->reg[re]);
00256 }
00257 
00258 Site *rightreg(Halfedge * he)
00259 {
00260     if (he->ELedge == (Edge *) NULL)
00261         return (bottomsite);
00262     return (he->ELpm == le ? he->ELedge->reg[re] : he->ELedge->reg[le]);
00263 }