Graphviz  2.29.20120524.0446
lib/common/routespl.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 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #include "render.h"
00019 #include "pathplan.h"
00020 #include <setjmp.h>
00021 
00022 #ifdef UNUSED
00023 static box *bs = NULL;
00024 static int bn;
00025 static int maxbn = 0;
00026 #define BINC 300
00027 #endif
00028 
00029 #define PINC 300
00030 
00031 #ifdef NOTNOW
00032 static edge_t *origedge;
00033 #endif
00034 
00035 static int nedges, nboxes; /* total no. of edges and boxes used in routing */
00036 
00037 static int routeinit;
00038 /* static data used across multiple edges */
00039 static pointf *ps;             /* final spline points */
00040 static int maxpn;             /* size of ps[] */
00041 static Ppoint_t *polypoints;  /* vertices of polygon defined by boxes */
00042 static int polypointn;        /* size of polypoints[] */
00043 static Pedge_t *edges;        /* polygon edges passed to Proutespline */
00044 static int edgen;             /* size of edges[] */
00045 
00046 static int checkpath(int, boxf*, path*);
00047 static int mkspacep(int size);
00048 static void printpath(path * pp);
00049 #ifdef DEBUG
00050 static void printboxes(int boxn, boxf* boxes)
00051 {
00052     pointf ll, ur;
00053     int bi;
00054     char buf[BUFSIZ];
00055     int newcnt = Show_cnt + boxn;
00056 
00057     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00058     for (bi = 0; bi < boxn; bi++) {
00059         ll = boxes[bi].LL, ur = boxes[bi].UR;
00060         sprintf(buf, "%d %d %d %d pathbox", (int)ll.x, (int)ll.y, (int)ur.x, (int)ur.y);
00061         Show_boxes[bi+1+Show_cnt] = strdup (buf);
00062     }
00063     Show_cnt = newcnt;
00064     Show_boxes[Show_cnt+1] = NULL;
00065 }
00066 
00067 static void psprintpolypts(Ppoint_t * p, int sz)
00068 {
00069     int i;
00070 
00071     fprintf(stderr, "%%!\n");
00072     fprintf(stderr, "%% constraint poly\n");
00073     fprintf(stderr, "newpath\n");
00074     for (i = 0; i < sz; i++)
00075         fprintf(stderr, "%f %f %s\n", p[i].x, p[i].y,
00076                 (i == 0 ? "moveto" : "lineto"));
00077     fprintf(stderr, "closepath stroke\n");
00078 }
00079 static void psprintpoint(point p)
00080 {
00081     fprintf(stderr, "gsave\n");
00082     fprintf(stderr,
00083             "newpath %d %d moveto %d %d 2 0 360 arc closepath fill stroke\n",
00084             p.x, p.y, p.x, p.y);
00085     fprintf(stderr, "/Times-Roman findfont 4 scalefont setfont\n");
00086     fprintf(stderr, "%d %d moveto (\\(%d,%d\\)) show\n", p.x + 5, p.y + 5,
00087             p.x, p.y);
00088     fprintf(stderr, "grestore\n");
00089 }
00090 static void psprintpointf(pointf p)
00091 {
00092     fprintf(stderr, "gsave\n");
00093     fprintf(stderr,
00094             "newpath %.5g %.5g moveto %.5g %.5g 2 0 360 arc closepath fill stroke\n",
00095             p.x, p.y, p.x, p.y);
00096     fprintf(stderr, "/Times-Roman findfont 4 scalefont setfont\n");
00097     fprintf(stderr, "%.5g %.5g moveto (\\(%.5g,%.5g\\)) show\n", p.x + 5, p.y + 5,
00098             p.x, p.y);
00099     fprintf(stderr, "grestore\n");
00100 }
00101 
00102 static void psprintspline(Ppolyline_t spl)
00103 {
00104     char buf[BUFSIZ];
00105     int newcnt = Show_cnt + spl.pn + 4;
00106     int li, i;
00107 
00108     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00109     li = Show_cnt+1;
00110     Show_boxes[li++] = strdup ("%%!");
00111     Show_boxes[li++] = strdup ("%% spline");
00112     Show_boxes[li++] = strdup ("gsave 1 0 0 setrgbcolor newpath");
00113     for (i = 0; i < spl.pn; i++) {
00114         sprintf(buf, "%f %f %s", spl.ps[i].x, spl.ps[i].y,
00115           (i == 0) ?  "moveto" : ((i % 3 == 0) ? "curveto" : ""));
00116         Show_boxes[li++] = strdup (buf);
00117     }
00118     Show_boxes[li++] = strdup ("stroke grestore");
00119     Show_cnt = newcnt;
00120     Show_boxes[Show_cnt+1] = NULL;
00121 }
00122 
00123 static void psprintline(Ppolyline_t pl)
00124 {
00125     char buf[BUFSIZ];
00126     int newcnt = Show_cnt + pl.pn + 4;
00127     int i, li;
00128 
00129     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00130     li = Show_cnt+1;
00131     Show_boxes[li++] = strdup ("%%!");
00132     Show_boxes[li++] = strdup ("%% line");
00133     Show_boxes[li++] = strdup ("gsave 0 0 1 setrgbcolor newpath");
00134     for (i = 0; i < pl.pn; i++) {
00135         sprintf(buf, "%f %f %s", pl.ps[i].x, pl.ps[i].y,
00136                 (i == 0 ? "moveto" : "lineto"));
00137         Show_boxes[li++] = strdup (buf);
00138     }
00139     Show_boxes[li++] = strdup ("stroke grestore");
00140     Show_cnt = newcnt;
00141     Show_boxes[Show_cnt+1] = NULL;
00142 }
00143 
00144 static void psprintpoly(Ppoly_t p)
00145 {
00146     char buf[BUFSIZ];
00147     int newcnt = Show_cnt + p.pn + 3;
00148     point tl, hd;
00149     int bi, li;
00150     char*  pfx;
00151 
00152     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00153     li = Show_cnt+1;
00154     Show_boxes[li++] = strdup ("%% poly list");
00155     Show_boxes[li++] = strdup ("gsave 0 1 0 setrgbcolor");
00156     for (bi = 0; bi < p.pn; bi++) {
00157         tl.x = (int)p.ps[bi].x;
00158         tl.y = (int)p.ps[bi].y;
00159         hd.x = (int)p.ps[(bi+1) % p.pn].x;
00160         hd.y = (int)p.ps[(bi+1) % p.pn].y;
00161         if ((tl.x == hd.x) && (tl.y == hd.y)) pfx = "%%";
00162         else pfx ="";
00163         sprintf(buf, "%s%d %d %d %d makevec", pfx, tl.x, tl.y, hd.x, hd.y);
00164         Show_boxes[li++] = strdup (buf);
00165     }
00166     Show_boxes[li++] = strdup ("grestore");
00167 
00168     Show_cnt = newcnt;
00169     Show_boxes[Show_cnt+1] = NULL;
00170 }
00171 
00172 static void psprintboxes(int boxn, boxf* boxes)
00173 {
00174     char buf[BUFSIZ];
00175     int newcnt = Show_cnt + 5*boxn + 3;
00176     pointf ll, ur;
00177     int bi, li;
00178 
00179     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00180     li = Show_cnt+1;
00181     Show_boxes[li++] = strdup ("%% box list");
00182     Show_boxes[li++] = strdup ("gsave 0 1 0 setrgbcolor");
00183     for (bi = 0; bi < boxn; bi++) {
00184         ll = boxes[bi].LL, ur = boxes[bi].UR;
00185         sprintf(buf, "newpath\n%d %d moveto", (int)ll.x, (int)ll.y);
00186         Show_boxes[li++] = strdup (buf);
00187         sprintf(buf, "%d %d lineto", (int)ll.x, (int)ur.y);
00188         Show_boxes[li++] = strdup (buf);
00189         sprintf(buf, "%d %d lineto", (int)ur.x, (int)ur.y);
00190         Show_boxes[li++] = strdup (buf);
00191         sprintf(buf, "%d %d lineto", (int)ur.x, (int)ll.y);
00192         Show_boxes[li++] = strdup (buf);
00193         Show_boxes[li++] = strdup ("closepath stroke");
00194     }
00195     Show_boxes[li++] = strdup ("grestore");
00196 
00197     Show_cnt = newcnt;
00198     Show_boxes[Show_cnt+1] = NULL;
00199 }
00200 
00201 static void psprintinit (int begin)
00202 {
00203     int newcnt = Show_cnt + 1;
00204 
00205     Show_boxes = ALLOC(newcnt+2,Show_boxes,char*);
00206     if (begin)
00207         Show_boxes[1+Show_cnt] = strdup ("dbgstart");
00208     else
00209         Show_boxes[1+Show_cnt] = strdup ("grestore");
00210     Show_cnt = newcnt;
00211     Show_boxes[Show_cnt+1] = NULL;
00212 }
00213 
00214 static int debugleveln(edge_t* realedge, int i)
00215 {
00216     return (GD_showboxes(realedge->head->graph) == i ||
00217             GD_showboxes(realedge->tail->graph) == i ||
00218             ED_showboxes(realedge) == i ||
00219             ND_showboxes(realedge->head) == i ||
00220             ND_showboxes(realedge->tail) == i);
00221 }
00222 #endif  /* DEBUG */
00223 
00224 
00225 
00226 /* simpleSplineRoute:
00227  * Given a simple (ccw) polygon, route an edge from tp to hp.
00228  */
00229 pointf*
00230 simpleSplineRoute (pointf tp, pointf hp, Ppoly_t poly, int* n_spl_pts,
00231     int polyline)
00232 {
00233     Ppolyline_t pl, spl;
00234     Ppoint_t eps[2];
00235     Pvector_t evs[2];
00236     int i;
00237 
00238     eps[0].x = tp.x;
00239     eps[0].y = tp.y;
00240     eps[1].x = hp.x;
00241     eps[1].y = hp.y;
00242     if (Pshortestpath(&poly, eps, &pl) < 0)
00243         return NULL;
00244 
00245     if (polyline)
00246         make_polyline (pl, &spl);
00247     else {
00248         if (poly.pn > edgen) {
00249             edges = ALLOC(poly.pn, edges, Pedge_t);
00250             edgen = poly.pn;
00251         }
00252         for (i = 0; i < poly.pn; i++) {
00253             edges[i].a = poly.ps[i];
00254             edges[i].b = poly.ps[(i + 1) % poly.pn];
00255         }
00256 #if 0
00257         if (pp->start.constrained) {
00258             evs[0].x = cos(pp->start.theta);
00259             evs[0].y = sin(pp->start.theta);
00260         } else
00261 #endif
00262             evs[0].x = evs[0].y = 0;
00263 #if 0
00264         if (pp->end.constrained) {
00265             evs[1].x = -cos(pp->end.theta);
00266             evs[1].y = -sin(pp->end.theta);
00267         } else
00268 #endif
00269             evs[1].x = evs[1].y = 0;
00270         if (Proutespline(edges, poly.pn, pl, evs, &spl) < 0)
00271             return NULL;
00272     }
00273 
00274     if (mkspacep(spl.pn))
00275         return NULL;
00276     for (i = 0; i < spl.pn; i++) {
00277         ps[i] = spl.ps[i];
00278     }
00279     *n_spl_pts = spl.pn;
00280     return ps;
00281 }
00282 
00283 /* routesplinesinit:
00284  * Data initialized once until matching call to routeplineterm
00285  * Allows recursive calls to dot
00286  */
00287 int
00288 routesplinesinit()
00289 {
00290     if (++routeinit > 1) return 0;
00291     if (!(ps = N_GNEW(PINC, pointf))) {
00292         agerr(AGERR, "routesplinesinit: cannot allocate ps\n");
00293         return 1;
00294     }
00295     maxpn = PINC;
00296 #ifdef DEBUG
00297     if (Show_boxes) {
00298         int i;
00299         for (i = 0; Show_boxes[i]; i++)
00300             free (Show_boxes[i]);
00301         free (Show_boxes);
00302         Show_boxes = NULL;
00303         Show_cnt = 0;
00304     }
00305 #endif
00306     nedges = 0;
00307     nboxes = 0;
00308     if (Verbose)
00309         start_timer();
00310     return 0;
00311 }
00312 
00313 void routesplinesterm()
00314 {
00315     if (--routeinit > 0) return;
00316     free(ps);
00317 #ifdef UNUSED
00318     free(bs), bs = NULL /*, maxbn = bn = 0 */ ;
00319 #endif
00320     if (Verbose)
00321         fprintf(stderr,
00322                 "routesplines: %d edges, %d boxes %.2f sec\n",
00323                 nedges, nboxes, elapsed_sec());
00324 }
00325 
00326 static void
00327 limitBoxes (boxf* boxes, int boxn, pointf *pps, int pn, int delta)
00328 {
00329     int bi, si, splinepi;
00330     double t;
00331     pointf sp[4];
00332     int num_div = delta * boxn;
00333 
00334     for (splinepi = 0; splinepi + 3 < pn; splinepi += 3) {
00335         for (si = 0; si <= num_div; si++) {
00336             t = si / (double)num_div;
00337             sp[0] = pps[splinepi];
00338             sp[1] = pps[splinepi + 1];
00339             sp[2] = pps[splinepi + 2];
00340             sp[3] = pps[splinepi + 3];
00341             sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x);
00342             sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y);
00343             sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x);
00344             sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y);
00345             sp[2].x = sp[2].x + t * (sp[3].x - sp[2].x);
00346             sp[2].y = sp[2].y + t * (sp[3].y - sp[2].y);
00347             sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x);
00348             sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y);
00349             sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x);
00350             sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y);
00351             sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x);
00352             sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y);
00353             for (bi = 0; bi < boxn; bi++) {
00354 /* this tested ok on 64bit machines, but on 32bit we need this FUDGE
00355  *     or graphs/directed/records.gv fails */
00356 #define FUDGE .0001
00357                 if (sp[0].y <= boxes[bi].UR.y+FUDGE && sp[0].y >= boxes[bi].LL.y-FUDGE) {
00358                     if (boxes[bi].LL.x > sp[0].x)
00359                         boxes[bi].LL.x = sp[0].x;
00360                     if (boxes[bi].UR.x < sp[0].x)
00361                         boxes[bi].UR.x = sp[0].x;
00362                 }
00363             }
00364         }
00365     }
00366 }
00367 
00368 #define INIT_DELTA 10 
00369 #define LOOP_TRIES 15  /* number of times to try to limiting boxes to regain space, using smaller divisions */
00370 
00371 /* routesplines:
00372  * Route a path using the path info in pp. This includes start and end points
00373  * plus a collection of contiguous boxes contain the terminal points. The boxes
00374  * are converted into a containing polygon. A shortest path is constructed within
00375  * the polygon from between the terminal points. If polyline is true, this path
00376  * is converted to a spline representation. Otherwise, we call the path planner to
00377  * convert the polyline into a smooth spline staying within the polygon. In both
00378  * cases, the function returns an array of the computed control points. The number
00379  * of these points is given in npoints.
00380  *
00381  * Note that the returned points are stored in a single array, so the points must be
00382  * used before another call to this function.
00383  *
00384  * During cleanup, the function determines the x-extent of the spline in the box, so
00385  * the box can be shrunk to the minimum width. The extra space can then be used by other
00386  * edges. 
00387  *
00388  * If a catastrophic error, return NULL.
00389  */
00390 static pointf *_routesplines(path * pp, int *npoints, int polyline)
00391 {
00392     Ppoly_t poly;
00393     Ppolyline_t pl, spl;
00394     int splinepi;
00395     Ppoint_t eps[2];
00396     Pvector_t evs[2];
00397     int edgei, prev, next;
00398     int pi, bi;
00399     boxf *boxes;
00400     int boxn;
00401     edge_t* realedge;
00402     int flip;
00403     int loopcnt, delta = INIT_DELTA;
00404     boolean unbounded;
00405 
00406     nedges++;
00407     nboxes += pp->nbox;
00408 
00409     for (realedge = (edge_t *) pp->data;
00410 #ifdef NOTNOW
00411          origedge = realedge;
00412 #endif
00413          realedge && ED_edge_type(realedge) != NORMAL;
00414          realedge = ED_to_orig(realedge));
00415     if (!realedge) {
00416         agerr(AGERR, "in routesplines, cannot find NORMAL edge\n");
00417         return NULL;
00418     }
00419 
00420     boxes = pp->boxes;
00421     boxn = pp->nbox;
00422 
00423     if (checkpath(boxn, boxes, pp))
00424         return NULL;
00425 
00426 #ifdef DEBUG
00427     if (debugleveln(realedge, 1))
00428         printboxes(boxn, boxes);
00429     if (debugleveln(realedge, 3)) {
00430         psprintinit(1);
00431         psprintboxes(boxn, boxes);
00432     }
00433 #endif
00434 
00435     if (boxn * 8 > polypointn) {
00436         polypoints = ALLOC(boxn * 8, polypoints, Ppoint_t);
00437         polypointn = boxn * 8;
00438     }
00439 
00440     if ((boxn > 1) && (boxes[0].LL.y > boxes[1].LL.y)) {
00441         flip = 1;
00442         for (bi = 0; bi < boxn; bi++) {
00443             double v = boxes[bi].UR.y;
00444             boxes[bi].UR.y = -1*boxes[bi].LL.y;
00445             boxes[bi].LL.y = -v;
00446         }
00447     }
00448     else flip = 0;
00449 
00450     if (agtail(realedge) != aghead(realedge)) {
00451         /* I assume that the path goes either down only or
00452            up - right - down */
00453         for (bi = 0, pi = 0; bi < boxn; bi++) {
00454             next = prev = 0;
00455             if (bi > 0)
00456                 prev = (boxes[bi].LL.y > boxes[bi - 1].LL.y) ? -1 : 1;
00457             if (bi < boxn - 1)
00458                 next = (boxes[bi + 1].LL.y > boxes[bi].LL.y) ? 1 : -1;
00459             if (prev != next) {
00460                 if (next == -1 || prev == 1) {
00461                     polypoints[pi].x = boxes[bi].LL.x;
00462                     polypoints[pi++].y = boxes[bi].UR.y;
00463                     polypoints[pi].x = boxes[bi].LL.x;
00464                     polypoints[pi++].y = boxes[bi].LL.y;
00465                 } else {
00466                     polypoints[pi].x = boxes[bi].UR.x;
00467                     polypoints[pi++].y = boxes[bi].LL.y;
00468                     polypoints[pi].x = boxes[bi].UR.x;
00469                     polypoints[pi++].y = boxes[bi].UR.y;
00470                 }
00471             }
00472             else if (prev == 0) { /* single box */
00473                 polypoints[pi].x = boxes[bi].LL.x;
00474                 polypoints[pi++].y = boxes[bi].UR.y;
00475                 polypoints[pi].x = boxes[bi].LL.x;
00476                 polypoints[pi++].y = boxes[bi].LL.y;
00477             } 
00478             else {
00479                 if (!(prev == -1 && next == -1)) {
00480                     agerr(AGERR, "in routesplines, illegal values of prev %d and next %d, line %d\n", prev, next, __LINE__);
00481                     return NULL;
00482                 }
00483             }
00484         }
00485         for (bi = boxn - 1; bi >= 0; bi--) {
00486             next = prev = 0;
00487             if (bi < boxn - 1)
00488                 prev = (boxes[bi].LL.y > boxes[bi + 1].LL.y) ? -1 : 1;
00489             if (bi > 0)
00490                 next = (boxes[bi - 1].LL.y > boxes[bi].LL.y) ? 1 : -1;
00491             if (prev != next) {
00492                 if (next == -1 || prev == 1 ) {
00493                     polypoints[pi].x = boxes[bi].LL.x;
00494                     polypoints[pi++].y = boxes[bi].UR.y;
00495                     polypoints[pi].x = boxes[bi].LL.x;
00496                     polypoints[pi++].y = boxes[bi].LL.y;
00497                 } else {
00498                     polypoints[pi].x = boxes[bi].UR.x;
00499                     polypoints[pi++].y = boxes[bi].LL.y;
00500                     polypoints[pi].x = boxes[bi].UR.x;
00501                     polypoints[pi++].y = boxes[bi].UR.y;
00502                 }
00503             } 
00504             else if (prev == 0) { /* single box */
00505                 polypoints[pi].x = boxes[bi].UR.x;
00506                 polypoints[pi++].y = boxes[bi].LL.y;
00507                 polypoints[pi].x = boxes[bi].UR.x;
00508                 polypoints[pi++].y = boxes[bi].UR.y;
00509             }
00510             else {
00511                 if (!(prev == -1 && next == -1)) {
00512                     /* it went badly, e.g. degenerate box in boxlist */
00513                     agerr(AGERR, "in routesplines, illegal values of prev %d and next %d, line %d\n", prev, next, __LINE__);
00514                     return NULL; /* for correctness sake, it's best to just stop */
00515                 }
00516                 polypoints[pi].x = boxes[bi].UR.x;
00517                 polypoints[pi++].y = boxes[bi].LL.y;
00518                 polypoints[pi].x = boxes[bi].UR.x;
00519                 polypoints[pi++].y = boxes[bi].UR.y;
00520                 polypoints[pi].x = boxes[bi].LL.x;
00521                 polypoints[pi++].y = boxes[bi].UR.y;
00522                 polypoints[pi].x = boxes[bi].LL.x;
00523                 polypoints[pi++].y = boxes[bi].LL.y;
00524             }
00525         }
00526     }
00527     else {
00528         agerr(AGERR, "in routesplines, edge is a loop at %s\n", agnameof(aghead(realedge)));
00529         return NULL;
00530     }
00531 
00532     if (flip) {
00533         int i;
00534         for (bi = 0; bi < boxn; bi++) {
00535             int v = boxes[bi].UR.y;
00536             boxes[bi].UR.y = -1*boxes[bi].LL.y;
00537             boxes[bi].LL.y = -v;
00538         }
00539         for (i = 0; i < pi; i++)
00540             polypoints[i].y *= -1;
00541     }
00542 
00543     for (bi = 0; bi < boxn; bi++)
00544         boxes[bi].LL.x = INT_MAX, boxes[bi].UR.x = INT_MIN;
00545     poly.ps = polypoints, poly.pn = pi;
00546     eps[0].x = pp->start.p.x, eps[0].y = pp->start.p.y;
00547     eps[1].x = pp->end.p.x, eps[1].y = pp->end.p.y;
00548     if (Pshortestpath(&poly, eps, &pl) < 0) {
00549         agerr(AGERR, "in routesplines, Pshortestpath failed\n");
00550         return NULL;
00551     }
00552 #ifdef DEBUG
00553     if (debugleveln(realedge, 3)) {
00554         psprintpoly(poly);
00555         psprintline(pl);
00556     }
00557 #endif
00558 
00559     if (polyline) {
00560         make_polyline (pl, &spl);
00561     }
00562     else {
00563         if (poly.pn > edgen) {
00564             edges = ALLOC(poly.pn, edges, Pedge_t);
00565             edgen = poly.pn;
00566         }
00567         for (edgei = 0; edgei < poly.pn; edgei++) {
00568             edges[edgei].a = polypoints[edgei];
00569             edges[edgei].b = polypoints[(edgei + 1) % poly.pn];
00570         }
00571         if (pp->start.constrained) {
00572             evs[0].x = cos(pp->start.theta);
00573             evs[0].y = sin(pp->start.theta);
00574         } else
00575             evs[0].x = evs[0].y = 0;
00576         if (pp->end.constrained) {
00577             evs[1].x = -cos(pp->end.theta);
00578             evs[1].y = -sin(pp->end.theta);
00579         } else
00580             evs[1].x = evs[1].y = 0;
00581 
00582         if (Proutespline(edges, poly.pn, pl, evs, &spl) < 0) {
00583             agerr(AGERR, "in routesplines, Proutespline failed\n");
00584             return NULL;
00585         }
00586 #ifdef DEBUG
00587         if (debugleveln(realedge, 3)) {
00588             psprintspline(spl);
00589             psprintinit(0);
00590         }
00591 #endif
00592     }
00593     if (mkspacep(spl.pn))
00594         return NULL;  /* Bailout if no memory left */
00595 
00596     for (bi = 0; bi < boxn; bi++) {
00597         boxes[bi].LL.x = INT_MAX;
00598         boxes[bi].UR.x = INT_MIN;
00599     }
00600     unbounded = TRUE;
00601     for (splinepi = 0; splinepi < spl.pn; splinepi++) {
00602         ps[splinepi] = spl.ps[splinepi];
00603     }
00604 
00605     for (loopcnt = 0; unbounded && (loopcnt < LOOP_TRIES); loopcnt++) {
00606         limitBoxes (boxes, boxn, ps, spl.pn, delta);
00607 
00608     /* The following check is necessary because if a box is not very 
00609      * high, it is possible that the sampling above might miss it.
00610      * Therefore, we make the sample finer until all boxes have
00611      * valid values. cf. bug 456. Would making sp[] pointfs help?
00612      */
00613         for (bi = 0; bi < boxn; bi++) {
00614         /* these fp equality tests are used only to detect if the
00615          * values have been changed since initialization - ok */
00616             if ((boxes[bi].LL.x == INT_MAX) || (boxes[bi].UR.x == INT_MIN)) {
00617                 delta *= 2; /* try again with a finer interval */
00618                 if (delta > INT_MAX/boxn) /* in limitBoxes, boxn*delta must fit in an int, so give up */
00619                     loopcnt = LOOP_TRIES;
00620                 break;
00621             }
00622         }
00623         if (bi == boxn)
00624             unbounded = FALSE;
00625     }
00626     if (unbounded) {  
00627         /* Either an extremely short, even degenerate, box, or some failure with the path
00628          * planner causing the spline to miss some boxes. In any case, use the shortest path 
00629          * to bound the boxes. This will probably mean a bad edge, but we avoid an infinite
00630          * loop and we can see the bad edge, and even use the showboxes scaffolding.
00631          */
00632         Ppolyline_t polyspl;
00633         agerr(AGWARN, "Unable to reclaim box space in spline routing for edge \"%s\" -> \"%s\". Something is probably seriously wrong.\n", agnameof(agtail(realedge)), agnameof(aghead(realedge)));
00634         make_polyline (pl, &polyspl);
00635         limitBoxes (boxes, boxn, polyspl.ps, polyspl.pn, INIT_DELTA);
00636         free (polyspl.ps);
00637     }
00638 
00639     *npoints = spl.pn;
00640 
00641 #ifdef DEBUG
00642     if (GD_showboxes(realedge->head->graph) == 2 ||
00643         GD_showboxes(realedge->tail->graph) == 2 ||
00644         ED_showboxes(realedge) == 2 ||
00645         ND_showboxes(realedge->head) == 2 ||
00646         ND_showboxes(realedge->tail) == 2)
00647         printboxes(boxn, boxes);
00648 #endif
00649 
00650     return ps;
00651 }
00652 
00653 pointf *routesplines(path * pp, int *npoints)
00654 {
00655     return _routesplines (pp, npoints, 0);
00656 }
00657 
00658 pointf *routepolylines(path * pp, int *npoints)
00659 {
00660     return _routesplines (pp, npoints, 1);
00661 }
00662 
00663 static int overlap(int i0, int i1, int j0, int j1)
00664 {
00665     /* i'll bet there's an elegant way to do this */
00666     if (i1 <= j0)
00667         return 0;
00668     if (i0 >= j1)
00669         return 0;
00670     if ((j0 <= i0) && (i0 <= j1))
00671         return (j1 - i0);
00672     if ((j0 <= i1) && (i1 <= j1))
00673         return (i1 - j0);
00674     return MIN(i1 - i0, j1 - j0);
00675 }
00676 
00677 
00678 /*
00679  * repairs minor errors in the boxpath, such as boxes not joining
00680  * or slightly intersecting.  it's sort of the equivalent of the
00681  * audit process in the 5E control program - if you've given up on
00682  * fixing all the bugs, at least try to engineer around them!
00683  * in postmodern CS, we could call this "self-healing code."
00684  *
00685  * Return 1 on failure; 0 on success.
00686  */
00687 static int checkpath(int boxn, boxf* boxes, path* thepath)
00688 {
00689     boxf *ba, *bb;
00690     int bi, i, errs, l, r, d, u;
00691     int xoverlap, yoverlap;
00692 
00693 #ifndef DONTFIXPATH
00694     /* remove degenerate boxes. */
00695     i = 0;
00696     for (bi = 0; bi < boxn; bi++) {
00697         if (ABS(boxes[bi].LL.y - boxes[bi].UR.y) < .01)
00698             continue;
00699         if (ABS(boxes[bi].LL.x - boxes[bi].UR.x) < .01)
00700             continue;
00701         if (i != bi)
00702             boxes[i] = boxes[bi];
00703         i++;
00704     }
00705     boxn = i;
00706 #endif                          /* DONTFIXPATH */
00707 
00708     ba = &boxes[0];
00709     if (ba->LL.x > ba->UR.x || ba->LL.y > ba->UR.y) {
00710         agerr(AGERR, "in checkpath, box 0 has LL coord > UR coord\n");
00711         printpath(thepath);
00712         return 1;
00713     }
00714     for (bi = 0; bi < boxn - 1; bi++) {
00715         ba = &boxes[bi], bb = &boxes[bi + 1];
00716         if (bb->LL.x > bb->UR.x || bb->LL.y > bb->UR.y) {
00717             agerr(AGERR, "in checkpath, box %d has LL coord > UR coord\n",
00718                   bi + 1);
00719             printpath(thepath);
00720             return 1;
00721         }
00722         l = (ba->UR.x < bb->LL.x) ? 1 : 0;
00723         r = (ba->LL.x > bb->UR.x) ? 1 : 0;
00724         d = (ba->UR.y < bb->LL.y) ? 1 : 0;
00725         u = (ba->LL.y > bb->UR.y) ? 1 : 0;
00726         errs = l + r + d + u;
00727         if (errs > 0 && Verbose) {
00728             fprintf(stderr, "in checkpath, boxes %d and %d don't touch\n",
00729                     bi, bi + 1);
00730             printpath(thepath);
00731         }
00732 #ifndef DONTFIXPATH
00733         if (errs > 0) {
00734             int xy;
00735 
00736             if (l == 1)
00737                 xy = ba->UR.x, ba->UR.x = bb->LL.x, bb->LL.x = xy, l = 0;
00738             else if (r == 1)
00739                 xy = ba->LL.x, ba->LL.x = bb->UR.x, bb->UR.x = xy, r = 0;
00740             else if (d == 1)
00741                 xy = ba->UR.y, ba->UR.y = bb->LL.y, bb->LL.y = xy, d = 0;
00742             else if (u == 1)
00743                 xy = ba->LL.y, ba->LL.y = bb->UR.y, bb->UR.y = xy, u = 0;
00744             for (i = 0; i < errs - 1; i++) {
00745                 if (l == 1)
00746                     xy = (ba->UR.x + bb->LL.x) / 2.0 + 0.5, ba->UR.x =
00747                         bb->LL.x = xy, l = 0;
00748                 else if (r == 1)
00749                     xy = (ba->LL.x + bb->UR.x) / 2.0 + 0.5, ba->LL.x =
00750                         bb->UR.x = xy, r = 0;
00751                 else if (d == 1)
00752                     xy = (ba->UR.y + bb->LL.y) / 2.0 + 0.5, ba->UR.y =
00753                         bb->LL.y = xy, d = 0;
00754                 else if (u == 1)
00755                     xy = (ba->LL.y + bb->UR.y) / 2.0 + 0.5, ba->LL.y =
00756                         bb->UR.y = xy, u = 0;
00757             }
00758         }
00759 #else
00760         abort();
00761 #endif
00762 #ifndef DONTFIXPATH
00763         /* check for overlapping boxes */
00764         xoverlap = overlap(ba->LL.x, ba->UR.x, bb->LL.x, bb->UR.x);
00765         yoverlap = overlap(ba->LL.y, ba->UR.y, bb->LL.y, bb->UR.y);
00766         if (xoverlap && yoverlap) {
00767             if (xoverlap < yoverlap) {
00768                 if (ba->UR.x - ba->LL.x > bb->UR.x - bb->LL.x) {
00769                     /* take space from ba */
00770                     if (ba->UR.x < bb->UR.x)
00771                         ba->UR.x = bb->LL.x;
00772                     else
00773                         ba->LL.x = bb->UR.x;
00774                 } else {
00775                     /* take space from bb */
00776                     if (ba->UR.x < bb->UR.x)
00777                         bb->LL.x = ba->UR.x;
00778                     else
00779                         bb->UR.x = ba->LL.x;
00780                 }
00781             } else {            /* symmetric for y coords */
00782                 if (ba->UR.y - ba->LL.y > bb->UR.y - bb->LL.y) {
00783                     /* take space from ba */
00784                     if (ba->UR.y < bb->UR.y)
00785                         ba->UR.y = bb->LL.y;
00786                     else
00787                         ba->LL.y = bb->UR.y;
00788                 } else {
00789                     /* take space from bb */
00790                     if (ba->UR.y < bb->UR.y)
00791                         bb->LL.y = ba->UR.y;
00792                     else
00793                         bb->UR.y = ba->LL.y;
00794                 }
00795             }
00796         }
00797     }
00798 #endif                          /* DONTFIXPATH */
00799 
00800     if (thepath->start.p.x < boxes[0].LL.x
00801         || thepath->start.p.x > boxes[0].UR.x
00802         || thepath->start.p.y < boxes[0].LL.y
00803         || thepath->start.p.y > boxes[0].UR.y) {
00804         if (Verbose) {
00805             fprintf(stderr, "in checkpath, start port not in first box\n");
00806             printpath(thepath);
00807         }
00808 #ifndef DONTFIXPATH
00809         if (thepath->start.p.x < boxes[0].LL.x)
00810             thepath->start.p.x = boxes[0].LL.x;
00811         if (thepath->start.p.x > boxes[0].UR.x)
00812             thepath->start.p.x = boxes[0].UR.x;
00813         if (thepath->start.p.y < boxes[0].LL.y)
00814             thepath->start.p.y = boxes[0].LL.y;
00815         if (thepath->start.p.y > boxes[0].UR.y)
00816             thepath->start.p.y = boxes[0].UR.y;
00817 #else
00818         abort();
00819 #endif
00820     }
00821     if (thepath->end.p.x < boxes[boxn - 1].LL.x
00822         || thepath->end.p.x > boxes[boxn - 1].UR.x
00823         || thepath->end.p.y < boxes[boxn - 1].LL.y
00824         || thepath->end.p.y > boxes[boxn - 1].UR.y) {
00825         if (Verbose) {
00826             fprintf(stderr, "in checkpath, end port not in last box\n");
00827             printpath(thepath);
00828         }
00829 #ifndef DONTFIXPATH
00830         if (thepath->end.p.x < boxes[boxn - 1].LL.x)
00831             thepath->end.p.x = boxes[boxn - 1].LL.x;
00832         if (thepath->end.p.x > boxes[boxn - 1].UR.x)
00833             thepath->end.p.x = boxes[boxn - 1].UR.x;
00834         if (thepath->end.p.y < boxes[boxn - 1].LL.y)
00835             thepath->end.p.y = boxes[boxn - 1].LL.y;
00836         if (thepath->end.p.y > boxes[boxn - 1].UR.y)
00837             thepath->end.p.y = boxes[boxn - 1].UR.y;
00838 #else
00839         abort();
00840 #endif
00841     }
00842     return 0;
00843 }
00844 
00845 static int mkspacep(int size)
00846 {
00847     if (size > maxpn) {
00848         int newmax = maxpn + (size / PINC + 1) * PINC;
00849         ps = RALLOC(newmax, ps, pointf);
00850         if (!ps) {
00851             agerr(AGERR, "cannot re-allocate ps\n");
00852             return 1;
00853         }
00854         maxpn = newmax;
00855     }
00856     return 0;
00857 }
00858 
00859 static void printpath(path * pp)
00860 {
00861     int bi;
00862 
00863 #ifdef NOTNOW
00864     fprintf(stderr, "edge %d from %s to %s\n", nedges,
00865             realedge->tail->name, realedge->head->name);
00866     if (ED_count(origedge) > 1)
00867         fprintf(stderr, "    (it's part of a concentrator edge)\n");
00868 #endif
00869     fprintf(stderr, "%d boxes:\n", pp->nbox);
00870     for (bi = 0; bi < pp->nbox; bi++)
00871         fprintf(stderr, "%d (%.5g, %.5g), (%.5g, %.5g)\n", bi,
00872                 pp->boxes[bi].LL.x, pp->boxes[bi].LL.y,
00873                 pp->boxes[bi].UR.x, pp->boxes[bi].UR.y);
00874     fprintf(stderr, "start port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
00875             pp->start.p.x, pp->start.p.y, pp->start.theta,
00876             pp->start.constrained ? "constrained" : "not constrained");
00877     fprintf(stderr, "end port: (%.5g, %.5g), tangent angle: %.5g, %s\n",
00878             pp->end.p.x, pp->end.p.y, pp->end.theta,
00879             pp->end.constrained ? "constrained" : "not constrained");
00880 }
00881