|
Graphviz
2.29.20120524.0446
|
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
1.7.5