|
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 00015 #ifdef HAVE_CONFIG_H 00016 #include "config.h" 00017 #endif 00018 00019 #include "neato.h" 00020 #include "adjust.h" 00021 #include "pathplan.h" 00022 #include "vispath.h" 00023 #include "multispline.h" 00024 #ifndef HAVE_DRAND48 00025 extern double drand48(void); 00026 #endif 00027 00028 #ifdef ORTHO 00029 #include <ortho.h> 00030 #endif 00031 00032 extern void printvis(vconfig_t * cp); 00033 extern int in_poly(Ppoly_t argpoly, Ppoint_t q); 00034 00035 static boolean spline_merge(node_t * n) 00036 { 00037 return FALSE; 00038 } 00039 00040 static boolean swap_ends_p(edge_t * e) 00041 { 00042 return FALSE; 00043 } 00044 00045 static splineInfo sinfo = { swap_ends_p, spline_merge }; 00046 00047 static void 00048 make_barriers(Ppoly_t ** poly, int npoly, int pp, int qp, 00049 Pedge_t ** barriers, int *n_barriers) 00050 { 00051 int i, j, k, n, b; 00052 Pedge_t *bar; 00053 00054 n = 0; 00055 for (i = 0; i < npoly; i++) { 00056 if (i == pp) 00057 continue; 00058 if (i == qp) 00059 continue; 00060 n = n + poly[i]->pn; 00061 } 00062 bar = N_GNEW(n, Pedge_t); 00063 b = 0; 00064 for (i = 0; i < npoly; i++) { 00065 if (i == pp) 00066 continue; 00067 if (i == qp) 00068 continue; 00069 for (j = 0; j < poly[i]->pn; j++) { 00070 k = j + 1; 00071 if (k >= poly[i]->pn) 00072 k = 0; 00073 bar[b].a = poly[i]->ps[j]; 00074 bar[b].b = poly[i]->ps[k]; 00075 b++; 00076 } 00077 } 00078 assert(b == n); 00079 *barriers = bar; 00080 *n_barriers = n; 00081 } 00082 00083 /* genPt: 00084 */ 00085 static Ppoint_t genPt(double x, double y, pointf c) 00086 { 00087 Ppoint_t p; 00088 00089 p.x = x + c.x; 00090 p.y = y + c.y; 00091 return p; 00092 } 00093 00094 00095 /* recPt: 00096 */ 00097 static Ppoint_t recPt(double x, double y, pointf c, expand_t* m) 00098 { 00099 Ppoint_t p; 00100 00101 p.x = (x * m->x) + c.x; 00102 p.y = (y * m->y) + c.y; 00103 return p; 00104 } 00105 00106 typedef struct { 00107 node_t *n1; 00108 pointf p1; 00109 node_t *n2; 00110 pointf p2; 00111 } edgeinfo; 00112 typedef struct { 00113 Dtlink_t link; 00114 edgeinfo id; 00115 edge_t *e; 00116 } edgeitem; 00117 00118 static void *newitem(Dt_t * d, edgeitem * obj, Dtdisc_t * disc) 00119 { 00120 edgeitem *newp; 00121 00122 NOTUSED(disc); 00123 newp = NEW(edgeitem); 00124 newp->id = obj->id; 00125 newp->e = obj->e; 00126 ED_count(newp->e) = 1; 00127 00128 return newp; 00129 } 00130 00131 static void freeitem(Dt_t * d, edgeitem * obj, Dtdisc_t * disc) 00132 { 00133 free(obj); 00134 } 00135 00136 static int 00137 cmpitems(Dt_t * d, edgeinfo * key1, edgeinfo * key2, Dtdisc_t * disc) 00138 { 00139 int x; 00140 00141 if (key1->n1 > key2->n1) 00142 return 1; 00143 if (key1->n1 < key2->n1) 00144 return -1; 00145 if (key1->n2 > key2->n2) 00146 return 1; 00147 if (key1->n2 < key2->n2) 00148 return -1; 00149 00150 if ((x = key1->p1.x - key2->p1.x)) 00151 return x; 00152 if ((x = key1->p1.y - key2->p1.y)) 00153 return x; 00154 if ((x = key1->p2.x - key2->p2.x)) 00155 return x; 00156 return (key1->p2.y - key2->p2.y); 00157 } 00158 00159 Dtdisc_t edgeItemDisc = { 00160 offsetof(edgeitem, id), 00161 sizeof(edgeinfo), 00162 offsetof(edgeitem, link), 00163 (Dtmake_f) newitem, 00164 (Dtfree_f) freeitem, 00165 (Dtcompar_f) cmpitems, 00166 0, 00167 0, 00168 0 00169 }; 00170 00171 /* equivEdge: 00172 * See if we have already encountered an edge between the same 00173 * node:port pairs. If so, return the earlier edge. If not, 00174 * this edge is added to map and returned. 00175 * We first have to canonicalize the key fields using a lexicographic 00176 * ordering. 00177 */ 00178 static edge_t *equivEdge(Dt_t * map, edge_t * e) 00179 { 00180 edgeinfo test; 00181 edgeitem dummy; 00182 edgeitem *ip; 00183 00184 if (agtail(e) < aghead(e)) { 00185 test.n1 = agtail(e); 00186 test.p1 = ED_tail_port(e).p; 00187 test.n2 = aghead(e); 00188 test.p2 = ED_head_port(e).p; 00189 } else if (agtail(e) > aghead(e)) { 00190 test.n2 = agtail(e); 00191 test.p2 = ED_tail_port(e).p; 00192 test.n1 = aghead(e); 00193 test.p1 = ED_head_port(e).p; 00194 } else { 00195 pointf hp = ED_head_port(e).p; 00196 pointf tp = ED_tail_port(e).p; 00197 if (tp.x < hp.x) { 00198 test.p1 = tp; 00199 test.p2 = hp; 00200 } else if (tp.x > hp.x) { 00201 test.p1 = hp; 00202 test.p2 = tp; 00203 } else if (tp.y < hp.y) { 00204 test.p1 = tp; 00205 test.p2 = hp; 00206 } else if (tp.y > hp.y) { 00207 test.p1 = hp; 00208 test.p2 = tp; 00209 } else { 00210 test.p1 = test.p2 = tp; 00211 } 00212 test.n2 = test.n1 = agtail(e); 00213 } 00214 dummy.id = test; 00215 dummy.e = e; 00216 ip = dtinsert(map, &dummy); 00217 return ip->e; 00218 } 00219 00220 00221 /* makeSelfArcs: 00222 * Generate loops. We use the library routine makeSelfEdge 00223 * which also places the labels. 00224 * We have to handle port labels here. 00225 * as well as update the bbox from edge labels. 00226 */ 00227 void makeSelfArcs(path * P, edge_t * e, int stepx) 00228 { 00229 int cnt = ED_count(e); 00230 00231 if ((cnt == 1) || Concentrate) { 00232 edge_t *edges1[1]; 00233 edges1[0] = e; 00234 makeSelfEdge(P, edges1, 0, 1, stepx, stepx, &sinfo); 00235 if (ED_label(e)) 00236 updateBB(agraphof(agtail(e)), ED_label(e)); 00237 makePortLabels(e); 00238 } else { 00239 int i; 00240 edge_t **edges = N_GNEW(cnt, edge_t *); 00241 for (i = 0; i < cnt; i++) { 00242 edges[i] = e; 00243 e = ED_to_virt(e); 00244 } 00245 makeSelfEdge(P, edges, 0, cnt, stepx, stepx, &sinfo); 00246 for (i = 0; i < cnt; i++) { 00247 e = edges[i]; 00248 if (ED_label(e)) 00249 updateBB(agraphof(agtail(e)), ED_label(e)); 00250 makePortLabels(e); 00251 } 00252 free(edges); 00253 } 00254 } 00255 00256 /* makeStraightEdge: 00257 * 00258 * FIX: handle ports on boundary? 00259 */ 00260 void 00261 makeStraightEdge(graph_t * g, edge_t * e, int doPolyline) 00262 { 00263 pointf dumb[4]; 00264 node_t *n = agtail(e); 00265 node_t *head = aghead(e); 00266 int e_cnt = ED_count(e); 00267 pointf perp; 00268 pointf del; 00269 edge_t *e0; 00270 int i, j, xstep, dx; 00271 double l_perp; 00272 pointf dumber[4]; 00273 pointf p, q; 00274 00275 p = dumb[1] = dumb[0] = add_pointf(ND_coord(n), ED_tail_port(e).p); 00276 q = dumb[2] = dumb[3] = add_pointf(ND_coord(head), ED_head_port(e).p); 00277 if ((e_cnt == 1) || Concentrate) { 00278 clip_and_install(e, aghead(e), dumb, 4, &sinfo); 00279 addEdgeLabels(g, e, p, q); 00280 return; 00281 } 00282 00283 e0 = e; 00284 if (APPROXEQPT(dumb[0], dumb[3], MILLIPOINT)) { 00285 /* degenerate case */ 00286 dumb[1] = dumb[0]; 00287 dumb[2] = dumb[3]; 00288 del.x = 0; 00289 del.y = 0; 00290 } 00291 else { 00292 perp.x = dumb[0].y - dumb[3].y; 00293 perp.y = dumb[3].x - dumb[0].x; 00294 l_perp = LEN(perp.x, perp.y); 00295 xstep = GD_nodesep(g->root); 00296 dx = xstep * (e_cnt - 1) / 2; 00297 dumb[1].x = dumb[0].x + (dx * perp.x) / l_perp; 00298 dumb[1].y = dumb[0].y + (dx * perp.y) / l_perp; 00299 dumb[2].x = dumb[3].x + (dx * perp.x) / l_perp; 00300 dumb[2].y = dumb[3].y + (dx * perp.y) / l_perp; 00301 del.x = -xstep * perp.x / l_perp; 00302 del.y = -xstep * perp.y / l_perp; 00303 } 00304 00305 for (i = 0; i < e_cnt; i++) { 00306 if (aghead(e0) == head) { 00307 p = dumb[0]; 00308 q = dumb[3]; 00309 for (j = 0; j < 4; j++) { 00310 dumber[j] = dumb[j]; 00311 } 00312 } else { 00313 p = dumb[3]; 00314 q = dumb[0]; 00315 for (j = 0; j < 4; j++) { 00316 dumber[3 - j] = dumb[j]; 00317 } 00318 } 00319 if (doPolyline) { 00320 Ppoint_t pts[4]; 00321 Ppolyline_t spl, line; 00322 00323 line.pn = 4; 00324 line.ps = pts; 00325 for (j=0; j < 4; j++) { 00326 pts[j] = dumber[j]; 00327 } 00328 make_polyline (line, &spl); 00329 clip_and_install(e0, aghead(e0), spl.ps, spl.pn, &sinfo); 00330 } 00331 else 00332 clip_and_install(e0, aghead(e0), dumber, 4, &sinfo); 00333 00334 addEdgeLabels(g, e0, p, q); 00335 e0 = ED_to_virt(e0); 00336 dumb[1].x += del.x; 00337 dumb[1].y += del.y; 00338 dumb[2].x += del.x; 00339 dumb[2].y += del.y; 00340 } 00341 } 00342 00343 /* makeObstacle: 00344 * Given a node, return an obstacle reflecting the 00345 * node's geometry. pmargin specifies how much space to allow 00346 * around the polygon. 00347 * Returns the constructed polygon on success, NULL on failure. 00348 * Failure means the node shape is not supported. 00349 * 00350 * The polygon has its vertices in CW order. 00351 * 00352 */ 00353 Ppoly_t *makeObstacle(node_t * n, expand_t* pmargin) 00354 { 00355 Ppoly_t *obs; 00356 polygon_t *poly; 00357 double adj = 0.0; 00358 int j, sides; 00359 pointf polyp; 00360 boxf b; 00361 pointf pt; 00362 field_t *fld; 00363 epsf_t *desc; 00364 00365 switch (shapeOf(n)) { 00366 case SH_POLY: 00367 case SH_POINT: 00368 obs = NEW(Ppoly_t); 00369 poly = (polygon_t *) ND_shape_info(n); 00370 if (poly->sides >= 3) { 00371 sides = poly->sides; 00372 } else { /* ellipse */ 00373 sides = 8; 00374 adj = drand48() * .01; 00375 } 00376 obs->pn = sides; 00377 obs->ps = N_NEW(sides, Ppoint_t); 00378 /* assuming polys are in CCW order, and pathplan needs CW */ 00379 for (j = 0; j < sides; j++) { 00380 double xmargin = 0.0, ymargin = 0.0; 00381 if (poly->sides >= 3) { 00382 if (pmargin->doAdd) { 00383 if (poly->sides == 4) { 00384 switch (j) { 00385 case 0 : 00386 xmargin = pmargin->x; 00387 ymargin = pmargin->y; 00388 break; 00389 case 1 : 00390 xmargin = -pmargin->x; 00391 ymargin = pmargin->y; 00392 break; 00393 case 2 : 00394 xmargin = -pmargin->x; 00395 ymargin = -pmargin->y; 00396 break; 00397 case 3 : 00398 xmargin = pmargin->x; 00399 ymargin = -pmargin->y; 00400 break; 00401 } 00402 polyp.x = poly->vertices[j].x + xmargin; 00403 polyp.y = poly->vertices[j].y + ymargin; 00404 } 00405 else { 00406 double h = LEN(poly->vertices[j].x,poly->vertices[j].y); 00407 polyp.x = poly->vertices[j].x * (1.0 + pmargin->x/h); 00408 polyp.y = poly->vertices[j].y * (1.0 + pmargin->y/h); 00409 } 00410 } 00411 else { 00412 polyp.x = poly->vertices[j].x * pmargin->x; 00413 polyp.y = poly->vertices[j].y * pmargin->y; 00414 } 00415 } else { 00416 double c, s; 00417 c = cos(2.0 * M_PI * j / sides + adj); 00418 s = sin(2.0 * M_PI * j / sides + adj); 00419 if (pmargin->doAdd) { 00420 polyp.x = c*(ND_lw(n)+ND_rw(n)+pmargin->x) / 2.0; 00421 polyp.y = s*(ND_ht(n)+pmargin->y) / 2.0; 00422 } 00423 else { 00424 polyp.x = pmargin->x * c * (ND_lw(n) + ND_rw(n)) / 2.0; 00425 polyp.y = pmargin->y * s * ND_ht(n) / 2.0; 00426 } 00427 } 00428 obs->ps[sides - j - 1].x = polyp.x + ND_coord(n).x; 00429 obs->ps[sides - j - 1].y = polyp.y + ND_coord(n).y; 00430 } 00431 break; 00432 case SH_RECORD: 00433 fld = (field_t *) ND_shape_info(n); 00434 b = fld->b; 00435 obs = NEW(Ppoly_t); 00436 obs->pn = 4; 00437 obs->ps = N_NEW(4, Ppoint_t); 00438 /* CW order */ 00439 pt = ND_coord(n); 00440 if (pmargin->doAdd) { 00441 obs->ps[0] = genPt(b.LL.x-pmargin->x, b.LL.y-pmargin->y, pt); 00442 obs->ps[1] = genPt(b.LL.x-pmargin->x, b.UR.y+pmargin->y, pt); 00443 obs->ps[2] = genPt(b.UR.x+pmargin->x, b.UR.y+pmargin->y, pt); 00444 obs->ps[3] = genPt(b.UR.x+pmargin->x, b.LL.y-pmargin->y, pt); 00445 } 00446 else { 00447 obs->ps[0] = recPt(b.LL.x, b.LL.y, pt, pmargin); 00448 obs->ps[1] = recPt(b.LL.x, b.UR.y, pt, pmargin); 00449 obs->ps[2] = recPt(b.UR.x, b.UR.y, pt, pmargin); 00450 obs->ps[3] = recPt(b.UR.x, b.LL.y, pt, pmargin); 00451 } 00452 break; 00453 case SH_EPSF: 00454 desc = (epsf_t *) (ND_shape_info(n)); 00455 obs = NEW(Ppoly_t); 00456 obs->pn = 4; 00457 obs->ps = N_NEW(4, Ppoint_t); 00458 /* CW order */ 00459 pt = ND_coord(n); 00460 if (pmargin->doAdd) { 00461 obs->ps[0] = genPt(-ND_lw(n)-pmargin->x, -ND_ht(n)-pmargin->y,pt); 00462 obs->ps[1] = genPt(-ND_lw(n)-pmargin->x, ND_ht(n)+pmargin->y,pt); 00463 obs->ps[2] = genPt(ND_rw(n)+pmargin->x, ND_ht(n)+pmargin->y,pt); 00464 obs->ps[3] = genPt(ND_rw(n)+pmargin->x, -ND_ht(n)-pmargin->y,pt); 00465 } 00466 else { 00467 obs->ps[0] = recPt(-ND_lw(n), -ND_ht(n), pt, pmargin); 00468 obs->ps[1] = recPt(-ND_lw(n), ND_ht(n), pt, pmargin); 00469 obs->ps[2] = recPt(ND_rw(n), ND_ht(n), pt, pmargin); 00470 obs->ps[3] = recPt(ND_rw(n), -ND_ht(n), pt, pmargin); 00471 } 00472 break; 00473 default: 00474 obs = NULL; 00475 break; 00476 } 00477 return obs; 00478 } 00479 00480 /* getPath 00481 * Construct the shortest path from one endpoint of e to the other. 00482 * The obstacles and their number are given by obs and npoly. 00483 * vconfig is a precomputed data structure to help in the computation. 00484 * If chkPts is true, the function finds the polygons, if any, containing 00485 * the endpoints and tells the shortest path computation to ignore them. 00486 * Assumes this info is set in ND_lim, usually from _spline_edges. 00487 * Returns the shortest path. 00488 */ 00489 Ppolyline_t 00490 getPath(edge_t * e, vconfig_t * vconfig, int chkPts, Ppoly_t ** obs, 00491 int npoly) 00492 { 00493 Ppolyline_t line; 00494 int pp, qp; 00495 Ppoint_t p, q; 00496 00497 p = add_pointf(ND_coord(agtail(e)), ED_tail_port(e).p); 00498 q = add_pointf(ND_coord(aghead(e)), ED_head_port(e).p); 00499 00500 /* determine the polygons (if any) that contain the endpoints */ 00501 pp = qp = POLYID_NONE; 00502 if (chkPts) { 00503 pp = ND_lim(agtail(e)); 00504 qp = ND_lim(aghead(e)); 00505 /* 00506 for (i = 0; i < npoly; i++) { 00507 if ((pp == POLYID_NONE) && in_poly(*obs[i], p)) 00508 pp = i; 00509 if ((qp == POLYID_NONE) && in_poly(*obs[i], q)) 00510 qp = i; 00511 } 00512 */ 00513 } 00514 Pobspath(vconfig, p, pp, q, qp, &line); 00515 return line; 00516 } 00517 00518 /* makePolyline: 00519 */ 00520 static void 00521 makePolyline(graph_t* g, edge_t * e) 00522 { 00523 Ppolyline_t spl, line = ED_path(e); 00524 Ppoint_t p0, q0; 00525 00526 p0 = line.ps[0]; 00527 q0 = line.ps[line.pn - 1]; 00528 make_polyline (line, &spl); 00529 if (Verbose > 1) 00530 fprintf(stderr, "polyline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e))); 00531 clip_and_install(e, aghead(e), spl.ps, spl.pn, &sinfo); 00532 addEdgeLabels(g, e, p0, q0); 00533 } 00534 00535 /* makeSpline: 00536 * Construct a spline connecting the endpoints of e, avoiding the npoly 00537 * obstacles obs. 00538 * The resultant spline is attached to the edge, the positions of any 00539 * edge labels are computed, and the graph's bounding box is recomputed. 00540 * 00541 * If chkPts is true, the function checks if one or both of the endpoints 00542 * is on or inside one of the obstacles and, if so, tells the shortest path 00543 * computation to ignore them. 00544 */ 00545 void makeSpline(graph_t* g, edge_t * e, Ppoly_t ** obs, int npoly, boolean chkPts) 00546 { 00547 Ppolyline_t line, spline; 00548 Pvector_t slopes[2]; 00549 int i, n_barriers; 00550 int pp, qp; 00551 Ppoint_t p, q; 00552 Pedge_t *barriers; 00553 00554 line = ED_path(e); 00555 p = line.ps[0]; 00556 q = line.ps[line.pn - 1]; 00557 /* determine the polygons (if any) that contain the endpoints */ 00558 pp = qp = POLYID_NONE; 00559 if (chkPts) 00560 for (i = 0; i < npoly; i++) { 00561 if ((pp == POLYID_NONE) && in_poly(*obs[i], p)) 00562 pp = i; 00563 if ((qp == POLYID_NONE) && in_poly(*obs[i], q)) 00564 qp = i; 00565 } 00566 00567 make_barriers(obs, npoly, pp, qp, &barriers, &n_barriers); 00568 slopes[0].x = slopes[0].y = 0.0; 00569 slopes[1].x = slopes[1].y = 0.0; 00570 if (Proutespline(barriers, n_barriers, line, slopes, &spline) < 0) { 00571 agerr (AGERR, "makeSpline: failed to make spline edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e))); 00572 return; 00573 } 00574 00575 /* north why did you ever use int coords */ 00576 if (Verbose > 1) 00577 fprintf(stderr, "spline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e))); 00578 clip_and_install(e, aghead(e), spline.ps, spline.pn, &sinfo); 00579 free(barriers); 00580 addEdgeLabels(g, e, p, q); 00581 } 00582 00583 /* True if either head or tail has a port on its boundary */ 00584 #define BOUNDARY_PORT(e) ((ED_tail_port(e).side)||(ED_head_port(e).side)) 00585 00586 /* _spline_edges: 00587 * Basic default routine for creating edges. 00588 * If splines are requested, we construct the obstacles. 00589 * If not, or nodes overlap, the function reverts to line segments. 00590 * NOTE: intra-cluster edges are not constrained to 00591 * remain in the cluster's bounding box and, conversely, a cluster's box 00592 * is not altered to reflect intra-cluster edges. 00593 * If Nop > 1 and the spline exists, it is just copied. 00594 */ 00595 static int _spline_edges(graph_t * g, expand_t* pmargin, int edgetype) 00596 { 00597 node_t *n; 00598 edge_t *e; 00599 edge_t *e0; 00600 Ppoly_t **obs = 0; 00601 Ppoly_t *obp; 00602 int cnt, i = 0, npoly; 00603 vconfig_t *vconfig = 0; 00604 path *P = NULL; 00605 int useEdges = (Nop > 1); 00606 router_t* rtr = 0; 00607 int legal = 0; 00608 00609 /* build configuration */ 00610 if (edgetype != ET_LINE) { 00611 obs = N_NEW(agnnodes(g), Ppoly_t *); 00612 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00613 obp = makeObstacle(n, pmargin); 00614 if (obp) { 00615 ND_lim(n) = i; 00616 obs[i++] = obp; 00617 } 00618 else 00619 ND_lim(n) = POLYID_NONE; 00620 } 00621 } else { 00622 obs = 0; 00623 } 00624 npoly = i; 00625 if (obs) { 00626 if ((legal = Plegal_arrangement(obs, npoly))) { 00627 if (edgetype != ET_ORTHO) vconfig = Pobsopen(obs, npoly); 00628 } 00629 else if (Verbose) 00630 fprintf(stderr, 00631 "nodes touch - falling back to straight line edges\n"); 00632 } 00633 00634 /* route edges */ 00635 if (Verbose) 00636 fprintf(stderr, "Creating edges using %s\n", 00637 (legal && (edgetype == ET_ORTHO)) ? "orthogonal lines" : 00638 (vconfig ? (edgetype == ET_SPLINE ? "splines" : "polylines") : 00639 "line segments")); 00640 if (vconfig) { 00641 /* path-finding pass */ 00642 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00643 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00644 ED_path(e) = getPath(e, vconfig, TRUE, obs, npoly); 00645 } 00646 } 00647 } 00648 #ifdef ORTHO 00649 else if (legal && (edgetype == ET_ORTHO)) { 00650 orthoEdges (g, 0); 00651 useEdges = 1; 00652 } 00653 #endif 00654 00655 /* spline-drawing pass */ 00656 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00657 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00658 /* fprintf (stderr, "%s -- %s %d\n", agnameof(agtail(e)), agnameof(aghead(e)), ED_count(e)); */ 00659 node_t *head = aghead(e); 00660 if (useEdges && ED_spl(e)) { 00661 addEdgeLabels(g, e, 00662 add_pointf(ND_coord(n), ED_tail_port(e).p), 00663 add_pointf(ND_coord(head), ED_head_port(e).p)); 00664 } 00665 else if (ED_count(e) == 0) continue; /* only do representative */ 00666 else if (n == head) { /* self arc */ 00667 if (!P) { 00668 P = NEW(path); 00669 P->boxes = N_NEW(agnnodes(g) + 20 * 2 * 9, boxf); 00670 } 00671 makeSelfArcs(P, e, GD_nodesep(g->root)); 00672 } else if (vconfig) { /* ET_SPLINE or ET_PLINE */ 00673 #ifdef HAVE_GTS 00674 if ((ED_count(e) > 1) || BOUNDARY_PORT(e)) { 00675 int fail = 0; 00676 if ((ED_path(e).pn == 2) && !BOUNDARY_PORT(e)) 00677 /* if a straight line can connect the ends */ 00678 makeStraightEdge(g, e, edgetype == ET_PLINE); 00679 else { 00680 if (!rtr) rtr = mkRouter (obs, npoly); 00681 fail = makeMultiSpline(g, e, rtr, edgetype == ET_PLINE); 00682 } 00683 if (!fail) continue; 00684 } 00685 /* We can probably remove this branch and just use 00686 * makeMultiSpline. It can also catch the makeStraightEdge 00687 * case. We could then eliminate all of the vconfig stuff. 00688 */ 00689 #endif 00690 cnt = ED_count(e); 00691 if (Concentrate) cnt = 1; /* only do representative */ 00692 e0 = e; 00693 for (i = 0; i < cnt; i++) { 00694 if (edgetype == ET_SPLINE) 00695 makeSpline(g, e0, obs, npoly, TRUE); 00696 else 00697 makePolyline(g, e0); 00698 e0 = ED_to_virt(e0); 00699 } 00700 } else { 00701 makeStraightEdge(g, e, 0); 00702 } 00703 } 00704 } 00705 00706 #ifdef HAVE_GTS 00707 if (rtr) 00708 freeRouter (rtr); 00709 #endif 00710 00711 if (vconfig) 00712 Pobsclose (vconfig); 00713 if (P) { 00714 free(P->boxes); 00715 free(P); 00716 } 00717 if (obs) { 00718 for (i=0; i < npoly; i++) 00719 free (obs[i]); 00720 free (obs); 00721 } 00722 return 0; 00723 } 00724 00725 /* splineEdges: 00726 * Main wrapper code for generating edges. 00727 * Sets desired separation. 00728 * Coalesces equivalent edges (edges * with the same endpoints). 00729 * It then calls the edge generating function, and marks the 00730 * spline phase complete. 00731 * Returns 0 on success. 00732 * 00733 * The edge function is given the graph, the separation to be added 00734 * around obstacles, and the type of edge. It must guarantee 00735 * that all bounding boxes are current; in particular, the bounding box of 00736 * g must reflect the addition of the edges. 00737 */ 00738 int 00739 splineEdges(graph_t * g, int (*edgefn) (graph_t *, expand_t*, int), 00740 int edgetype) 00741 { 00742 node_t *n; 00743 edge_t *e; 00744 expand_t margin; 00745 Dt_t *map; 00746 00747 margin = esepFactor (g); 00748 00749 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00750 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00751 resolvePorts (e); 00752 } 00753 } 00754 00755 /* find equivalent edges */ 00756 map = dtopen(&edgeItemDisc, Dtoset); 00757 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00758 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00759 edge_t *leader = equivEdge(map, e); 00760 if (leader != e) { 00761 ED_count(leader)++; 00762 ED_to_virt(e) = ED_to_virt(leader); 00763 ED_to_virt(leader) = e; 00764 } 00765 } 00766 } 00767 dtclose(map); 00768 00769 if (edgefn(g, &margin, edgetype)) 00770 return 1; 00771 00772 State = GVSPLINES; 00773 return 0; 00774 } 00775 00776 /* spline_edges1: 00777 * Construct edges using default algorithm and given splines value. 00778 * Return 0 on success. 00779 */ 00780 int spline_edges1(graph_t * g, int edgetype) 00781 { 00782 return splineEdges(g, _spline_edges, edgetype); 00783 } 00784 00785 /* spline_edges0: 00786 * Sets the graph's aspect ratio. 00787 * Check splines attribute and construct edges using default algorithm. 00788 * If the splines attribute is defined but equal to "", skip edge routing. 00789 * 00790 * Assumes u.bb for has been computed for g and all clusters 00791 * (not just top-level clusters), and that GD_bb(g).LL is at the origin. 00792 * 00793 * This last criterion is, I believe, mainly to simplify the code 00794 * in neato_set_aspect. It would be good to remove this constraint, 00795 * as this would allow nodes pinned on input to have the same coordinates 00796 * when output in dot or plain format. 00797 * 00798 */ 00799 void spline_edges0(graph_t * g) 00800 { 00801 int et = EDGE_TYPE (g); 00802 neato_set_aspect(g); 00803 if (et == ET_NONE) return; 00804 #ifndef ORTHO 00805 if (et == ET_ORTHO) { 00806 agerr (AGWARN, "Orthogonal edges not yet supported\n"); 00807 et = ET_PLINE; 00808 GD_flags(g->root) &= ~ET_ORTHO; 00809 GD_flags(g->root) |= ET_PLINE; 00810 } 00811 #endif 00812 spline_edges1(g, et); 00813 } 00814 00815 /* shiftClusters: 00816 */ 00817 static void 00818 shiftClusters (graph_t * g, pointf offset) 00819 { 00820 int i; 00821 00822 for (i = 1; i <= GD_n_cluster(g); i++) { 00823 shiftClusters (GD_clust(g)[i], offset); 00824 } 00825 00826 GD_bb(g).UR.x -= offset.x; 00827 GD_bb(g).UR.y -= offset.y; 00828 GD_bb(g).LL.x -= offset.x; 00829 GD_bb(g).LL.y -= offset.y; 00830 } 00831 00832 /* spline_edges: 00833 * Compute bounding box, translate graph to origin, 00834 * then construct all edges. 00835 */ 00836 void spline_edges(graph_t * g) 00837 { 00838 node_t *n; 00839 pointf offset; 00840 00841 compute_bb(g); 00842 offset.x = PS2INCH(GD_bb(g).LL.x); 00843 offset.y = PS2INCH(GD_bb(g).LL.y); 00844 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00845 ND_pos(n)[0] -= offset.x; 00846 ND_pos(n)[1] -= offset.y; 00847 } 00848 00849 shiftClusters (g, GD_bb(g).LL); 00850 spline_edges0(g); 00851 } 00852 00853 /* scaleEdge: 00854 * Scale edge by given factor. 00855 * Assume ED_spl != NULL. 00856 */ 00857 static void scaleEdge(edge_t * e, double xf, double yf) 00858 { 00859 int i, j; 00860 pointf *pt; 00861 bezier *bez; 00862 pointf delh, delt; 00863 00864 delh.x = POINTS_PER_INCH * (ND_pos(aghead(e))[0] * (xf - 1.0)); 00865 delh.y = POINTS_PER_INCH * (ND_pos(aghead(e))[1] * (yf - 1.0)); 00866 delt.x = POINTS_PER_INCH * (ND_pos(agtail(e))[0] * (xf - 1.0)); 00867 delt.y = POINTS_PER_INCH * (ND_pos(agtail(e))[1] * (yf - 1.0)); 00868 00869 bez = ED_spl(e)->list; 00870 for (i = 0; i < ED_spl(e)->size; i++) { 00871 pt = bez->list; 00872 for (j = 0; j < bez->size; j++) { 00873 if ((i == 0) && (j == 0)) { 00874 pt->x += delt.x; 00875 pt->y += delt.y; 00876 } 00877 else if ((i == ED_spl(e)->size-1) && (j == bez->size-1)) { 00878 pt->x += delh.x; 00879 pt->y += delh.y; 00880 } 00881 else { 00882 pt->x *= xf; 00883 pt->y *= yf; 00884 } 00885 pt++; 00886 } 00887 if (bez->sflag) { 00888 bez->sp.x += delt.x; 00889 bez->sp.y += delt.y; 00890 } 00891 if (bez->eflag) { 00892 bez->ep.x += delh.x; 00893 bez->ep.y += delh.y; 00894 } 00895 bez++; 00896 } 00897 00898 if (ED_label(e) && ED_label(e)->set) { 00899 ED_label(e)->pos.x *= xf; 00900 ED_label(e)->pos.y *= yf; 00901 } 00902 if (ED_head_label(e) && ED_head_label(e)->set) { 00903 ED_head_label(e)->pos.x += delh.x; 00904 ED_head_label(e)->pos.y += delh.y; 00905 } 00906 if (ED_tail_label(e) && ED_tail_label(e)->set) { 00907 ED_tail_label(e)->pos.x += delt.x; 00908 ED_tail_label(e)->pos.y += delt.y; 00909 } 00910 } 00911 00912 /* scaleBB: 00913 * Scale bounding box of clusters of g by given factors. 00914 */ 00915 static void scaleBB(graph_t * g, double xf, double yf) 00916 { 00917 int i; 00918 00919 GD_bb(g).UR.x *= xf; 00920 GD_bb(g).UR.y *= yf; 00921 GD_bb(g).LL.x *= xf; 00922 GD_bb(g).LL.y *= yf; 00923 00924 if (GD_label(g) && GD_label(g)->set) { 00925 GD_label(g)->pos.x *= xf; 00926 GD_label(g)->pos.y *= yf; 00927 } 00928 00929 for (i = 1; i <= GD_n_cluster(g); i++) 00930 scaleBB(GD_clust(g)[i], xf, yf); 00931 } 00932 00933 /* _neato_set_aspect; 00934 * Assume all bounding boxes are correct and 00935 * that GD_bb(g).LL is at origin. 00936 * Also assume g is the root graph 00937 */ 00938 static void _neato_set_aspect(graph_t * g) 00939 { 00940 /* int i; */ 00941 double xf, yf, actual, desired; 00942 node_t *n; 00943 00944 /* compute_bb(g); */ 00945 if (GD_drawing(g)->ratio_kind) { 00946 /* normalize */ 00947 assert(ROUND(GD_bb(g).LL.x) == 0); 00948 assert(ROUND(GD_bb(g).LL.y) == 0); 00949 if (GD_flip(g)) { 00950 double t = GD_bb(g).UR.x; 00951 GD_bb(g).UR.x = GD_bb(g).UR.y; 00952 GD_bb(g).UR.y = t; 00953 } 00954 if (GD_drawing(g)->ratio_kind == R_FILL) { 00955 /* fill is weird because both X and Y can stretch */ 00956 if (GD_drawing(g)->size.x <= 0) 00957 return; 00958 xf = (double) GD_drawing(g)->size.x / GD_bb(g).UR.x; 00959 yf = (double) GD_drawing(g)->size.y / GD_bb(g).UR.y; 00960 /* handle case where one or more dimensions is too big */ 00961 if ((xf < 1.0) || (yf < 1.0)) { 00962 if (xf < yf) { 00963 yf = yf / xf; 00964 xf = 1.0; 00965 } else { 00966 xf = xf / yf; 00967 yf = 1.0; 00968 } 00969 } 00970 } else if (GD_drawing(g)->ratio_kind == R_EXPAND) { 00971 if (GD_drawing(g)->size.x <= 0) 00972 return; 00973 xf = (double) GD_drawing(g)->size.x / GD_bb(g).UR.x; 00974 yf = (double) GD_drawing(g)->size.y / GD_bb(g).UR.y; 00975 if ((xf > 1.0) && (yf > 1.0)) { 00976 double scale = MIN(xf, yf); 00977 xf = yf = scale; 00978 } else 00979 return; 00980 } else if (GD_drawing(g)->ratio_kind == R_VALUE) { 00981 desired = GD_drawing(g)->ratio; 00982 actual = (GD_bb(g).UR.y) / (GD_bb(g).UR.x); 00983 if (actual < desired) { 00984 yf = desired / actual; 00985 xf = 1.0; 00986 } else { 00987 xf = actual / desired; 00988 yf = 1.0; 00989 } 00990 } else 00991 return; 00992 if (GD_flip(g)) { 00993 double t = xf; 00994 xf = yf; 00995 yf = t; 00996 } 00997 00998 if (Nop > 1) { 00999 edge_t *e; 01000 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01001 for (e = agfstout(g, n); e; e = agnxtout(g, e)) 01002 if (ED_spl(e)) 01003 scaleEdge(e, xf, yf); 01004 } 01005 } 01006 /* Not relying on neato_nlist here allows us not to have to 01007 * allocate it in the root graph and the connected components. 01008 */ 01009 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01010 ND_pos(n)[0] = ND_pos(n)[0] * xf; 01011 ND_pos(n)[1] = ND_pos(n)[1] * yf; 01012 } 01013 scaleBB(g, xf, yf); 01014 } 01015 } 01016 01017 /* neato_set_aspect: 01018 * Sets aspect ratio if necessary; real work done in _neato_set_aspect; 01019 * This also copies the internal layout coordinates (ND_pos) to the 01020 * external ones (ND_coord). 01021 */ 01022 void neato_set_aspect(graph_t * g) 01023 { 01024 node_t *n; 01025 01026 /* setting aspect ratio only makes sense on root graph */ 01027 if (g->root == g) 01028 _neato_set_aspect(g); 01029 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 01030 ND_coord(n).x = POINTS_PER_INCH * (ND_pos(n)[0]); 01031 ND_coord(n).y = POINTS_PER_INCH * (ND_pos(n)[1]); 01032 } 01033 } 01034
1.7.5