/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/common/routespl.c

Go to the documentation of this file.
00001 /* $Id: routespl.c,v 1.13 2007/10/12 00:40:59 erg Exp $ $Revision: 1.13 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 #include "render.h"
00019 #include "pathplan.h"
00020 
00021 #ifdef UNUSED
00022 static box *bs = NULL;
00023 static int bn;
00024 static int maxbn = 0;
00025 #define BINC 300
00026 #endif
00027 
00028 #define PINC 300
00029 
00030 #ifdef NOTNOW
00031 static edge_t *origedge;
00032 #endif
00033 
00034 static int nedges, nboxes; /* total no. of edges and boxes used in routing */
00035 
00036 static int routeinit;
00037 /* static data used across multiple edges */
00038 static point *ps;             /* final spline points */
00039 static int maxpn;             /* size of ps[] */
00040 static Ppoint_t *polypoints;  /* vertices of polygon defined by boxes */
00041 static int polypointn;        /* size of polypoints[] */
00042 static Pedge_t *edges;        /* polygon edges passed to Proutespline */
00043 static int edgen;             /* size of edges[] */
00044 
00045 static void checkpath(int, box*, path*);
00046 static void mkspacep(int size);
00047 static void printpath(path * pp);
00048 #ifdef OBSOLETE
00049 static int append(path * path, int bi, point p0, point p1, int);
00050 #endif
00051 #ifdef DEBUG
00052 static void printboxes(int boxn, box* boxes)
00053 {
00054     point ll, ur;
00055     int bi;
00056     char buf[BUFSIZ];
00057     int newcnt = Show_cnt + boxn;
00058 
00059     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00060     for (bi = 0; bi < boxn; bi++) {
00061         ll = boxes[bi].LL, ur = boxes[bi].UR;
00062         sprintf(buf, "%d %d %d %d pathbox", ll.x, ll.y, ur.x, ur.y);
00063         Show_boxes[bi+1+Show_cnt] = strdup (buf);
00064     }
00065     Show_cnt = newcnt;
00066     Show_boxes[Show_cnt+1] = NULL;
00067 }
00068 
00069 static void psprintpolypts(Ppoint_t * p, int sz)
00070 {
00071     int i;
00072 
00073     fprintf(stderr, "%%!\n");
00074     fprintf(stderr, "%% constraint poly\n");
00075     fprintf(stderr, "newpath\n");
00076     for (i = 0; i < sz; i++)
00077         fprintf(stderr, "%f %f %s\n", p[i].x, p[i].y,
00078                 (i == 0 ? "moveto" : "lineto"));
00079     fprintf(stderr, "closepath stroke\n");
00080 }
00081 static void psprintpoint(point p)
00082 {
00083     fprintf(stderr, "gsave\n");
00084     fprintf(stderr,
00085             "newpath %d %d moveto %d %d 2 0 360 arc closepath fill stroke\n",
00086             p.x, p.y, p.x, p.y);
00087     fprintf(stderr, "/Times-Roman findfont 4 scalefont setfont\n");
00088     fprintf(stderr, "%d %d moveto (\\(%d,%d\\)) show\n", p.x + 5, p.y + 5,
00089             p.x, p.y);
00090     fprintf(stderr, "grestore\n");
00091 }
00092 
00093 static void psprintspline(Ppolyline_t spl)
00094 {
00095     char buf[BUFSIZ];
00096     int newcnt = Show_cnt + spl.pn + 4;
00097     int li, i;
00098 
00099     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00100     li = Show_cnt+1;
00101     Show_boxes[li++] = strdup ("%%!");
00102     Show_boxes[li++] = strdup ("%% spline");
00103     Show_boxes[li++] = strdup ("gsave 1 0 0 setrgbcolor newpath");
00104     for (i = 0; i < spl.pn; i++) {
00105         sprintf(buf, "%f %f %s", spl.ps[i].x, spl.ps[i].y,
00106           (i == 0) ?  "moveto" : ((i % 3 == 0) ? "curveto" : ""));
00107         Show_boxes[li++] = strdup (buf);
00108     }
00109     Show_boxes[li++] = strdup ("stroke grestore");
00110     Show_cnt = newcnt;
00111     Show_boxes[Show_cnt+1] = NULL;
00112 }
00113 
00114 static void psprintline(Ppolyline_t pl)
00115 {
00116     char buf[BUFSIZ];
00117     int newcnt = Show_cnt + pl.pn + 4;
00118     int i, li;
00119 
00120     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00121     li = Show_cnt+1;
00122     Show_boxes[li++] = strdup ("%%!");
00123     Show_boxes[li++] = strdup ("%% line");
00124     Show_boxes[li++] = strdup ("gsave 0 0 1 setrgbcolor newpath");
00125     for (i = 0; i < pl.pn; i++) {
00126         sprintf(buf, "%f %f %s", pl.ps[i].x, pl.ps[i].y,
00127                 (i == 0 ? "moveto" : "lineto"));
00128         Show_boxes[li++] = strdup (buf);
00129     }
00130     Show_boxes[li++] = strdup ("stroke grestore");
00131     Show_cnt = newcnt;
00132     Show_boxes[Show_cnt+1] = NULL;
00133 }
00134 
00135 static void psprintpoly(Ppoly_t p)
00136 {
00137     char buf[BUFSIZ];
00138     int newcnt = Show_cnt + p.pn + 3;
00139     point tl, hd;
00140     int bi, li;
00141     char*  pfx;
00142 
00143     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00144     li = Show_cnt+1;
00145     Show_boxes[li++] = strdup ("%% poly list");
00146     Show_boxes[li++] = strdup ("gsave 0 1 0 setrgbcolor");
00147     for (bi = 0; bi < p.pn; bi++) {
00148         tl.x = (int)p.ps[bi].x;
00149         tl.y = (int)p.ps[bi].y;
00150         hd.x = (int)p.ps[(bi+1) % p.pn].x;
00151         hd.y = (int)p.ps[(bi+1) % p.pn].y;
00152         if ((tl.x == hd.x) && (tl.y == hd.y)) pfx = "%%";
00153         else pfx ="";
00154         sprintf(buf, "%s%d %d %d %d makevec", pfx, tl.x, tl.y, hd.x, hd.y);
00155         Show_boxes[li++] = strdup (buf);
00156     }
00157     Show_boxes[li++] = strdup ("grestore");
00158 
00159     Show_cnt = newcnt;
00160     Show_boxes[Show_cnt+1] = NULL;
00161 }
00162 
00163 static void psprintboxes(int boxn, box* boxes)
00164 {
00165     char buf[BUFSIZ];
00166     int newcnt = Show_cnt + 5*boxn + 3;
00167     point ll, ur;
00168     int bi, li;
00169 
00170     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00171     li = Show_cnt+1;
00172     Show_boxes[li++] = strdup ("%% box list");
00173     Show_boxes[li++] = strdup ("gsave 0 1 0 setrgbcolor");
00174     for (bi = 0; bi < boxn; bi++) {
00175         ll = boxes[bi].LL, ur = boxes[bi].UR;
00176         sprintf(buf, "newpath\n%d %d moveto", ll.x, ll.y);
00177         Show_boxes[li++] = strdup (buf);
00178         sprintf(buf, "%d %d lineto", ll.x, ur.y);
00179         Show_boxes[li++] = strdup (buf);
00180         sprintf(buf, "%d %d lineto", ur.x, ur.y);
00181         Show_boxes[li++] = strdup (buf);
00182         sprintf(buf, "%d %d lineto", ur.x, ll.y);
00183         Show_boxes[li++] = strdup (buf);
00184         Show_boxes[li++] = strdup ("closepath stroke");
00185     }
00186     Show_boxes[li++] = strdup ("grestore");
00187 
00188     Show_cnt = newcnt;
00189     Show_boxes[Show_cnt+1] = NULL;
00190 }
00191 
00192 static void psprintinit (int begin)
00193 {
00194     int newcnt = Show_cnt + 1;
00195 
00196     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00197     if (begin)
00198         Show_boxes[1+Show_cnt] = strdup ("dbgstart");
00199     else
00200         Show_boxes[1+Show_cnt] = strdup ("grestore");
00201     Show_cnt = newcnt;
00202     Show_boxes[Show_cnt+1] = NULL;
00203 }
00204 
00205 static int debugleveln(edge_t* realedge, int i)
00206 {
00207     return (GD_showboxes(realedge->head->graph) == i ||
00208             GD_showboxes(realedge->tail->graph) == i ||
00209             ED_showboxes(realedge) == i ||
00210             ND_showboxes(realedge->head) == i ||
00211             ND_showboxes(realedge->tail) == i);
00212 }
00213 #endif  /* DEBUG */
00214 
00215 #ifdef OBSOLETE
00216 static point mkpt(int x, int y)
00217 {
00218     point rv;
00219     rv.x = x;
00220     rv.y = y;
00221     return rv;
00222 }
00223 
00224 static int pteq(point p, point q)
00225 {
00226     return ((p.x == q.x) && (p.y == q.y));
00227 }
00228 #endif
00229 
00230 /* routesplinesinit:
00231  * Data initialized once until matching call to routeplineterm
00232  * Allows recursive calls to dot
00233  */
00234 void
00235 routesplinesinit()
00236 {
00237     if (++routeinit > 1) return;
00238 #ifdef UNUSED
00239     if (!(bs = N_GNEW(BINC, box))) {
00240         agerr(AGERR, "cannot allocate bs\n");
00241         abort();
00242     }
00243     maxbn = BINC;
00244 #endif
00245     if (!(ps = N_GNEW(PINC, point))) {
00246         agerr(AGERR, "cannot allocate ps\n");
00247         abort();
00248     }
00249     maxpn = PINC;
00250 #ifdef DEBUG
00251     if (Show_boxes) {
00252         int i;
00253         for (i = 0; Show_boxes[i]; i++)
00254             free (Show_boxes[i]);
00255         free (Show_boxes);
00256         Show_boxes = NULL;
00257         Show_cnt = 0;
00258     }
00259 #endif
00260     nedges = 0;
00261     nboxes = 0;
00262     if (Verbose)
00263         start_timer();
00264 }
00265 
00266 void routesplinesterm()
00267 {
00268     if (--routeinit > 0) return;
00269     free(ps);
00270 #ifdef UNUSED
00271     free(bs), bs = NULL /*, maxbn = bn = 0 */ ;
00272 #endif
00273     if (Verbose)
00274         fprintf(stderr,
00275                 "routesplines: %d edges, %d boxes %.2f sec\n",
00276                 nedges, nboxes, elapsed_sec());
00277 }
00278 
00279 static point *_routesplines(path * pp, int *npoints, int polyline)
00280 {
00281     Ppoly_t poly;
00282     Ppolyline_t pl, spl;
00283     int splinepi;
00284     Ppoint_t eps[2];
00285     Pvector_t evs[2];
00286     int edgei, prev, next;
00287     point sp[4];
00288     int pi, bi, si;
00289     double t;
00290     box *boxes;
00291     int boxn;
00292     edge_t* realedge;
00293     int flip;
00294     int delta = 10;
00295 
00296     nedges++;
00297     nboxes += pp->nbox;
00298 
00299     for (realedge = (edge_t *) pp->data;
00300 #ifdef NOTNOW
00301          origedge = realedge;
00302 #endif
00303          realedge && ED_edge_type(realedge) != NORMAL;
00304          realedge = ED_to_orig(realedge));
00305     if (!realedge) {
00306         agerr(AGERR, "in routesplines, cannot find NORMAL edge\n");
00307         abort();
00308     }
00309 
00310     boxes = pp->boxes;
00311     boxn = pp->nbox;
00312 
00313     checkpath(boxn, boxes, pp);
00314 
00315 #ifdef DEBUG
00316     if (debugleveln(realedge, 1))
00317         printboxes(boxn, boxes);
00318     if (debugleveln(realedge, 3)) {
00319         psprintinit(1);
00320         psprintboxes(boxn, boxes);
00321     }
00322 #endif
00323 
00324     if (boxn * 8 > polypointn) {
00325         polypoints = ALLOC(boxn * 8, polypoints, Ppoint_t);
00326         polypointn = boxn * 8;
00327     }
00328 
00329     if ((boxn > 1) && (boxes[0].LL.y > boxes[1].LL.y)) {
00330         flip = 1;
00331         for (bi = 0; bi < boxn; bi++) {
00332             int v = boxes[bi].UR.y;
00333             boxes[bi].UR.y = -1*boxes[bi].LL.y;
00334             boxes[bi].LL.y = -v;
00335         }
00336     }
00337     else flip = 0;
00338 
00339     if (realedge->tail != realedge->head) {
00340         /* I assume that the path goes either down only or
00341            up - right - down */
00342         for (bi = 0, pi = 0; bi < boxn; bi++) {
00343             next = prev = 0;
00344             if (bi > 0)
00345                 prev = (boxes[bi].LL.y > boxes[bi - 1].LL.y) ? -1 : 1;
00346             if (bi < boxn - 1)
00347                 next = (boxes[bi + 1].LL.y > boxes[bi].LL.y) ? 1 : -1;
00348             if (prev != next) {
00349                 if (next == -1 || prev == 1) {
00350                     polypoints[pi].x = boxes[bi].LL.x;
00351                     polypoints[pi++].y = boxes[bi].UR.y;
00352                     polypoints[pi].x = boxes[bi].LL.x;
00353                     polypoints[pi++].y = boxes[bi].LL.y;
00354                 } else {
00355                     polypoints[pi].x = boxes[bi].UR.x;
00356                     polypoints[pi++].y = boxes[bi].LL.y;
00357                     polypoints[pi].x = boxes[bi].UR.x;
00358                     polypoints[pi++].y = boxes[bi].UR.y;
00359                 }
00360             }
00361             else if (prev == 0) { /* single box */
00362                 polypoints[pi].x = boxes[bi].LL.x;
00363                 polypoints[pi++].y = boxes[bi].UR.y;
00364                 polypoints[pi].x = boxes[bi].LL.x;
00365                 polypoints[pi++].y = boxes[bi].LL.y;
00366             } 
00367             else {
00368                 if (!(prev == -1 && next == -1))
00369                     abort();
00370             }
00371         }
00372         for (bi = boxn - 1; bi >= 0; bi--) {
00373             next = prev = 0;
00374             if (bi < boxn - 1)
00375                 prev = (boxes[bi].LL.y > boxes[bi + 1].LL.y) ? -1 : 1;
00376             if (bi > 0)
00377                 next = (boxes[bi - 1].LL.y > boxes[bi].LL.y) ? 1 : -1;
00378             if (prev != next) {
00379                 if (next == -1 || prev == 1 ) {
00380                     polypoints[pi].x = boxes[bi].LL.x;
00381                     polypoints[pi++].y = boxes[bi].UR.y;
00382                     polypoints[pi].x = boxes[bi].LL.x;
00383                     polypoints[pi++].y = boxes[bi].LL.y;
00384                 } else {
00385                     polypoints[pi].x = boxes[bi].UR.x;
00386                     polypoints[pi++].y = boxes[bi].LL.y;
00387                     polypoints[pi].x = boxes[bi].UR.x;
00388                     polypoints[pi++].y = boxes[bi].UR.y;
00389                 }
00390             } 
00391             else if (prev == 0) { /* single box */
00392                 polypoints[pi].x = boxes[bi].UR.x;
00393                 polypoints[pi++].y = boxes[bi].LL.y;
00394                 polypoints[pi].x = boxes[bi].UR.x;
00395                 polypoints[pi++].y = boxes[bi].UR.y;
00396             }
00397             else {
00398                 if (!(prev == -1 && next == -1)) {
00399                     /* it went badly, e.g. degenerate box in boxlist */
00400                     *npoints = 0;
00401                     abort();    /* for correctness sake, it's best to just stop */
00402                     return ps;  /* could also be reported as a lost edge (no spline) */
00403                 }
00404                 polypoints[pi].x = boxes[bi].UR.x;
00405                 polypoints[pi++].y = boxes[bi].LL.y;
00406                 polypoints[pi].x = boxes[bi].UR.x;
00407                 polypoints[pi++].y = boxes[bi].UR.y;
00408                 polypoints[pi].x = boxes[bi].LL.x;
00409                 polypoints[pi++].y = boxes[bi].UR.y;
00410                 polypoints[pi].x = boxes[bi].LL.x;
00411                 polypoints[pi++].y = boxes[bi].LL.y;
00412             }
00413         }
00414     } 
00415     else {
00416 #ifdef OBSOLETE
00417         /* new, more generalized approach for self-edges.  We do not
00418            assume any monotonicity about the box path, only that it
00419            is simply connected.  We build up the constraint poly by
00420            walking the box path from one end to the other and back
00421            in the recursive function append(). A better approach to all
00422            of this might be to dispense with the box paths altogether
00423            and just compute the constraint poly directly, but this
00424            needs to be done as part of a more thorough overhaul. */
00425         point p0, p1;
00426         box b0, b1;
00427         b0 = pp->boxes[0];
00428         b1 = pp->boxes[1];
00429         /* determine 'starting' segment (side of b0) for box path search */
00430         if (b0.UR.x == b1.LL.x) {
00431             p0 = b0.LL;
00432             p1 = mkpt(b0.LL.x, b0.UR.y);
00433         } else if (b0.LL.y == b1.UR.y) {
00434             p0 = mkpt(b0.LL.x, b0.UR.y);
00435             p1 = b0.UR;
00436         } else if (b0.LL.x == b1.UR.x) {
00437             p0 = b0.UR;
00438             p1 = mkpt(b0.UR.x, b0.LL.y);
00439         } else if (b0.UR.y == b1.LL.y) {
00440             p0 = mkpt(b0.UR.x, b0.LL.y);
00441             p1 = b0.LL;
00442         } else
00443             abort();
00444         pi = append(pp, 0, p0, p1, 0);
00445 #else
00446         abort();
00447 #endif
00448     }
00449 
00450     if (flip) {
00451         int i;
00452         for (bi = 0; bi < boxn; bi++) {
00453             int v = boxes[bi].UR.y;
00454             boxes[bi].UR.y = -1*boxes[bi].LL.y;
00455             boxes[bi].LL.y = -v;
00456         }
00457         for (i = 0; i < pi; i++)
00458             polypoints[i].y *= -1;
00459     }
00460 
00461     for (bi = 0; bi < boxn; bi++)
00462         boxes[bi].LL.x = INT_MAX, boxes[bi].UR.x = INT_MIN;
00463     poly.ps = polypoints, poly.pn = pi;
00464     eps[0].x = pp->start.p.x, eps[0].y = pp->start.p.y;
00465     eps[1].x = pp->end.p.x, eps[1].y = pp->end.p.y;
00466     if (Pshortestpath(&poly, eps, &pl) == -1)
00467         abort();
00468 #ifdef DEBUG
00469     if (debugleveln(realedge, 3)) {
00470         psprintpoly(poly);
00471         psprintline(pl);
00472     }
00473 #endif
00474 
00475     if (polyline) {
00476         make_polyline (pl, &spl);
00477     }
00478     else {
00479         if (poly.pn > edgen) {
00480             edges = ALLOC(poly.pn, edges, Pedge_t);
00481             edgen = poly.pn;
00482         }
00483         for (edgei = 0; edgei < poly.pn; edgei++) {
00484             edges[edgei].a = polypoints[edgei];
00485             edges[edgei].b = polypoints[(edgei + 1) % poly.pn];
00486         }
00487         if (pp->start.constrained) {
00488             evs[0].x = cos(pp->start.theta);
00489             evs[0].y = sin(pp->start.theta);
00490         } else
00491             evs[0].x = evs[0].y = 0;
00492         if (pp->end.constrained) {
00493             evs[1].x = -cos(pp->end.theta);
00494             evs[1].y = -sin(pp->end.theta);
00495         } else
00496             evs[1].x = evs[1].y = 0;
00497 
00498         if (Proutespline(edges, poly.pn, pl, evs, &spl) == -1)
00499             abort();
00500 #ifdef DEBUG
00501         if (debugleveln(realedge, 3)) {
00502             psprintspline(spl);
00503             psprintinit(0);
00504         }
00505 #endif
00506     }
00507     mkspacep(spl.pn);
00508     for (bi = 0; bi < boxn; bi++) {
00509         boxes[bi].LL.x = INT_MAX;
00510         boxes[bi].UR.x = INT_MIN;
00511     }
00512     for (splinepi = 0; splinepi < spl.pn; splinepi++) {
00513         ps[splinepi].x = spl.ps[splinepi].x;
00514         ps[splinepi].y = spl.ps[splinepi].y;
00515     }
00516 REDO:
00517     for (splinepi = 0; splinepi + 3 < spl.pn; splinepi += 3) {
00518         int num_div = delta * boxn;
00519         for (si = 0; si <= num_div; si++) {
00520             t = si / ((double)num_div);
00521             sp[0] = ps[splinepi];
00522             sp[1] = ps[splinepi + 1];
00523             sp[2] = ps[splinepi + 2];
00524             sp[3] = ps[splinepi + 3];
00525             sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x);
00526             sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y);
00527             sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x);
00528             sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y);
00529             sp[2].x = sp[2].x + t * (sp[3].x - sp[2].x);
00530             sp[2].y = sp[2].y + t * (sp[3].y - sp[2].y);
00531             sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x);
00532             sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y);
00533             sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x);
00534             sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y);
00535             sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x);
00536             sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y);
00537             for (bi = 0; bi < boxn; bi++) {
00538                 if (sp[0].y <= boxes[bi].UR.y && sp[0].y >= boxes[bi].LL.y) {
00539                     if (boxes[bi].LL.x > sp[0].x)
00540                         boxes[bi].LL.x = sp[0].x;
00541                     if (boxes[bi].UR.x < sp[0].x)
00542                         boxes[bi].UR.x = sp[0].x;
00543                 }
00544             }
00545         }
00546     }
00547     /* The following check is necessary because if a box is not very 
00548      * high, it is possible that the sampling above might miss it.
00549      * Therefore, we make the sample finer until all boxes have
00550      * valid values. cf. bug 456. Would making sp[] pointfs help?
00551      */
00552     for (bi = 0; bi < boxn; bi++) {
00553         if ((boxes[bi].LL.x == INT_MAX) || (boxes[bi].UR.x == INT_MIN)) {
00554             delta *= 2;
00555             goto REDO;
00556         }
00557     }
00558     *npoints = spl.pn;
00559 
00560 #ifdef DEBUG
00561     if (GD_showboxes(realedge->head->graph) == 2 ||
00562         GD_showboxes(realedge->tail->graph) == 2 ||
00563         ED_showboxes(realedge) == 2 ||
00564         ND_showboxes(realedge->head) == 2 ||
00565         ND_showboxes(realedge->tail) == 2)
00566         printboxes(boxn, boxes);
00567 #endif
00568 
00569     return ps;
00570 }
00571 
00572 point *routesplines(path * pp, int *npoints)
00573 {
00574     return _routesplines (pp, npoints, 0);
00575 }
00576 
00577 point *routepolylines(path * pp, int *npoints)
00578 {
00579     return _routesplines (pp, npoints, 1);
00580 }
00581 
00582 static int overlap(int i0, int i1, int j0, int j1)
00583 {
00584     /* i'll bet there's an elegant way to do this */
00585     if (i1 <= j0)
00586         return 0;
00587     if (i0 >= j1)
00588         return 0;
00589     if ((j0 <= i0) && (i0 <= j1))
00590         return (j1 - i0);
00591     if ((j0 <= i1) && (i1 <= j1))
00592         return (i1 - j0);
00593     return MIN(i1 - i0, j1 - j0);
00594 }
00595 
00596 
00597 /*
00598  * repairs minor errors in the boxpath, such as boxes not joining
00599  * or slightly intersecting.  it's sort of the equivalent of the
00600  * audit process in the 5E control program - if you've given up on
00601  * fixing all the bugs, at least try to engineer around them!
00602  * in postmodern CS, we could call this "self-healing code."
00603  */
00604 static void checkpath(int boxn, box* boxes, path* thepath)
00605 {
00606     box *ba, *bb;
00607     int bi, i, errs, l, r, d, u;
00608     int xoverlap, yoverlap;
00609 
00610 #ifndef DONTFIXPATH
00611     /* remove degenerate boxes. */
00612     i = 0;
00613     for (bi = 0; bi < boxn; bi++) {
00614         if (boxes[bi].LL.y == boxes[bi].UR.y)
00615             continue;
00616         if (boxes[bi].LL.x == boxes[bi].UR.x)
00617             continue;
00618         if (i != bi)
00619             boxes[i] = boxes[bi];
00620         i++;
00621     }
00622     boxn = i;
00623 #endif                          /* DONTFIXPATH */
00624 
00625     ba = &boxes[0];
00626     if (ba->LL.x > ba->UR.x || ba->LL.y > ba->UR.y) {
00627         agerr(AGERR, "in checkpath, box 0 has LL coord > UR coord\n");
00628         printpath(thepath);
00629         abort();
00630     }
00631     for (bi = 0; bi < boxn - 1; bi++) {
00632         ba = &boxes[bi], bb = &boxes[bi + 1];
00633         if (bb->LL.x > bb->UR.x || bb->LL.y > bb->UR.y) {
00634             agerr(AGERR, "in checkpath, box %d has LL coord > UR coord\n",
00635                   bi + 1);
00636             printpath(thepath);
00637             abort();
00638         }
00639         l = (ba->UR.x < bb->LL.x) ? 1 : 0;
00640         r = (ba->LL.x > bb->UR.x) ? 1 : 0;
00641         d = (ba->UR.y < bb->LL.y) ? 1 : 0;
00642         u = (ba->LL.y > bb->UR.y) ? 1 : 0;
00643         errs = l + r + d + u;
00644         if (errs > 0 && Verbose) {
00645             fprintf(stderr, "in checkpath, boxes %d and %d don't touch\n",
00646                     bi, bi + 1);
00647             printpath(thepath);
00648         }
00649 #ifndef DONTFIXPATH
00650         if (errs > 0) {
00651             int xy;
00652 
00653             if (l == 1)
00654                 xy = ba->UR.x, ba->UR.x = bb->LL.x, bb->LL.x = xy, l = 0;
00655             else if (r == 1)
00656                 xy = ba->LL.x, ba->LL.x = bb->UR.x, bb->UR.x = xy, r = 0;
00657             else if (d == 1)
00658                 xy = ba->UR.y, ba->UR.y = bb->LL.y, bb->LL.y = xy, d = 0;
00659             else if (u == 1)
00660                 xy = ba->LL.y, ba->LL.y = bb->UR.y, bb->UR.y = xy, u = 0;
00661             for (i = 0; i < errs - 1; i++) {
00662                 if (l == 1)
00663                     xy = (ba->UR.x + bb->LL.x) / 2.0 + 0.5, ba->UR.x =
00664                         bb->LL.x = xy, l = 0;
00665                 else if (r == 1)
00666                     xy = (ba->LL.x + bb->UR.x) / 2.0 + 0.5, ba->LL.x =
00667                         bb->UR.x = xy, r = 0;
00668                 else if (d == 1)
00669                     xy = (ba->UR.y + bb->LL.y) / 2.0 + 0.5, ba->UR.y =
00670                         bb->LL.y = xy, d = 0;
00671                 else if (u == 1)
00672                     xy = (ba->LL.y + bb->UR.y) / 2.0 + 0.5, ba->LL.y =
00673                         bb->UR.y = xy, u = 0;
00674             }
00675         }
00676 #else
00677         abort();
00678 #endif
00679 #ifndef DONTFIXPATH
00680         /* check for overlapping boxes */
00681         xoverlap = overlap(ba->LL.x, ba->UR.x, bb->LL.x, bb->UR.x);
00682         yoverlap = overlap(ba->LL.y, ba->UR.y, bb->LL.y, bb->UR.y);
00683         if (xoverlap && yoverlap) {
00684             if (xoverlap < yoverlap) {
00685                 if (ba->UR.x - ba->LL.x > bb->UR.x - bb->LL.x) {
00686                     /* take space from ba */
00687                     if (ba->UR.x < bb->UR.x)
00688                         ba->UR.x = bb->LL.x;
00689                     else
00690                         ba->LL.x = bb->UR.x;
00691                 } else {
00692                     /* take space from bb */
00693                     if (ba->UR.x < bb->UR.x)
00694                         bb->LL.x = ba->UR.x;
00695                     else
00696                         bb->UR.x = ba->LL.x;
00697                 }
00698             } else {            /* symmetric for y coords */
00699                 if (ba->UR.y - ba->LL.y > bb->UR.y - bb->LL.y) {
00700                     /* take space from ba */
00701                     if (ba->UR.y < bb->UR.y)
00702                         ba->UR.y = bb->LL.y;
00703                     else
00704                         ba->LL.y = bb->UR.y;
00705                 } else {
00706                     /* take space from bb */
00707                     if (ba->UR.y < bb->UR.y)
00708                         bb->LL.y = ba->UR.y;
00709                     else
00710                         bb->UR.y = ba->LL.y;
00711                 }
00712             }
00713         }
00714     }
00715 #endif                          /* DONTFIXPATH */
00716 
00717     if (thepath->start.p.x < boxes[0].LL.x
00718         || thepath->start.p.x > boxes[0].UR.x
00719         || thepath->start.p.y < boxes[0].LL.y
00720         || thepath->start.p.y > boxes[0].UR.y) {
00721         if (Verbose) {
00722             fprintf(stderr, "in checkpath, start port not in first box\n");
00723             printpath(thepath);
00724         }
00725 #ifndef DONTFIXPATH
00726         if (thepath->start.p.x < boxes[0].LL.x)
00727             thepath->start.p.x = boxes[0].LL.x;
00728         if (thepath->start.p.x > boxes[0].UR.x)
00729             thepath->start.p.x = boxes[0].UR.x;
00730         if (thepath->start.p.y < boxes[0].LL.y)
00731             thepath->start.p.y = boxes[0].LL.y;
00732         if (thepath->start.p.y > boxes[0].UR.y)
00733             thepath->start.p.y = boxes[0].UR.y;
00734 #else
00735         abort();
00736 #endif
00737     }
00738     if (thepath->end.p.x < boxes[boxn - 1].LL.x
00739         || thepath->end.p.x > boxes[boxn - 1].UR.x
00740         || thepath->end.p.y < boxes[boxn - 1].LL.y
00741         || thepath->end.p.y > boxes[boxn - 1].UR.y) {
00742         if (Verbose) {
00743             fprintf(stderr, "in checkpath, end port not in last box\n");
00744             printpath(thepath);
00745         }
00746 #ifndef DONTFIXPATH
00747         if (thepath->end.p.x < boxes[boxn - 1].LL.x)
00748             thepath->end.p.x = boxes[boxn - 1].LL.x;
00749         if (thepath->end.p.x > boxes[boxn - 1].UR.x)
00750             thepath->end.p.x = boxes[boxn - 1].UR.x;
00751         if (thepath->end.p.y < boxes[boxn - 1].LL.y)
00752             thepath->end.p.y = boxes[boxn - 1].LL.y;
00753         if (thepath->end.p.y > boxes[boxn - 1].UR.y)
00754             thepath->end.p.y = boxes[boxn - 1].UR.y;
00755 #else
00756         abort();
00757 #endif
00758     }
00759 }
00760 
00761 static void mkspacep(int size)
00762 {
00763     if (size > maxpn) {
00764         int newmax = maxpn + (size / PINC + 1) * PINC;
00765         ps = RALLOC(newmax, ps, point);
00766         maxpn = newmax;
00767     }
00768 }
00769 
00770 #ifdef OBSOLETE
00771 /* new code to create poly from box list
00772  * given that we entered the box b on segment p0,p1 (p0==p1 allowed) 
00773  * then add successive points to the constraint poly
00774  */
00775 
00776 #define BOXLEFT 0
00777 #define BOXTOP 1
00778 #define BOXRIGHT 2
00779 #define BOXBOTTOM 3
00780 static box B;
00781 
00782 static int sideofB(point p, box B)
00783 {
00784     if (p.x == B.LL.x)
00785         return BOXLEFT;
00786     if (p.y == B.UR.y)
00787         return BOXTOP;
00788     if (p.x == B.UR.x)
00789         return BOXRIGHT;
00790     if (p.y == B.LL.y)
00791         return BOXBOTTOM;
00792     abort();
00793     return 0;
00794 }
00795 
00796 static int appendpt(point p, int polysz)
00797 {
00798     polypoints[polysz].x = p.x;
00799     polypoints[polysz].y = p.y;
00800     return (polysz+1);
00801 }
00802 
00803 static int cmpf(const void *pp0, const void *pp1)
00804 {
00805     point p0, p1;
00806     int s0, s1;
00807 
00808     p0 = *(point *) pp0;
00809     p1 = *(point *) pp1;
00810     s0 = sideofB(p0, B);
00811     s1 = sideofB(p1, B);
00812 
00813     if (s0 != s1)
00814         return s1 - s0;
00815     switch (s0) {
00816     case BOXLEFT:
00817         return p1.y - p0.y;
00818     case BOXTOP:
00819         return p1.x - p0.x;
00820     case BOXRIGHT:
00821         return p0.y - p1.y;
00822     case BOXBOTTOM:
00823         return p0.x - p1.x;
00824     default:
00825         abort();
00826     }
00827     return 0;                   /* not reached */
00828 }
00829 
00830 /* append:
00831  */
00832 static int 
00833 append(path * path, int bi, point p0, point p1, int polysz)
00834 {
00835     point v[8];         /* worst case 4 corners + 2 segs * 2 points each */
00836     point w[8];
00837     box b = path->boxes[bi];
00838     box bb;
00839     int i, i0, npw, delta;
00840     point q0 = { 0, 0 }, q1 = { 0, 0}, r;
00841     int pn;
00842 
00843     /* v = 4 corners of b, p0 and p1 */
00844     pn = 0;
00845     v[pn++] = b.LL;
00846     v[pn++] = mkpt(b.UR.x, b.LL.y);
00847     v[pn++] = b.UR;
00848     v[pn++] = mkpt(b.LL.x, b.UR.y);
00849     v[pn++] = p0;
00850     v[pn++] = p1;
00851 
00852     if (bi + 1 < path->nbox) {
00853         bb = path->boxes[bi + 1];
00854         /* determine points q0,q1 where b and bb touch and append to v */
00855         if (b.UR.x == bb.LL.x) {
00856             q0.x = q1.x = b.UR.x;
00857             q0.y = MIN(b.UR.y, bb.UR.y);
00858             q1.y = MAX(b.LL.y, bb.LL.y);
00859         } else if (b.LL.x == bb.UR.x) {
00860             q0.x = q1.x = b.LL.x;
00861             q0.y = MIN(b.UR.y, bb.UR.y);
00862             q1.y = MAX(b.LL.y, bb.LL.y);
00863         } else if (b.UR.y == bb.LL.y) {
00864             q0.y = q1.y = b.UR.y;
00865             q0.x = MIN(b.UR.x, bb.UR.x);
00866             q1.x = MAX(b.LL.x, bb.LL.x);
00867         } else if (b.LL.y == bb.UR.y) {
00868             q0.y = q1.y = b.LL.y;
00869             q0.x = MIN(b.UR.x, bb.UR.x);
00870             q1.x = MAX(b.LL.x, bb.LL.x);
00871         } else
00872             abort();
00873         v[pn++] = q0;
00874         v[pn++] = q1;
00875     }
00876 
00877     /* sort v so that the cyclic order is p0, all other points, p1  */
00878     B = b;
00879     qsort(v, pn, sizeof(v[0]), cmpf);
00880 
00881     /* eliminate duplicates and record i0 = index of p0 in w */
00882     w[0] = v[0];
00883     npw = 1;
00884     i0 = -1;
00885     for (i = 0; i < pn; i++) {
00886         if (pteq(w[npw - 1], p0))
00887             i0 = npw - 1;
00888         if (!pteq(v[i], w[npw - 1]))
00889             w[npw++] = v[i];
00890     }
00891 
00892     i = i0;
00893     if (bi == 0)
00894         polysz = appendpt(p0, polysz);
00895     if (pteq(p1, w[(i0 + 1) % npw]))
00896         delta = -1;
00897     else if (pteq(p1, w[(i0 - 1 + npw) % npw]))
00898         delta = 1;
00899     else
00900         abort();
00901     do {
00902         i = (i + delta + npw) % npw;    /* go to the next point in order */
00903         r = w[i];               /* call it r */
00904 
00905         /* append r to current poly, except p0 and p1 are special cases */
00906         if ((bi == 0) || (!pteq(r, p0) && !pteq(r, p1)))
00907             polysz = appendpt(r, polysz);
00908         if (pteq(r, p1))
00909             break;
00910         if (bi + 1 < path->nbox) {      /* recur when we hit the next box */
00911             if (pteq(r, q0)) {
00912                 polysz = append(path, bi + 1, q0, q1, polysz);
00913                 polysz = appendpt(q1, polysz);  /* assumes q1 != p0 and p1 */
00914                 i += delta;     /* skip q1 */
00915             } else if (pteq(r, q1)) {
00916                 polysz = append(path, bi + 1, q1, q0, polysz);
00917                 polysz = appendpt(q0, polysz);
00918                 i += delta;
00919             }
00920         }
00921     } while (i != i0);
00922     return polysz;
00923 }
00924 #endif
00925 
00926 static void printpath(path * pp)
00927 {
00928     int bi;
00929 
00930 #ifdef NOTNOW
00931     fprintf(stderr, "edge %d from %s to %s\n", nedges,
00932             realedge->tail->name, realedge->head->name);
00933     if (ED_count(origedge) > 1)
00934         fprintf(stderr, "    (it's part of a concentrator edge)\n");
00935 #endif
00936     fprintf(stderr, "%d boxes:\n", pp->nbox);
00937     for (bi = 0; bi < pp->nbox; bi++)
00938         fprintf(stderr, "%d (%d, %d), (%d, %d)\n", bi, pp->boxes[bi].LL.x,
00939                 pp->boxes[bi].LL.y, pp->boxes[bi].UR.x,
00940                 pp->boxes[bi].UR.y);
00941     fprintf(stderr, "start port: (%d, %d), tangent angle: %.3f, %s\n",
00942             pp->start.p.x, pp->start.p.y, pp->start.theta,
00943             pp->start.constrained ? "constrained" : "not constrained");
00944     fprintf(stderr, "end port: (%d, %d), tangent angle: %.3f, %s\n",
00945             pp->end.p.x, pp->end.p.y, pp->end.theta,
00946             pp->end.constrained ? "constrained" : "not constrained");
00947 }
00948 

Generated on Mon Mar 31 19:03:25 2008 for Graphviz by  doxygen 1.5.1