|
Graphviz
2.29.20120523.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 /* 00016 * set edge splines. 00017 */ 00018 00019 #include "dot.h" 00020 00021 #ifdef ORTHO 00022 #include <ortho.h> 00023 #endif 00024 00025 #define NSUB 9 /* number of subdivisions, re-aiming splines */ 00026 #define CHUNK 128 /* in building list of edges */ 00027 00028 #define MINW 16 /* minimum width of a box in the edge path */ 00029 #define HALFMINW 8 00030 00031 #define FWDEDGE 16 00032 #define BWDEDGE 32 00033 00034 #define MAINGRAPH 64 00035 #define AUXGRAPH 128 00036 #define GRAPHTYPEMASK 192 /* the OR of the above */ 00037 00038 #ifndef WITH_CGRAPH 00039 #define MAKEFWDEDGE(new, old) { \ 00040 edge_t *newp; \ 00041 newp = new; \ 00042 *newp = *old; \ 00043 newp->tail = old->head; \ 00044 newp->head = old->tail; \ 00045 ED_tail_port(newp) = ED_head_port(old); \ 00046 ED_head_port(newp) = ED_tail_port(old); \ 00047 ED_edge_type(newp) = VIRTUAL; \ 00048 ED_to_orig(newp) = old; \ 00049 } 00050 #else /* WITH_CGRAPH */ 00051 #define MAKEFWDEDGE(new, old) { \ 00052 edge_t *newp; \ 00053 Agedgeinfo_t *info; \ 00054 newp = new; \ 00055 info = (Agedgeinfo_t*)newp->base.data; \ 00056 *info = *(Agedgeinfo_t*)old->base.data; \ 00057 *newp = *old; \ 00058 newp->base.data = (Agrec_t*)info; \ 00059 AGTAIL(newp) = AGHEAD(old); \ 00060 AGHEAD(newp) = AGTAIL(old); \ 00061 ED_tail_port(newp) = ED_head_port(old); \ 00062 ED_head_port(newp) = ED_tail_port(old); \ 00063 ED_edge_type(newp) = VIRTUAL; \ 00064 ED_to_orig(newp) = old; \ 00065 } 00066 #endif /* WITH_CGRAPH */ 00067 00068 static boxf boxes[1000]; 00069 typedef struct { 00070 int LeftBound, RightBound, Splinesep, Multisep; 00071 boxf* Rank_box; 00072 } spline_info_t; 00073 00074 static void adjustregularpath(path *, int, int); 00075 static Agedge_t *bot_bound(Agedge_t *, int); 00076 static boolean pathscross(Agnode_t *, Agnode_t *, Agedge_t *, Agedge_t *); 00077 static Agraph_t *cl_bound(Agnode_t *, Agnode_t *); 00078 static int cl_vninside(Agraph_t *, Agnode_t *); 00079 static void completeregularpath(path *, Agedge_t *, Agedge_t *, 00080 pathend_t *, pathend_t *, boxf *, int, int); 00081 static int edgecmp(Agedge_t **, Agedge_t **); 00082 static void make_flat_edge(spline_info_t*, path *, Agedge_t **, int, int, int); 00083 static void make_regular_edge(spline_info_t*, path *, Agedge_t **, int, int, int); 00084 static boxf makeregularend(boxf, int, int); 00085 static boxf maximal_bbox(spline_info_t*, Agnode_t *, Agedge_t *, Agedge_t *); 00086 static Agnode_t *neighbor(Agnode_t *, Agedge_t *, Agedge_t *, int); 00087 static void place_vnlabel(Agnode_t *); 00088 static boxf rank_box(spline_info_t* sp, Agraph_t *, int); 00089 static void recover_slack(Agedge_t *, path *); 00090 static void resize_vn(Agnode_t *, int, int, int); 00091 static void setflags(Agedge_t *, int, int, int); 00092 static int straight_len(Agnode_t *); 00093 static Agedge_t *straight_path(Agedge_t *, int, pointf *, int *); 00094 static Agedge_t *top_bound(Agedge_t *, int); 00095 00096 #define GROWEDGES (edges = ALLOC (n_edges + CHUNK, edges, edge_t*)) 00097 00098 static edge_t* 00099 getmainedge(edge_t * e) 00100 { 00101 edge_t *le = e; 00102 while (ED_to_virt(le)) 00103 le = ED_to_virt(le); 00104 while (ED_to_orig(le)) 00105 le = ED_to_orig(le); 00106 return le; 00107 } 00108 00109 static boolean spline_merge(node_t * n) 00110 { 00111 return ((ND_node_type(n) == VIRTUAL) 00112 && ((ND_in(n).size > 1) || (ND_out(n).size > 1))); 00113 } 00114 00115 static boolean swap_ends_p(edge_t * e) 00116 { 00117 while (ED_to_orig(e)) 00118 e = ED_to_orig(e); 00119 if (ND_rank(aghead(e)) > ND_rank(agtail(e))) 00120 return FALSE; 00121 if (ND_rank(aghead(e)) < ND_rank(agtail(e))) 00122 return TRUE; 00123 if (ND_order(aghead(e)) >= ND_order(agtail(e))) 00124 return FALSE; 00125 return TRUE; 00126 } 00127 00128 static splineInfo sinfo = { swap_ends_p, spline_merge }; 00129 00130 int portcmp(port p0, port p1) 00131 { 00132 int rv; 00133 if (p1.defined == FALSE) 00134 return (p0.defined ? 1 : 0); 00135 if (p0.defined == FALSE) 00136 return -1; 00137 rv = p0.p.x - p1.p.x; 00138 if (rv == 0) 00139 rv = p0.p.y - p1.p.y; 00140 return rv; 00141 } 00142 00143 /* swap_bezier: 00144 */ 00145 static void swap_bezier(bezier * old, bezier * new) 00146 { 00147 pointf *list; 00148 pointf *lp; 00149 pointf *olp; 00150 int i, sz; 00151 00152 sz = old->size; 00153 list = N_GNEW(sz, pointf); 00154 lp = list; 00155 olp = old->list + (sz - 1); 00156 for (i = 0; i < sz; i++) { /* reverse list of points */ 00157 *lp++ = *olp--; 00158 } 00159 00160 new->list = list; 00161 new->size = sz; 00162 new->sflag = old->eflag; 00163 new->eflag = old->sflag; 00164 new->sp = old->ep; 00165 new->ep = old->sp; 00166 } 00167 00168 /* swap_spline: 00169 */ 00170 static void swap_spline(splines * s) 00171 { 00172 bezier *list; 00173 bezier *lp; 00174 bezier *olp; 00175 int i, sz; 00176 00177 sz = s->size; 00178 list = N_GNEW(sz, bezier); 00179 lp = list; 00180 olp = s->list + (sz - 1); 00181 for (i = 0; i < sz; i++) { /* reverse and swap list of beziers */ 00182 swap_bezier(olp--, lp++); 00183 } 00184 00185 /* free old structures */ 00186 for (i = 0; i < sz; i++) 00187 free(s->list[i].list); 00188 free(s->list); 00189 00190 s->list = list; 00191 } 00192 00193 /* edge_normalize: 00194 * Some back edges are reversed during layout and the reversed edge 00195 * is used to compute the spline. We would like to guarantee that 00196 * the order of control points always goes from tail to head, so 00197 * we reverse them if necessary. 00198 */ 00199 static void edge_normalize(graph_t * g) 00200 { 00201 edge_t *e; 00202 node_t *n; 00203 00204 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00205 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00206 if (sinfo.swapEnds(e) && ED_spl(e)) 00207 swap_spline(ED_spl(e)); 00208 } 00209 } 00210 } 00211 00212 /* resetRW: 00213 * In position, each node has its rw stored in mval and, 00214 * if a node is part of a loop, rw may be increased to 00215 * reflect the loops and associated labels. We restore 00216 * the original value here. 00217 */ 00218 static void 00219 resetRW (graph_t * g) 00220 { 00221 node_t* n; 00222 00223 for (n = agfstnode(g); n; n = agnxtnode(g,n)) { 00224 if (ND_other(n).list) { 00225 double tmp = ND_rw(n); 00226 ND_rw(n) = ND_mval(n); 00227 ND_mval(n) = tmp; 00228 } 00229 } 00230 } 00231 00232 /* setEdgeLabelPos: 00233 * Set edge label position information for regular and non-adjacent flat edges. 00234 * Dot has allocated space and position for these labels. This info will be 00235 * used when routing orthogonal edges. 00236 */ 00237 static void 00238 setEdgeLabelPos (graph_t * g) 00239 { 00240 node_t* n; 00241 textlabel_t* l; 00242 00243 /* place regular edge labels */ 00244 for (n = GD_nlist(g); n; n = ND_next(n)) { 00245 if (ND_node_type(n) == VIRTUAL) { 00246 if (ND_alg(n)) { // label of non-adjacent flat edge 00247 edge_t* fe = (edge_t*)ND_alg(n); 00248 assert ((l = ED_label(fe))); 00249 l->pos = ND_coord(n); 00250 l->set = TRUE; 00251 } 00252 else if ((l = ND_label(n))) {// label of regular edge 00253 place_vnlabel(n); 00254 } 00255 if (l) updateBB(g, l); 00256 } 00257 } 00258 } 00259 00260 /* _dot_splines: 00261 * Main spline routing code. 00262 * The normalize parameter allows this function to be called by the 00263 * recursive call in make_flat_edge without normalization occurring, 00264 * so that the edge will only be normalized once in the top level call 00265 * of dot_splines. 00266 */ 00267 static void _dot_splines(graph_t * g, int normalize) 00268 { 00269 int i, j, k, n_nodes, n_edges, ind, cnt; 00270 node_t *n; 00271 #ifndef WITH_CGRAPH 00272 edge_t fwdedgea, fwdedgeb; 00273 #else 00274 Agedgeinfo_t fwdedgeai, fwdedgebi; 00275 Agedgepair_t fwdedgea, fwdedgeb; 00276 #endif 00277 edge_t *e, *e0, *e1, *ea, *eb, *le0, *le1, **edges; 00278 path *P; 00279 spline_info_t sd; 00280 int et = EDGE_TYPE(g); 00281 #ifdef WITH_CGRAPH 00282 fwdedgea.out.base.data = (Agrec_t*)&fwdedgeai; 00283 fwdedgeb.out.base.data = (Agrec_t*)&fwdedgebi; 00284 #endif /* WITH_CGRAPH */ 00285 00286 if (et == ET_NONE) return; 00287 #ifdef ORTHO 00288 if (et == ET_ORTHO) { 00289 resetRW (g); 00290 if (GD_has_labels(g) & EDGE_LABEL) { 00291 setEdgeLabelPos (g); 00292 orthoEdges (g, 1); 00293 } 00294 else 00295 orthoEdges (g, 0); 00296 goto finish; 00297 } 00298 #endif 00299 00300 mark_lowclusters(g); 00301 if (routesplinesinit()) return; 00302 P = NEW(path); 00303 /* FlatHeight = 2 * GD_nodesep(g); */ 00304 sd.Splinesep = GD_nodesep(g) / 4; 00305 sd.Multisep = GD_nodesep(g); 00306 edges = N_NEW(CHUNK, edge_t *); 00307 00308 /* compute boundaries and list of splines */ 00309 sd.LeftBound = sd.RightBound = 0; 00310 n_edges = n_nodes = 0; 00311 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { 00312 n_nodes += GD_rank(g)[i].n; 00313 if ((n = GD_rank(g)[i].v[0])) 00314 sd.LeftBound = MIN(sd.LeftBound, (ND_coord(n).x - ND_lw(n))); 00315 if (GD_rank(g)[i].n && (n = GD_rank(g)[i].v[GD_rank(g)[i].n - 1])) 00316 sd.RightBound = MAX(sd.RightBound, (ND_coord(n).x + ND_rw(n))); 00317 sd.LeftBound -= MINW; 00318 sd.RightBound += MINW; 00319 00320 for (j = 0; j < GD_rank(g)[i].n; j++) { 00321 n = GD_rank(g)[i].v[j]; 00322 /* if n is the label of a flat edge, copy its position to 00323 * the label. 00324 */ 00325 if (ND_alg(n)) { 00326 edge_t* fe = (edge_t*)ND_alg(n); 00327 assert (ED_label(fe)); 00328 ED_label(fe)->pos = ND_coord(n); 00329 ED_label(fe)->set = TRUE; 00330 } 00331 if ((ND_node_type(n) != NORMAL) && 00332 (sinfo.splineMerge(n) == FALSE)) 00333 continue; 00334 for (k = 0; (e = ND_out(n).list[k]); k++) { 00335 if ((ED_edge_type(e) == FLATORDER) 00336 || (ED_edge_type(e) == IGNORED)) 00337 continue; 00338 setflags(e, REGULAREDGE, FWDEDGE, MAINGRAPH); 00339 edges[n_edges++] = e; 00340 if (n_edges % CHUNK == 0) 00341 GROWEDGES; 00342 } 00343 if (ND_flat_out(n).list) 00344 for (k = 0; (e = ND_flat_out(n).list[k]); k++) { 00345 setflags(e, FLATEDGE, 0, AUXGRAPH); 00346 edges[n_edges++] = e; 00347 if (n_edges % CHUNK == 0) 00348 GROWEDGES; 00349 } 00350 if (ND_other(n).list) { 00351 /* In position, each node has its rw stored in mval and, 00352 * if a node is part of a loop, rw may be increased to 00353 * reflect the loops and associated labels. We restore 00354 * the original value here. 00355 */ 00356 if (ND_node_type(n) == NORMAL) { 00357 double tmp = ND_rw(n); 00358 ND_rw(n) = ND_mval(n); 00359 ND_mval(n) = tmp; 00360 } 00361 for (k = 0; (e = ND_other(n).list[k]); k++) { 00362 setflags(e, 0, 0, AUXGRAPH); 00363 edges[n_edges++] = e; 00364 if (n_edges % CHUNK == 0) 00365 GROWEDGES; 00366 } 00367 } 00368 } 00369 } 00370 00371 /* Sort so that equivalent edges are contiguous. 00372 * Equivalence should basically mean that 2 edges have the 00373 * same set {(tailnode,tailport),(headnode,headport)}, or 00374 * alternatively, the edges would be routed identically if 00375 * routed separately. 00376 */ 00377 qsort((char *) &edges[0], n_edges, sizeof(edges[0]), 00378 (qsort_cmpf) edgecmp); 00379 00380 /* FIXME: just how many boxes can there be? */ 00381 P->boxes = N_NEW(n_nodes + 20 * 2 * NSUB, boxf); 00382 sd.Rank_box = N_NEW(i, boxf); 00383 00384 if (et == ET_LINE) { 00385 /* place regular edge labels */ 00386 for (n = GD_nlist(g); n; n = ND_next(n)) { 00387 if ((ND_node_type(n) == VIRTUAL) && (ND_label(n))) { 00388 place_vnlabel(n); 00389 } 00390 } 00391 } 00392 00393 for (i = 0; i < n_edges;) { 00394 ind = i; 00395 le0 = getmainedge((e0 = edges[i++])); 00396 ea = (ED_tail_port(e0).defined 00397 || ED_head_port(e0).defined) ? e0 : le0; 00398 if (ED_tree_index(ea) & BWDEDGE) { 00399 #ifndef WITH_CGRAPH 00400 MAKEFWDEDGE(&fwdedgea, ea); 00401 ea = &fwdedgea; 00402 #else 00403 MAKEFWDEDGE(&fwdedgea.out, ea); 00404 ea = &fwdedgea.out; 00405 #endif 00406 } 00407 for (cnt = 1; i < n_edges; cnt++, i++) { 00408 if (le0 != (le1 = getmainedge((e1 = edges[i])))) 00409 break; 00410 if (ED_adjacent(e0)) continue; /* all flat adjacent edges at once */ 00411 eb = (ED_tail_port(e1).defined 00412 || ED_head_port(e1).defined) ? e1 : le1; 00413 if (ED_tree_index(eb) & BWDEDGE) { 00414 #ifndef WITH_CGRAPH 00415 MAKEFWDEDGE(&fwdedgeb, eb); 00416 eb = &fwdedgeb; 00417 #else 00418 MAKEFWDEDGE(&fwdedgeb.out, eb); 00419 eb = &fwdedgeb.out; 00420 #endif 00421 } 00422 if (portcmp(ED_tail_port(ea), ED_tail_port(eb))) 00423 break; 00424 if (portcmp(ED_head_port(ea), ED_head_port(eb))) 00425 break; 00426 if ((ED_tree_index(e0) & EDGETYPEMASK) == FLATEDGE 00427 && ED_label(e0) != ED_label(e1)) 00428 break; 00429 if (ED_tree_index(edges[i]) & MAINGRAPH) /* Aha! -C is on */ 00430 break; 00431 } 00432 00433 if (agtail(e0) == aghead(e0)) { 00434 int b, sizey, r; 00435 n = agtail(e0); 00436 r = ND_rank(n); 00437 if (r == GD_maxrank(g)) { 00438 if (r > 0) 00439 sizey = ND_coord(GD_rank(g)[r-1].v[0]).y - ND_coord(n).y; 00440 else 00441 sizey = ND_ht(n); 00442 } 00443 else if (r == GD_minrank(g)) { 00444 sizey = ND_coord(n).y - ND_coord(GD_rank(g)[r+1].v[0]).y; 00445 } 00446 else { 00447 int upy = ND_coord(GD_rank(g)[r-1].v[0]).y - ND_coord(n).y; 00448 int dwny = ND_coord(n).y - ND_coord(GD_rank(g)[r+1].v[0]).y; 00449 sizey = MIN(upy, dwny); 00450 } 00451 makeSelfEdge(P, edges, ind, cnt, sd.Multisep, sizey/2, &sinfo); 00452 for (b = 0; b < cnt; b++) { 00453 e = edges[ind+b]; 00454 if (ED_label(e)) 00455 updateBB(g, ED_label(e)); 00456 } 00457 } 00458 else if (ND_rank(agtail(e0)) == ND_rank(aghead(e0))) { 00459 make_flat_edge(&sd, P, edges, ind, cnt, et); 00460 } 00461 else 00462 make_regular_edge(&sd, P, edges, ind, cnt, et); 00463 } 00464 00465 /* place regular edge labels */ 00466 for (n = GD_nlist(g); n; n = ND_next(n)) { 00467 if ((ND_node_type(n) == VIRTUAL) && (ND_label(n))) { 00468 place_vnlabel(n); 00469 updateBB(g, ND_label(n)); 00470 } 00471 } 00472 00473 /* normalize splines so they always go from tail to head */ 00474 /* place_portlabel relies on this being done first */ 00475 if (normalize) 00476 edge_normalize(g); 00477 00478 #ifdef ORTHO 00479 finish : 00480 #endif 00481 /* vladimir: place port labels */ 00482 /* FIX: head and tail labels are not part of cluster bbox */ 00483 if ((E_headlabel || E_taillabel) && (E_labelangle || E_labeldistance)) { 00484 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00485 if (E_headlabel) { 00486 for (e = agfstin(g, n); e; e = agnxtin(g, e)) 00487 #ifndef WITH_CGRAPH 00488 if (ED_head_label(e)) { 00489 if (place_portlabel(e, TRUE)) 00490 updateBB(g, ED_head_label(e)); 00491 } 00492 #else 00493 if (ED_head_label(AGMKOUT(e))) { 00494 place_portlabel(AGMKOUT(e), TRUE); 00495 updateBB(g, ED_head_label(AGMKOUT(e))); 00496 } 00497 #endif 00498 00499 } 00500 if (E_taillabel) { 00501 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00502 if (ED_tail_label(e)) { 00503 if (place_portlabel(e, FALSE)) 00504 updateBB(g, ED_tail_label(e)); 00505 } 00506 } 00507 } 00508 } 00509 } 00510 /* end vladimir */ 00511 00512 #ifdef ORTHO 00513 if (et != ET_ORTHO) { 00514 #endif 00515 free(edges); 00516 free(P->boxes); 00517 free(P); 00518 free(sd.Rank_box); 00519 routesplinesterm(); 00520 #ifdef ORTHO 00521 } 00522 #endif 00523 State = GVSPLINES; 00524 EdgeLabelsDone = 1; 00525 } 00526 00527 /* dot_splines: 00528 * If the splines attribute is defined but equal to "", skip edge routing. 00529 */ 00530 void dot_splines(graph_t * g) 00531 { 00532 _dot_splines (g, 1); 00533 } 00534 00535 /* place_vnlabel: 00536 * assign position of an edge label from its virtual node 00537 * This is for regular edges only. 00538 */ 00539 static void 00540 place_vnlabel(node_t * n) 00541 { 00542 pointf dimen; 00543 double width; 00544 edge_t *e; 00545 if (ND_in(n).size == 0) 00546 return; /* skip flat edge labels here */ 00547 for (e = ND_out(n).list[0]; ED_edge_type(e) != NORMAL; 00548 e = ED_to_orig(e)); 00549 dimen = ED_label(e)->dimen; 00550 width = GD_flip(agraphof(n)) ? dimen.y : dimen.x; 00551 ED_label(e)->pos.x = ND_coord(n).x + width / 2.0; 00552 ED_label(e)->pos.y = ND_coord(n).y; 00553 ED_label(e)->set = TRUE; 00554 } 00555 00556 static void 00557 setflags(edge_t *e, int hint1, int hint2, int f3) 00558 { 00559 int f1, f2; 00560 if (hint1 != 0) 00561 f1 = hint1; 00562 else { 00563 if (agtail(e) == aghead(e)) 00564 if (ED_tail_port(e).defined || ED_head_port(e).defined) 00565 f1 = SELFWPEDGE; 00566 else 00567 f1 = SELFNPEDGE; 00568 else if (ND_rank(agtail(e)) == ND_rank(aghead(e))) 00569 f1 = FLATEDGE; 00570 else 00571 f1 = REGULAREDGE; 00572 } 00573 if (hint2 != 0) 00574 f2 = hint2; 00575 else { 00576 if (f1 == REGULAREDGE) 00577 f2 = (ND_rank(agtail(e)) < ND_rank(aghead(e))) ? FWDEDGE : BWDEDGE; 00578 else if (f1 == FLATEDGE) 00579 f2 = (ND_order(agtail(e)) < ND_order(aghead(e))) ? FWDEDGE : BWDEDGE; 00580 else /* f1 == SELF*EDGE */ 00581 f2 = FWDEDGE; 00582 } 00583 ED_tree_index(e) = (f1 | f2 | f3); 00584 } 00585 00586 /* edgecmp: 00587 * lexicographically order edges by 00588 * - edge type 00589 * - |rank difference of nodes| 00590 * - |x difference of nodes| 00591 * - id of witness edge for equivalence class 00592 * - port comparison 00593 * - graph type 00594 * - labels if flat edges 00595 * - edge id 00596 */ 00597 static int edgecmp(edge_t** ptr0, edge_t** ptr1) 00598 { 00599 #ifndef WITH_CGRAPH 00600 edge_t fwdedgea, fwdedgeb, *e0, *e1, *ea, *eb, *le0, *le1; 00601 #else 00602 Agedgeinfo_t fwdedgeai, fwdedgebi; 00603 Agedgepair_t fwdedgea, fwdedgeb; 00604 edge_t *e0, *e1, *ea, *eb, *le0, *le1; 00605 #endif 00606 int et0, et1, v0, v1, rv; 00607 double t0, t1; 00608 00609 #ifdef WITH_CGRAPH 00610 fwdedgea.out.base.data = (Agrec_t*)&fwdedgeai; 00611 fwdedgeb.out.base.data = (Agrec_t*)&fwdedgebi; 00612 #endif 00613 e0 = (edge_t *) * ptr0; 00614 e1 = (edge_t *) * ptr1; 00615 et0 = ED_tree_index(e0) & EDGETYPEMASK; 00616 et1 = ED_tree_index(e1) & EDGETYPEMASK; 00617 if (et0 != et1) 00618 return (et1 - et0); 00619 00620 le0 = getmainedge(e0); 00621 le1 = getmainedge(e1); 00622 00623 t0 = ND_rank(agtail(le0)) - ND_rank(aghead(le0)); 00624 t1 = ND_rank(agtail(le1)) - ND_rank(aghead(le1)); 00625 v0 = ABS((int)t0); /* ugly, but explicit as to how we avoid equality tests on fp numbers */ 00626 v1 = ABS((int)t1); 00627 if (v0 != v1) 00628 return (v0 - v1); 00629 00630 t0 = ND_coord(agtail(le0)).x - ND_coord(aghead(le0)).x; 00631 t1 = ND_coord(agtail(le1)).x - ND_coord(aghead(le1)).x; 00632 v0 = ABS((int)t0); 00633 v1 = ABS((int)t1); 00634 if (v0 != v1) 00635 return (v0 - v1); 00636 00637 /* This provides a cheap test for edges having the same set of endpoints. */ 00638 if (AGSEQ(le0) != AGSEQ(le1)) 00639 return (AGSEQ(le0) - AGSEQ(le1)); 00640 00641 ea = (ED_tail_port(e0).defined || ED_head_port(e0).defined) ? e0 : le0; 00642 if (ED_tree_index(ea) & BWDEDGE) { 00643 #ifndef WITH_CGRAPH 00644 MAKEFWDEDGE(&fwdedgea, ea); 00645 ea = &fwdedgea; 00646 #else 00647 MAKEFWDEDGE(&fwdedgea.out, ea); 00648 ea = &fwdedgea.out; 00649 #endif 00650 } 00651 eb = (ED_tail_port(e1).defined || ED_head_port(e1).defined) ? e1 : le1; 00652 if (ED_tree_index(eb) & BWDEDGE) { 00653 #ifndef WITH_CGRAPH 00654 MAKEFWDEDGE(&fwdedgeb, eb); 00655 eb = &fwdedgeb; 00656 #else 00657 MAKEFWDEDGE(&fwdedgeb.out, eb); 00658 eb = &fwdedgeb.out; 00659 #endif 00660 } 00661 if ((rv = portcmp(ED_tail_port(ea), ED_tail_port(eb)))) 00662 return rv; 00663 if ((rv = portcmp(ED_head_port(ea), ED_head_port(eb)))) 00664 return rv; 00665 00666 et0 = ED_tree_index(e0) & GRAPHTYPEMASK; 00667 et1 = ED_tree_index(e1) & GRAPHTYPEMASK; 00668 if (et0 != et1) 00669 return (et0 - et1); 00670 00671 if (et0 == FLATEDGE && ED_label(e0) != ED_label(e1)) 00672 return (int) (ED_label(e0) - ED_label(e1)); 00673 00674 return (AGSEQ(e0) - AGSEQ(e1)); 00675 } 00676 00677 /* cloneGraph: 00678 */ 00679 static struct { 00680 attrsym_t* E_constr; 00681 attrsym_t* E_samehead; 00682 attrsym_t* E_sametail; 00683 attrsym_t* E_weight; 00684 attrsym_t* E_minlen; 00685 attrsym_t* N_group; 00686 int State; 00687 } attr_state; 00688 00689 /* cloneGraph: 00690 * Create clone graph. It stores the global Agsyms, to be 00691 * restored in cleanupCloneGraph. The graph uses the main 00692 * graph's settings for certain geometry parameters, and 00693 * declares all node and edge attributes used in the original 00694 * graph. 00695 */ 00696 static graph_t* 00697 cloneGraph (graph_t* g) 00698 { 00699 Agsym_t* sym; 00700 graph_t* auxg; 00701 #ifndef WITH_CGRAPH 00702 Agsym_t **list; 00703 00704 auxg = agopen ("auxg", AG_IS_DIRECTED(g)?AGDIGRAPH:AGRAPH); 00705 agraphattr(auxg, "rank", ""); 00706 #else /* WITH_CGRAPH */ 00707 if (agisdirected(g)) 00708 auxg = agopen ("auxg",Agdirected, NIL(Agdisc_t *)); 00709 else 00710 auxg = agopen ("auxg",Agundirected, NIL(Agdisc_t *)); 00711 agbindrec(auxg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); 00712 agattr(auxg, AGRAPH, "rank", ""); 00713 #endif /* WITH_CGRAPH */ 00714 GD_drawing(auxg) = NEW(layout_t); 00715 GD_drawing(auxg)->quantum = GD_drawing(g)->quantum; 00716 GD_drawing(auxg)->dpi = GD_drawing(g)->dpi; 00717 00718 GD_charset(auxg) = GD_charset (g); 00719 if (GD_flip(g)) 00720 SET_RANKDIR(auxg, RANKDIR_TB); 00721 else 00722 SET_RANKDIR(auxg, RANKDIR_LR); 00723 GD_nodesep(auxg) = GD_nodesep(g); 00724 GD_ranksep(auxg) = GD_ranksep(g); 00725 00726 #ifndef WITH_CGRAPH 00727 list = g->root->univ->nodeattr->list; 00728 while ((sym = *list++)) { 00729 agnodeattr (auxg, sym->name, sym->value); 00730 #else /* WITH_CGRAPH */ 00731 //copy node attrs to auxg 00732 // list = g->root->univ->nodeattr->list; 00733 sym=agnxtattr(agroot(g),AGNODE,NULL); //get the first attr. 00734 while ((sym = agnxtattr(agroot(g),AGNODE,sym))) { 00735 agattr (auxg, AGNODE,sym->name, sym->defval ); 00736 #endif /* WITH_CGRAPH */ 00737 } 00738 00739 #ifndef WITH_CGRAPH 00740 list = g->root->univ->edgeattr->list; 00741 while ((sym = *list++)) { 00742 agedgeattr (auxg, sym->name, sym->value); 00743 #else /* WITH_CGRAPH */ 00744 //copy edge attributes 00745 sym=agnxtattr(agroot(g),AGEDGE,NULL); //get the first attr. 00746 while ((sym = agnxtattr(agroot(g),AGEDGE,sym))) { 00747 agattr (auxg, AGEDGE,sym->name, sym->defval); 00748 #endif /* WITH_CGRAPH */ 00749 } 00750 00751 #ifndef WITH_CGRAPH 00752 if (!agfindattr(auxg->proto->e, "headport")) 00753 agedgeattr (auxg, "headport", ""); 00754 if (!agfindattr(auxg->proto->e, "tailport")) 00755 agedgeattr (auxg, "tailport", ""); 00756 #else /* WITH_CGRAPH */ 00757 if (!agattr(auxg,AGEDGE, "headport", NULL)) 00758 agattr(auxg,AGEDGE, "headport", ""); 00759 if (!agattr(auxg,AGEDGE, "tailport", NULL)) 00760 agattr(auxg,AGEDGE, "tailport", ""); 00761 #endif /* WITH_CGRAPH */ 00762 00763 attr_state.E_constr = E_constr; 00764 attr_state.E_samehead = E_samehead; 00765 attr_state.E_sametail = E_sametail; 00766 attr_state.E_weight = E_weight; 00767 attr_state.E_minlen = E_minlen; 00768 attr_state.N_group = N_group; 00769 attr_state.State = State; 00770 E_constr = NULL; 00771 #ifndef WITH_CGRAPH 00772 E_samehead = agfindattr(auxg->proto->e, "samehead"); 00773 E_sametail = agfindattr(auxg->proto->e, "sametail"); 00774 E_weight = agfindattr(auxg->proto->e, "weight"); 00775 #else /* WITH_CGRAPH */ 00776 E_samehead = agattr(auxg,AGEDGE, "samehead", NULL); 00777 E_sametail = agattr(auxg,AGEDGE, "sametail", NULL); 00778 E_weight = agattr(auxg,AGEDGE, "weight", NULL); 00779 #endif /* WITH_CGRAPH */ 00780 if (!E_weight) 00781 #ifndef WITH_CGRAPH 00782 E_weight = agedgeattr (auxg, "weight", ""); 00783 #else /* WITH_CGRAPH */ 00784 E_weight = agattr (auxg,AGEDGE,"weight", ""); 00785 #endif /* WITH_CGRAPH */ 00786 E_minlen = NULL; 00787 N_group = NULL; 00788 00789 return auxg; 00790 } 00791 00792 /* cleanupCloneGraph: 00793 */ 00794 static void 00795 cleanupCloneGraph (graph_t* g) 00796 { 00797 /* restore main graph syms */ 00798 E_constr = attr_state.E_constr; 00799 E_samehead = attr_state.E_samehead; 00800 E_sametail = attr_state.E_sametail; 00801 E_weight = attr_state.E_weight; 00802 E_minlen = attr_state.E_minlen; 00803 N_group = attr_state.N_group; 00804 State = attr_state.State; 00805 00806 dot_cleanup(g); 00807 agclose(g); 00808 } 00809 00810 /* cloneNode: 00811 * If flipped is true, original graph has rankdir=LR or RL. 00812 * In this case, records change shape, so we wrap a record node's 00813 * label in "{...}" to prevent this. 00814 */ 00815 static node_t* 00816 cloneNode (graph_t* g, node_t* orign, int flipped) 00817 { 00818 #ifndef WITH_CGRAPH 00819 node_t* n = agnode(g, orign->name); 00820 #else /* WITH_CGRAPH */ 00821 node_t* n = agnode(g, agnameof(orign),1); 00822 agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); 00823 #endif /* WITH_CGRAPH */ 00824 agcopyattr (orign, n); 00825 if (shapeOf(orign) == SH_RECORD) { 00826 int lbllen = strlen(ND_label(orign)->text); 00827 char* buf = N_GNEW(lbllen+3,char); 00828 sprintf (buf, "{%s}", ND_label(orign)->text); 00829 agset (n, "label", buf); 00830 } 00831 00832 return n; 00833 } 00834 00835 /* cloneEdge: 00836 */ 00837 static edge_t* 00838 cloneEdge (graph_t* g, node_t* tn, node_t* hn, edge_t* orig) 00839 { 00840 #ifndef WITH_CGRAPH 00841 edge_t* e = agedge(g, tn, hn); 00842 #else /* WITH_CGRAPH */ 00843 edge_t* e = agedge(g, tn, hn,NULL,1); 00844 #endif /* WITH_CGRAPH */ 00845 /* for (; ED_edge_type(orig) != NORMAL; orig = ED_to_orig(orig)); */ 00846 agcopyattr (orig, e); 00847 /* 00848 if (orig->tail != ND_alg(tn)) { 00849 char* hdport = agget (orig, HEAD_ID); 00850 char* tlport = agget (orig, TAIL_ID); 00851 agset (e, TAIL_ID, (hdport ? hdport : "")); 00852 agset (e, HEAD_ID, (tlport ? tlport : "")); 00853 } 00854 */ 00855 00856 return e; 00857 } 00858 00859 /* transformf: 00860 * Rotate, if necessary, then translate points. 00861 */ 00862 static pointf 00863 transformf (pointf p, pointf del, int flip) 00864 { 00865 if (flip) { 00866 double i = p.x; 00867 p.x = p.y; 00868 p.y = -i; 00869 } 00870 return add_pointf(p, del); 00871 } 00872 00873 /* edgelblcmpfn: 00874 * lexicographically order edges by 00875 * - has label 00876 * - label is wider 00877 * - label is higher 00878 */ 00879 static int edgelblcmpfn(edge_t** ptr0, edge_t** ptr1) 00880 { 00881 edge_t *e0, *e1; 00882 pointf sz0, sz1; 00883 00884 e0 = (edge_t *) * ptr0; 00885 e1 = (edge_t *) * ptr1; 00886 00887 if (ED_label(e0)) { 00888 if (ED_label(e1)) { 00889 sz0 = ED_label(e0)->dimen; 00890 sz1 = ED_label(e1)->dimen; 00891 if (sz0.x > sz1.x) return -1; 00892 else if (sz0.x < sz1.x) return 1; 00893 else if (sz0.y > sz1.y) return -1; 00894 else if (sz0.y < sz1.y) return 1; 00895 else return 0; 00896 } 00897 else 00898 return -1; 00899 } 00900 else if (ED_label(e1)) { 00901 return 1; 00902 } 00903 else 00904 return 0; 00905 } 00906 00907 #define LBL_SPACE 6 /* space between labels, in points */ 00908 00909 /* makeSimpleFlatLabels: 00910 * This handles the second simplest case for flat edges between 00911 * two adjacent nodes. We still invoke a dot on a rotated problem 00912 * to handle edges with ports. This usually works, but fails for 00913 * records because of their weird nature. 00914 */ 00915 static void 00916 makeSimpleFlatLabels (node_t* tn, node_t* hn, edge_t** edges, int ind, int cnt, int et, int n_lbls) 00917 { 00918 pointf *ps; 00919 Ppoly_t poly; 00920 int pn; 00921 edge_t* e = edges[ind]; 00922 pointf points[10], tp, hp; 00923 int i, pointn; 00924 double leftend, rightend, ctrx, ctry, miny, maxy; 00925 double uminx, umaxx; 00926 double lminx, lmaxx; 00927 00928 edge_t** earray = N_NEW(cnt, edge_t*); 00929 00930 for (i = 0; i < cnt; i++) { 00931 earray[i] = edges[ind + i]; 00932 } 00933 00934 qsort (earray, cnt, sizeof(edge_t*), (qsort_cmpf) edgelblcmpfn); 00935 00936 tp = add_pointf(ND_coord(tn), ED_tail_port(e).p); 00937 hp = add_pointf(ND_coord(hn), ED_head_port(e).p); 00938 00939 leftend = tp.x+ND_rw(tn); 00940 rightend = hp.x-ND_lw(hn); 00941 ctrx = (leftend + rightend)/2.0; 00942 00943 /* do first edge */ 00944 e = earray[0]; 00945 pointn = 0; 00946 points[pointn++] = tp; 00947 points[pointn++] = tp; 00948 points[pointn++] = hp; 00949 points[pointn++] = hp; 00950 #ifndef WITH_CGRAPH 00951 clip_and_install(e, e->head, points, pointn, &sinfo); 00952 #else /* WITH_CGRAPH */ 00953 clip_and_install(e, aghead(e), points, pointn, &sinfo); 00954 #endif /* WITH_CGRAPH */ 00955 ED_label(e)->pos.x = ctrx; 00956 ED_label(e)->pos.y = tp.y + (ED_label(e)->dimen.y+LBL_SPACE)/2.0; 00957 ED_label(e)->set = TRUE; 00958 00959 miny = tp.y + LBL_SPACE/2.0; 00960 maxy = miny + ED_label(e)->dimen.y; 00961 uminx = ctrx - (ED_label(e)->dimen.x)/2.0; 00962 umaxx = ctrx + (ED_label(e)->dimen.x)/2.0; 00963 00964 for (i = 1; i < n_lbls; i++) { 00965 e = earray[i]; 00966 if (i%2) { /* down */ 00967 if (i == 1) { 00968 lminx = ctrx - (ED_label(e)->dimen.x)/2.0; 00969 lmaxx = ctrx + (ED_label(e)->dimen.x)/2.0; 00970 } 00971 miny -= LBL_SPACE + ED_label(e)->dimen.y; 00972 points[0] = tp; 00973 points[1].x = tp.x; 00974 points[1].y = miny - LBL_SPACE; 00975 points[2].x = hp.x; 00976 points[2].y = points[1].y; 00977 points[3] = hp; 00978 points[4].x = lmaxx; 00979 points[4].y = hp.y; 00980 points[5].x = lmaxx; 00981 points[5].y = miny; 00982 points[6].x = lminx; 00983 points[6].y = miny; 00984 points[7].x = lminx; 00985 points[7].y = tp.y; 00986 ctry = miny + (ED_label(e)->dimen.y)/2.0; 00987 } 00988 else { /* up */ 00989 points[0] = tp; 00990 points[1].x = uminx; 00991 points[1].y = tp.y; 00992 points[2].x = uminx; 00993 points[2].y = maxy; 00994 points[3].x = umaxx; 00995 points[3].y = maxy; 00996 points[4].x = umaxx; 00997 points[4].y = hp.y; 00998 points[5].x = hp.x; 00999 points[5].y = hp.y; 01000 points[6].x = hp.x; 01001 points[6].y = maxy + LBL_SPACE; 01002 points[7].x = tp.x; 01003 points[7].y = maxy + LBL_SPACE; 01004 ctry = maxy + (ED_label(e)->dimen.y)/2.0 + LBL_SPACE; 01005 maxy += ED_label(e)->dimen.y + LBL_SPACE; 01006 } 01007 poly.pn = 8; 01008 poly.ps = (Ppoint_t*)points; 01009 ps = simpleSplineRoute (tp, hp, poly, &pn, et == ET_PLINE); 01010 if (pn == 0) return; 01011 ED_label(e)->pos.x = ctrx; 01012 ED_label(e)->pos.y = ctry; 01013 ED_label(e)->set = TRUE; 01014 #ifndef WITH_CGRAPH 01015 clip_and_install(e, e->head, ps, pn, &sinfo); 01016 #else /* WITH_CGRAPH */ 01017 clip_and_install(e, aghead(e), ps, pn, &sinfo); 01018 #endif /* WITH_CGRAPH */ 01019 } 01020 01021 /* edges with no labels */ 01022 for (; i < cnt; i++) { 01023 e = earray[i]; 01024 if (i%2) { /* down */ 01025 if (i == 1) { 01026 lminx = (2*leftend + rightend)/3.0; 01027 lmaxx = (leftend + 2*rightend)/3.0; 01028 } 01029 miny -= LBL_SPACE; 01030 points[0] = tp; 01031 points[1].x = tp.x; 01032 points[1].y = miny - LBL_SPACE; 01033 points[2].x = hp.x; 01034 points[2].y = points[1].y; 01035 points[3] = hp; 01036 points[4].x = lmaxx; 01037 points[4].y = hp.y; 01038 points[5].x = lmaxx; 01039 points[5].y = miny; 01040 points[6].x = lminx; 01041 points[6].y = miny; 01042 points[7].x = lminx; 01043 points[7].y = tp.y; 01044 } 01045 else { /* up */ 01046 points[0] = tp; 01047 points[1].x = uminx; 01048 points[1].y = tp.y; 01049 points[2].x = uminx; 01050 points[2].y = maxy; 01051 points[3].x = umaxx; 01052 points[3].y = maxy; 01053 points[4].x = umaxx; 01054 points[4].y = hp.y; 01055 points[5].x = hp.x; 01056 points[5].y = hp.y; 01057 points[6].x = hp.x; 01058 points[6].y = maxy + LBL_SPACE; 01059 points[7].x = tp.x; 01060 points[7].y = maxy + LBL_SPACE; 01061 maxy += + LBL_SPACE; 01062 } 01063 poly.pn = 8; 01064 poly.ps = (Ppoint_t*)points; 01065 ps = simpleSplineRoute (tp, hp, poly, &pn, et == ET_PLINE); 01066 if (pn == 0) return; 01067 #ifndef WITH_CGRAPH 01068 clip_and_install(e, e->head, ps, pn, &sinfo); 01069 #else /* WITH_CGRAPH */ 01070 clip_and_install(e, aghead(e), ps, pn, &sinfo); 01071 #endif /* WITH_CGRAPH */ 01072 } 01073 01074 free (earray); 01075 } 01076 01077 /* makeSimpleFlat: 01078 */ 01079 static void 01080 makeSimpleFlat (node_t* tn, node_t* hn, edge_t** edges, int ind, int cnt, int et) 01081 { 01082 edge_t* e = edges[ind]; 01083 pointf points[10], tp, hp; 01084 int i, pointn; 01085 double stepy, dy; 01086 01087 tp = add_pointf(ND_coord(tn), ED_tail_port(e).p); 01088 hp = add_pointf(ND_coord(hn), ED_head_port(e).p); 01089 01090 stepy = (cnt > 1) ? ND_ht(tn) / (double)(cnt - 1) : 0.; 01091 dy = tp.y - ((cnt > 1) ? ND_ht(tn) / 2. : 0.); 01092 01093 for (i = 0; i < cnt; i++) { 01094 e = edges[ind + i]; 01095 pointn = 0; 01096 if ((et == ET_SPLINE) || (et == ET_LINE)) { 01097 points[pointn++] = tp; 01098 points[pointn++] = pointfof((2 * tp.x + hp.x) / 3, dy); 01099 points[pointn++] = pointfof((2 * hp.x + tp.x) / 3, dy); 01100 points[pointn++] = hp; 01101 } 01102 else { /* ET_PLINE */ 01103 points[pointn++] = tp; 01104 points[pointn++] = tp; 01105 points[pointn++] = pointfof((2 * tp.x + hp.x) / 3, dy); 01106 points[pointn++] = pointfof((2 * tp.x + hp.x) / 3, dy); 01107 points[pointn++] = pointfof((2 * tp.x + hp.x) / 3, dy); 01108 points[pointn++] = pointfof((2 * hp.x + tp.x) / 3, dy); 01109 points[pointn++] = pointfof((2 * hp.x + tp.x) / 3, dy); 01110 points[pointn++] = pointfof((2 * hp.x + tp.x) / 3, dy); 01111 points[pointn++] = hp; 01112 points[pointn++] = hp; 01113 } 01114 dy += stepy; 01115 #ifndef WITH_CGRAPH 01116 clip_and_install(e, e->head, points, pointn, &sinfo); 01117 #else /* WITH_CGRAPH */ 01118 clip_and_install(e, aghead(e), points, pointn, &sinfo); 01119 #endif /* WITH_CGRAPH */ 01120 } 01121 } 01122 01123 /* make_flat_adj_edges: 01124 * In the simple case, with no labels or ports, this creates a simple 01125 * spindle of splines. 01126 * If there are only labels, cobble something together. 01127 * Otherwise, we run dot recursively on the 2 nodes and the edges, 01128 * essentially using rankdir=LR, to get the needed spline info. 01129 */ 01130 static void 01131 make_flat_adj_edges(path* P, edge_t** edges, int ind, int cnt, edge_t* e0, 01132 int et) 01133 { 01134 node_t* n; 01135 node_t *tn, *hn; 01136 edge_t* e; 01137 int labels = 0, ports = 0; 01138 graph_t* g; 01139 graph_t* auxg; 01140 graph_t* subg; 01141 node_t *auxt, *auxh; 01142 edge_t* auxe; 01143 int i, j, midx, midy, leftx, rightx; 01144 pointf del; 01145 edge_t* hvye = NULL; 01146 01147 g = agraphof(agtail(e0)); 01148 tn = agtail(e0), hn = aghead(e0); 01149 for (i = 0; i < cnt; i++) { 01150 e = edges[ind + i]; 01151 if (ND_label(e)) labels++; 01152 if (ED_tail_port(e).defined || ED_head_port(e).defined) ports = 1; 01153 } 01154 01155 if (ports == 0) { 01156 /* flat edges without ports and labels can go straight left to right */ 01157 if (labels == 0) { 01158 makeSimpleFlat (tn, hn, edges, ind, cnt, et); 01159 } 01160 /* flat edges without ports but with labels take more work */ 01161 else { 01162 makeSimpleFlatLabels (tn, hn, edges, ind, cnt, et, labels); 01163 } 01164 return; 01165 } 01166 01167 auxg = cloneGraph (g); 01168 #ifndef WITH_CGRAPH 01169 subg = agsubg (auxg, "xxx"); 01170 #else /* WITH_CGRAPH */ 01171 subg = agsubg (auxg, "xxx",1); 01172 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); 01173 #endif /* WITH_CGRAPH */ 01174 agset (subg, "rank", "source"); 01175 rightx = ND_coord(hn).x; 01176 leftx = ND_coord(tn).x; 01177 if (GD_flip(g)) { 01178 node_t* n; 01179 n = tn; 01180 tn = hn; 01181 hn = n; 01182 } 01183 auxt = cloneNode(subg, tn, GD_flip(g)); 01184 auxh = cloneNode(auxg, hn, GD_flip(g)); 01185 for (i = 0; i < cnt; i++) { 01186 e = edges[ind + i]; 01187 for (; ED_edge_type(e) != NORMAL; e = ED_to_orig(e)); 01188 if (agtail(e) == tn) 01189 auxe = cloneEdge (auxg, auxt, auxh, e); 01190 else 01191 auxe = cloneEdge (auxg, auxh, auxt, e); 01192 ED_alg(e) = auxe; 01193 if (!hvye && !ED_tail_port(e).defined && !ED_head_port(e).defined) { 01194 hvye = auxe; 01195 ED_alg(hvye) = e; 01196 } 01197 } 01198 if (!hvye) { 01199 #ifndef WITH_CGRAPH 01200 hvye = agedge (auxg, auxt, auxh); 01201 #else /* WITH_CGRAPH */ 01202 hvye = agedge (auxg, auxt, auxh,NULL,1); 01203 #endif /* WITH_CGRAPH */ 01204 } 01205 #ifndef WITH_CGRAPH 01206 agxset (hvye, E_weight->index, "10000"); 01207 #else /* WITH_CGRAPH */ 01208 agxset (hvye, E_weight, "10000"); 01209 #endif /* WITH_CGRAPH */ 01210 GD_gvc(auxg) = GD_gvc(g); 01211 setEdgeType (auxg, et); 01212 dot_init_node_edge(auxg); 01213 01214 dot_rank(auxg, 0); 01215 dot_mincross(auxg, 0); 01216 dot_position(auxg, 0); 01217 01218 /* reposition */ 01219 midx = (ND_coord(tn).x - ND_rw(tn) + ND_coord(hn).x + ND_lw(hn))/2; 01220 midy = (ND_coord(auxt).x + ND_coord(auxh).x)/2; 01221 for (n = GD_nlist(auxg); n; n = ND_next(n)) { 01222 if (n == auxt) { 01223 ND_coord(n).y = rightx; 01224 ND_coord(n).x = midy; 01225 } 01226 else if (n == auxh) { 01227 ND_coord(n).y = leftx; 01228 ND_coord(n).x = midy; 01229 } 01230 else ND_coord(n).y = midx; 01231 } 01232 dot_sameports(auxg); 01233 _dot_splines(auxg, 0); 01234 dotneato_postprocess(auxg); 01235 01236 /* copy splines */ 01237 if (GD_flip(g)) { 01238 del.x = ND_coord(tn).x - ND_coord(auxt).y; 01239 del.y = ND_coord(tn).y + ND_coord(auxt).x; 01240 } 01241 else { 01242 del.x = ND_coord(tn).x - ND_coord(auxt).x; 01243 del.y = ND_coord(tn).y - ND_coord(auxt).y; 01244 } 01245 for (i = 0; i < cnt; i++) { 01246 bezier* auxbz; 01247 bezier* bz; 01248 01249 e = edges[ind + i]; 01250 for (; ED_edge_type(e) != NORMAL; e = ED_to_orig(e)); 01251 auxe = (edge_t*)ED_alg(e); 01252 if ((auxe == hvye) & !ED_alg(auxe)) continue; /* pseudo-edge */ 01253 auxbz = ED_spl(auxe)->list; 01254 bz = new_spline(e, auxbz->size); 01255 bz->sflag = auxbz->sflag; 01256 bz->sp = transformf(auxbz->sp, del, GD_flip(g)); 01257 bz->eflag = auxbz->eflag; 01258 bz->ep = transformf(auxbz->ep, del, GD_flip(g)); 01259 for (j = 0; j < auxbz->size; ) { 01260 pointf cp[4]; 01261 cp[0] = bz->list[j] = transformf(auxbz->list[j], del, GD_flip(g)); 01262 j++; 01263 if ( j >= auxbz->size ) 01264 break; 01265 cp[1] = bz->list[j] = transformf(auxbz->list[j], del, GD_flip(g)); 01266 j++; 01267 cp[2] = bz->list[j] = transformf(auxbz->list[j], del, GD_flip(g)); 01268 j++; 01269 cp[3] = transformf(auxbz->list[j], del, GD_flip(g)); 01270 update_bb_bz(&GD_bb(g), cp); 01271 } 01272 if (ED_label(e)) { 01273 ED_label(e)->pos = transformf(ED_label(auxe)->pos, del, GD_flip(g)); 01274 ED_label(e)->set = TRUE; 01275 updateBB(g, ED_label(e)); 01276 } 01277 } 01278 01279 cleanupCloneGraph (auxg); 01280 } 01281 01282 /* makeFlatEnd; 01283 */ 01284 static void 01285 makeFlatEnd (spline_info_t* sp, path* P, node_t* n, edge_t* e, pathend_t* endp, 01286 boolean isBegin) 01287 { 01288 boxf b; 01289 graph_t* g = agraphof(n); 01290 01291 b = endp->nb = maximal_bbox(sp, n, NULL, e); 01292 endp->sidemask = TOP; 01293 if (isBegin) beginpath(P, e, FLATEDGE, endp, FALSE); 01294 else endpath(P, e, FLATEDGE, endp, FALSE); 01295 b.UR.y = endp->boxes[endp->boxn - 1].UR.y; 01296 b.LL.y = endp->boxes[endp->boxn - 1].LL.y; 01297 b = makeregularend(b, TOP, ND_coord(n).y + GD_rank(g)[ND_rank(n)].ht2); 01298 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y) 01299 endp->boxes[endp->boxn++] = b; 01300 } 01301 /* makeBottomFlatEnd; 01302 */ 01303 static void 01304 makeBottomFlatEnd (spline_info_t* sp, path* P, node_t* n, edge_t* e, 01305 pathend_t* endp, boolean isBegin) 01306 { 01307 boxf b; 01308 graph_t* g = agraphof(n); 01309 01310 b = endp->nb = maximal_bbox(sp, n, NULL, e); 01311 endp->sidemask = BOTTOM; 01312 if (isBegin) beginpath(P, e, FLATEDGE, endp, FALSE); 01313 else endpath(P, e, FLATEDGE, endp, FALSE); 01314 b.UR.y = endp->boxes[endp->boxn - 1].UR.y; 01315 b.LL.y = endp->boxes[endp->boxn - 1].LL.y; 01316 b = makeregularend(b, BOTTOM, ND_coord(n).y - GD_rank(g)[ND_rank(n)].ht2); 01317 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y) 01318 endp->boxes[endp->boxn++] = b; 01319 } 01320 01321 01322 /* make_flat_labeled_edge: 01323 */ 01324 static void 01325 make_flat_labeled_edge(spline_info_t* sp, path* P, edge_t* e, int et) 01326 { 01327 graph_t *g; 01328 node_t *tn, *hn, *ln; 01329 pointf *ps; 01330 pathend_t tend, hend; 01331 boxf lb; 01332 int boxn, i, pn, ydelta; 01333 edge_t *f; 01334 pointf points[7]; 01335 01336 tn = agtail(e); 01337 hn = aghead(e); 01338 g = agraphof(tn); 01339 01340 for (f = ED_to_virt(e); ED_to_virt(f); f = ED_to_virt(f)); 01341 ln = agtail(f); 01342 ED_label(e)->pos = ND_coord(ln); 01343 ED_label(e)->set = TRUE; 01344 01345 if (et == ET_LINE) { 01346 pointf startp, endp, lp; 01347 01348 startp = add_pointf(ND_coord(tn), ED_tail_port(e).p); 01349 endp = add_pointf(ND_coord(hn), ED_head_port(e).p); 01350 01351 lp = ED_label(e)->pos; 01352 lp.y -= (ED_label(e)->dimen.y)/2.0; 01353 points[1] = points[0] = startp; 01354 points[2] = points[3] = points[4] = lp; 01355 points[5] = points[6] = endp; 01356 ps = points; 01357 pn = 7; 01358 } 01359 else { 01360 lb.LL.x = ND_coord(ln).x - ND_lw(ln); 01361 lb.UR.x = ND_coord(ln).x + ND_rw(ln); 01362 lb.UR.y = ND_coord(ln).y + ND_ht(ln)/2; 01363 ydelta = ND_coord(ln).y - GD_rank(g)[ND_rank(tn)].ht1 - 01364 ND_coord(tn).y + GD_rank(g)[ND_rank(tn)].ht2; 01365 ydelta /= 6.; 01366 lb.LL.y = lb.UR.y - MAX(5.,ydelta); 01367 01368 boxn = 0; 01369 makeFlatEnd (sp, P, tn, e, &tend, TRUE); 01370 makeFlatEnd (sp, P, hn, e, &hend, FALSE); 01371 01372 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x; 01373 boxes[boxn].LL.y = tend.boxes[tend.boxn - 1].UR.y; 01374 boxes[boxn].UR.x = lb.LL.x; 01375 boxes[boxn].UR.y = lb.LL.y; 01376 boxn++; 01377 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x; 01378 boxes[boxn].LL.y = lb.LL.y; 01379 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x; 01380 boxes[boxn].UR.y = lb.UR.y; 01381 boxn++; 01382 boxes[boxn].LL.x = lb.UR.x; 01383 boxes[boxn].UR.y = lb.LL.y; 01384 boxes[boxn].LL.y = hend.boxes[hend.boxn - 1].UR.y; 01385 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x; 01386 boxn++; 01387 01388 for (i = 0; i < tend.boxn; i++) add_box(P, tend.boxes[i]); 01389 for (i = 0; i < boxn; i++) add_box(P, boxes[i]); 01390 for (i = hend.boxn - 1; i >= 0; i--) add_box(P, hend.boxes[i]); 01391 01392 if (et == ET_SPLINE) ps = routesplines(P, &pn); 01393 else ps = routepolylines(P, &pn); 01394 if (pn == 0) return; 01395 } 01396 #ifndef WITH_CGRAPH 01397 clip_and_install(e, e->head, ps, pn, &sinfo); 01398 #else /* WITH_CGRAPH */ 01399 clip_and_install(e, aghead(e), ps, pn, &sinfo); 01400 #endif /* WITH_CGRAPH */ 01401 } 01402 01403 /* make_flat_bottom_edges: 01404 */ 01405 static void 01406 make_flat_bottom_edges(spline_info_t* sp, path * P, edge_t ** edges, int 01407 ind, int cnt, edge_t* e, int splines) 01408 { 01409 node_t *tn, *hn; 01410 int j, i, r; 01411 double stepx, stepy, vspace; 01412 rank_t* nextr; 01413 int pn; 01414 pointf *ps; 01415 pathend_t tend, hend; 01416 graph_t* g; 01417 01418 tn = agtail(e); 01419 hn = aghead(e); 01420 g = agraphof(tn); 01421 r = ND_rank(tn); 01422 if (r < GD_maxrank(g)) { 01423 nextr = GD_rank(g) + (r+1); 01424 vspace = ND_coord(tn).y - GD_rank(g)[r].pht1 - 01425 (ND_coord(nextr->v[0]).y + nextr->pht2); 01426 } 01427 else { 01428 vspace = GD_ranksep(g); 01429 } 01430 stepx = ((double)(sp->Multisep)) / (cnt+1); 01431 stepy = vspace / (cnt+1); 01432 01433 makeBottomFlatEnd (sp, P, tn, e, &tend, TRUE); 01434 makeBottomFlatEnd (sp, P, hn, e, &hend, FALSE); 01435 01436 for (i = 0; i < cnt; i++) { 01437 int boxn; 01438 boxf b; 01439 e = edges[ind + i]; 01440 boxn = 0; 01441 01442 b = tend.boxes[tend.boxn - 1]; 01443 boxes[boxn].LL.x = b.LL.x; 01444 boxes[boxn].UR.y = b.LL.y; 01445 boxes[boxn].UR.x = b.UR.x + (i + 1) * stepx; 01446 boxes[boxn].LL.y = b.LL.y - (i + 1) * stepy; 01447 boxn++; 01448 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x; 01449 boxes[boxn].UR.y = boxes[boxn-1].LL.y; 01450 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x; 01451 boxes[boxn].LL.y = boxes[boxn].UR.y - stepy; 01452 boxn++; 01453 b = hend.boxes[hend.boxn - 1]; 01454 boxes[boxn].UR.x = b.UR.x; 01455 boxes[boxn].UR.y = b.LL.y; 01456 boxes[boxn].LL.x = b.LL.x - (i + 1) * stepx; 01457 boxes[boxn].LL.y = boxes[boxn-1].UR.y; 01458 boxn++; 01459 01460 for (j = 0; j < tend.boxn; j++) add_box(P, tend.boxes[j]); 01461 for (j = 0; j < boxn; j++) add_box(P, boxes[j]); 01462 for (j = hend.boxn - 1; j >= 0; j--) add_box(P, hend.boxes[j]); 01463 01464 if (splines) ps = routesplines(P, &pn); 01465 else ps = routepolylines(P, &pn); 01466 if (pn == 0) 01467 return; 01468 clip_and_install(e, aghead(e), ps, pn, &sinfo); 01469 P->nbox = 0; 01470 } 01471 } 01472 01473 /* make_flat_edge: 01474 * Construct flat edges edges[ind...ind+cnt-1] 01475 * There are 4 main cases: 01476 * - all edges between a and b where a and b are adjacent 01477 * - one labeled edge 01478 * - all non-labeled edges with identical ports between non-adjacent a and b 01479 * = connecting bottom to bottom/left/right - route along bottom 01480 * = the rest - route along top 01481 */ 01482 static void 01483 make_flat_edge(spline_info_t* sp, path * P, edge_t ** edges, int ind, int cnt, int et) 01484 { 01485 node_t *tn, *hn; 01486 #ifndef WITH_CGRAPH 01487 edge_t fwdedge, *e; 01488 #else 01489 Agedgeinfo_t fwdedgei; 01490 Agedgepair_t fwdedge; 01491 edge_t *e; 01492 #endif 01493 int j, i, r, isAdjacent; 01494 double stepx, stepy, vspace; 01495 int tside, hside, pn; 01496 pointf *ps; 01497 pathend_t tend, hend; 01498 graph_t* g; 01499 01500 #ifdef WITH_CGRAPH 01501 fwdedge.out.base.data = (Agrec_t*)&fwdedgei; 01502 #endif 01503 01504 /* Get sample edge; normalize to go from left to right */ 01505 e = edges[ind]; 01506 isAdjacent = ED_adjacent(e); 01507 if (ED_tree_index(e) & BWDEDGE) { 01508 #ifndef WITH_CGRAPH 01509 MAKEFWDEDGE(&fwdedge, e); 01510 e = &fwdedge; 01511 #else 01512 MAKEFWDEDGE(&fwdedge.out, e); 01513 e = &fwdedge.out; 01514 #endif 01515 } 01516 for (i = 1; i < cnt; i++) { 01517 if (ED_adjacent(edges[ind+i])) { 01518 isAdjacent = 1; 01519 break; 01520 } 01521 } 01522 /* The lead edge edges[ind] might not have been marked earlier as adjacent, 01523 * so check them all. 01524 */ 01525 if (isAdjacent) { 01526 make_flat_adj_edges (P, edges, ind, cnt, e, et); 01527 return; 01528 } 01529 if (ED_label(e)) { /* edges with labels aren't multi-edges */ 01530 make_flat_labeled_edge (sp, P, e, et); 01531 return; 01532 } 01533 01534 if (et == ET_LINE) { 01535 makeSimpleFlat (agtail(e), aghead(e), edges, ind, cnt, et); 01536 return; 01537 } 01538 01539 tside = ED_tail_port(e).side; 01540 hside = ED_head_port(e).side; 01541 if (((tside == BOTTOM) && (hside != TOP)) || 01542 ((hside == BOTTOM) && (tside != TOP))) { 01543 make_flat_bottom_edges (sp, P, edges, ind, cnt, e, et == ET_SPLINE); 01544 return; 01545 } 01546 01547 tn = agtail(e); 01548 hn = aghead(e); 01549 g = agraphof(tn); 01550 r = ND_rank(tn); 01551 if (r > 0) { 01552 rank_t* prevr; 01553 if (GD_has_labels(g) & EDGE_LABEL) 01554 prevr = GD_rank(g) + (r-2); 01555 else 01556 prevr = GD_rank(g) + (r-1); 01557 vspace = ND_coord(prevr->v[0]).y - prevr->ht1 - ND_coord(tn).y - GD_rank(g)[r].ht2; 01558 } 01559 else { 01560 vspace = GD_ranksep(g); 01561 } 01562 stepx = ((double)sp->Multisep) / (cnt+1); 01563 stepy = vspace / (cnt+1); 01564 01565 makeFlatEnd (sp, P, tn, e, &tend, TRUE); 01566 makeFlatEnd (sp, P, hn, e, &hend, FALSE); 01567 01568 for (i = 0; i < cnt; i++) { 01569 int boxn; 01570 boxf b; 01571 e = edges[ind + i]; 01572 boxn = 0; 01573 01574 b = tend.boxes[tend.boxn - 1]; 01575 boxes[boxn].LL.x = b.LL.x; 01576 boxes[boxn].LL.y = b.UR.y; 01577 boxes[boxn].UR.x = b.UR.x + (i + 1) * stepx; 01578 boxes[boxn].UR.y = b.UR.y + (i + 1) * stepy; 01579 boxn++; 01580 boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x; 01581 boxes[boxn].LL.y = boxes[boxn-1].UR.y; 01582 boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x; 01583 boxes[boxn].UR.y = boxes[boxn].LL.y + stepy; 01584 boxn++; 01585 b = hend.boxes[hend.boxn - 1]; 01586 boxes[boxn].UR.x = b.UR.x; 01587 boxes[boxn].LL.y = b.UR.y; 01588 boxes[boxn].LL.x = b.LL.x - (i + 1) * stepx; 01589 boxes[boxn].UR.y = boxes[boxn-1].LL.y; 01590 boxn++; 01591 01592 for (j = 0; j < tend.boxn; j++) add_box(P, tend.boxes[j]); 01593 for (j = 0; j < boxn; j++) add_box(P, boxes[j]); 01594 for (j = hend.boxn - 1; j >= 0; j--) add_box(P, hend.boxes[j]); 01595 01596 if (et == ET_SPLINE) ps = routesplines(P, &pn); 01597 else ps = routepolylines(P, &pn); 01598 if (pn == 0) 01599 return; 01600 clip_and_install(e, aghead(e), ps, pn, &sinfo); 01601 P->nbox = 0; 01602 } 01603 } 01604 01605 /* ccw: 01606 * Return true if p3 is to left of ray p1->p2 01607 */ 01608 static int 01609 leftOf (pointf p1, pointf p2, pointf p3) 01610 { 01611 int d; 01612 01613 d = ((p1.y - p2.y) * (p3.x - p2.x)) - 01614 ((p3.y - p2.y) * (p1.x - p2.x)); 01615 return (d > 0); 01616 } 01617 01618 /* makeLineEdge: 01619 * Create an edge as line segment. We guarantee that the points 01620 * are always drawn downwards. This means that for flipped edges, 01621 * we draw from the head to the tail. The routine returns the 01622 * end node of the edge in *hp. The points are stored in the 01623 * given array of points, and the number of points is returned. 01624 * 01625 * If the edge has a label, the edge is draw as two segments, with 01626 * the bend near the label. 01627 * 01628 * If the endpoints are on adjacent ranks, revert to usual code by 01629 * returning 0. 01630 * This is done because the usual code handles the interaction of 01631 * multiple edges better. 01632 */ 01633 static int 01634 makeLineEdge(edge_t* fe, pointf* points, node_t** hp) 01635 { 01636 int delr, pn; 01637 node_t* hn; 01638 node_t* tn; 01639 edge_t* e = fe; 01640 pointf startp, endp, lp; 01641 pointf dimen; 01642 double width, height; 01643 01644 while (ED_edge_type(e) != NORMAL) 01645 e = ED_to_orig(e); 01646 hn = aghead(e); 01647 tn = agtail(e); 01648 delr = ABS(ND_rank(hn)-ND_rank(tn)); 01649 if ((delr == 1) || ((delr == 2) && (GD_has_labels(agraphof(hn)) & EDGE_LABEL))) 01650 return 0; 01651 if (agtail(fe) == agtail(e)) { 01652 *hp = hn; 01653 startp = add_pointf(ND_coord(tn), ED_tail_port(e).p); 01654 endp = add_pointf(ND_coord(hn), ED_head_port(e).p); 01655 } 01656 else { 01657 *hp = tn; 01658 startp = add_pointf(ND_coord(hn), ED_head_port(e).p); 01659 endp = add_pointf(ND_coord(tn), ED_tail_port(e).p); 01660 } 01661 01662 if (ED_label(e)) { 01663 dimen = ED_label(e)->dimen; 01664 if (GD_flip(agraphof(hn))) { 01665 width = dimen.y; 01666 height = dimen.x; 01667 } 01668 else { 01669 width = dimen.x; 01670 height = dimen.y; 01671 } 01672 01673 lp = ED_label(e)->pos, lp; 01674 if (leftOf (endp,startp,lp)) { 01675 lp.x += width/2.0; 01676 lp.y -= height/2.0; 01677 } 01678 else { 01679 lp.x -= width/2.0; 01680 lp.y += height/2.0; 01681 } 01682 01683 points[1] = points[0] = startp; 01684 points[2] = points[3] = points[4] = lp; 01685 points[5] = points[6] = endp; 01686 pn = 7; 01687 } 01688 else { 01689 points[1] = points[0] = startp; 01690 points[3] = points[2] = endp; 01691 pn = 4; 01692 } 01693 01694 return pn; 01695 } 01696 01697 #define NUMPTS 2000 01698 01699 /* make_regular_edge: 01700 */ 01701 static void 01702 make_regular_edge(spline_info_t* sp, path * P, edge_t ** edges, int ind, int cnt, int et) 01703 { 01704 graph_t *g; 01705 node_t *tn, *hn; 01706 #ifndef WITH_CGRAPH 01707 edge_t fwdedgea, fwdedgeb, fwdedge, *e, *fe, *le, *segfirst; 01708 #else 01709 Agedgeinfo_t fwdedgeai, fwdedgebi, fwdedgei; 01710 Agedgepair_t fwdedgea, fwdedgeb, fwdedge; 01711 edge_t *e, *fe, *le, *segfirst; 01712 #endif /* WITH_CGRAPH */ 01713 pointf *ps; 01714 pathend_t tend, hend; 01715 boxf b; 01716 int boxn, sl, si, smode, i, j, dx, pn, hackflag, longedge; 01717 static pointf* pointfs; 01718 static pointf* pointfs2; 01719 static int numpts; 01720 static int numpts2; 01721 int pointn; 01722 01723 #ifdef WITH_CGRAPH 01724 fwdedgea.out.base.data = (Agrec_t*)&fwdedgeai; 01725 fwdedgeb.out.base.data = (Agrec_t*)&fwdedgebi; 01726 fwdedge.out.base.data = (Agrec_t*)&fwdedgei; 01727 #endif /* WITH_CGRAPH */ 01728 01729 if (!pointfs) { 01730 pointfs = N_GNEW(NUMPTS, pointf); 01731 pointfs2 = N_GNEW(NUMPTS, pointf); 01732 numpts = NUMPTS; 01733 numpts2 = NUMPTS; 01734 } 01735 sl = 0; 01736 e = edges[ind]; 01737 g = agraphof(agtail(e)); 01738 hackflag = FALSE; 01739 if (ABS(ND_rank(agtail(e)) - ND_rank(aghead(e))) > 1) { 01740 #ifndef WITH_CGRAPH 01741 fwdedgea = *e; 01742 #else /* WITH_CGRAPH */ 01743 fwdedgeai = *(Agedgeinfo_t*)e->base.data; 01744 fwdedgea.out = *e; 01745 fwdedgea.out.base.data = (Agrec_t*)&fwdedgeai; 01746 #endif /* WITH_CGRAPH */ 01747 if (ED_tree_index(e) & BWDEDGE) { 01748 #ifndef WITH_CGRAPH 01749 MAKEFWDEDGE(&fwdedgeb, e); 01750 fwdedgea.tail = aghead(e); 01751 fwdedgea.u.tail_port = ED_head_port(e); 01752 #else /* WITH_CGRAPH */ 01753 MAKEFWDEDGE(&fwdedgeb.out, e); 01754 agtail(&fwdedgea.out) = aghead(e); 01755 ED_tail_port(&fwdedgea.out) = ED_head_port(e); 01756 #endif /* WITH_CGRAPH */ 01757 } else { 01758 #ifndef WITH_CGRAPH 01759 fwdedgeb = *e; 01760 fwdedgea.tail = e->tail; 01761 #else /* WITH_CGRAPH */ 01762 fwdedgebi = *(Agedgeinfo_t*)e->base.data; 01763 fwdedgeb.out = *e; 01764 fwdedgeb.out.base.data = (Agrec_t*)&fwdedgebi; 01765 agtail(&fwdedgea.out) = agtail(e); 01766 #endif /* WITH_CGRAPH */ 01767 } 01768 le = getmainedge(e); 01769 while (ED_to_virt(le)) 01770 le = ED_to_virt(le); 01771 #ifndef WITH_CGRAPH 01772 fwdedgea.head = aghead(le); 01773 fwdedgea.u.head_port.defined = FALSE; 01774 fwdedgea.u.edge_type = VIRTUAL; 01775 fwdedgea.u.head_port.p.x = fwdedgea.u.head_port.p.y = 0; 01776 fwdedgea.u.to_orig = e; 01777 e = &fwdedgea; 01778 #else /* WITH_CGRAPH */ 01779 aghead(&fwdedgea.out) = aghead(le); 01780 ED_head_port(&fwdedgea.out).defined = FALSE; 01781 ED_edge_type(&fwdedgea.out) = VIRTUAL; 01782 ED_head_port(&fwdedgea.out).p.x = ED_head_port(&fwdedgea.out).p.y = 0; 01783 ED_to_orig(&fwdedgea.out) = e; 01784 e = &fwdedgea.out; 01785 #endif /* WITH_CGRAPH */ 01786 hackflag = TRUE; 01787 } else { 01788 if (ED_tree_index(e) & BWDEDGE) { 01789 #ifndef WITH_CGRAPH 01790 MAKEFWDEDGE(&fwdedgea, e); 01791 e = &fwdedgea; 01792 #else 01793 MAKEFWDEDGE(&fwdedgea.out, e); 01794 e = &fwdedgea.out; 01795 #endif 01796 } 01797 } 01798 fe = e; 01799 01800 /* compute the spline points for the edge */ 01801 01802 if ((et == ET_LINE) && (pointn = makeLineEdge (fe, pointfs, &hn))) { 01803 } 01804 else { 01805 int splines = et == ET_SPLINE; 01806 boxn = 0; 01807 pointn = 0; 01808 segfirst = e; 01809 tn = agtail(e); 01810 hn = aghead(e); 01811 b = tend.nb = maximal_bbox(sp, tn, NULL, e); 01812 beginpath(P, e, REGULAREDGE, &tend, spline_merge(tn)); 01813 b.UR.y = tend.boxes[tend.boxn - 1].UR.y; 01814 b.LL.y = tend.boxes[tend.boxn - 1].LL.y; 01815 b = makeregularend(b, BOTTOM, 01816 ND_coord(tn).y - GD_rank(agraphof(tn))[ND_rank(tn)].ht1); 01817 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y) 01818 tend.boxes[tend.boxn++] = b; 01819 longedge = 0; 01820 smode = FALSE, si = -1; 01821 while (ND_node_type(hn) == VIRTUAL && !sinfo.splineMerge(hn)) { 01822 longedge = 1; 01823 boxes[boxn++] = rank_box(sp, g, ND_rank(tn)); 01824 if (!smode 01825 && ((sl = straight_len(hn)) >= 01826 ((GD_has_labels(g) & EDGE_LABEL) ? 4 + 1 : 2 + 1))) { 01827 smode = TRUE; 01828 si = 1, sl -= 2; 01829 } 01830 if (!smode || si > 0) { 01831 si--; 01832 boxes[boxn++] = maximal_bbox(sp, hn, e, ND_out(hn).list[0]); 01833 e = ND_out(hn).list[0]; 01834 tn = agtail(e); 01835 hn = aghead(e); 01836 continue; 01837 } 01838 hend.nb = maximal_bbox(sp, hn, e, ND_out(hn).list[0]); 01839 endpath(P, e, REGULAREDGE, &hend, spline_merge(aghead(e))); 01840 b = makeregularend(hend.boxes[hend.boxn - 1], TOP, 01841 ND_coord(hn).y + GD_rank(agraphof(hn))[ND_rank(hn)].ht2); 01842 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y) 01843 hend.boxes[hend.boxn++] = b; 01844 P->end.theta = M_PI / 2, P->end.constrained = TRUE; 01845 completeregularpath(P, segfirst, e, &tend, &hend, boxes, boxn, 1); 01846 if (splines) ps = routesplines(P, &pn); 01847 else { 01848 ps = routepolylines (P, &pn); 01849 if ((et == ET_LINE) && (pn > 4)) { 01850 ps[1] = ps[0]; 01851 ps[3] = ps[2] = ps[pn-1]; 01852 pn = 4; 01853 } 01854 } 01855 if (pn == 0) 01856 return; 01857 01858 if (pointn + pn > numpts) { 01859 /* This should be enough to include 3 extra points added by 01860 * straight_path below. 01861 */ 01862 numpts = 2*(pointn+pn); 01863 pointfs = RALLOC(numpts, pointfs, pointf); 01864 } 01865 for (i = 0; i < pn; i++) { 01866 pointfs[pointn++] = ps[i]; 01867 } 01868 e = straight_path(ND_out(hn).list[0], sl, pointfs, &pointn); 01869 recover_slack(segfirst, P); 01870 segfirst = e; 01871 tn = agtail(e); 01872 hn = aghead(e); 01873 boxn = 0; 01874 tend.nb = maximal_bbox(sp, tn, ND_in(tn).list[0], e); 01875 beginpath(P, e, REGULAREDGE, &tend, spline_merge(tn)); 01876 b = makeregularend(tend.boxes[tend.boxn - 1], BOTTOM, 01877 ND_coord(tn).y - GD_rank(agraphof(tn))[ND_rank(tn)].ht1); 01878 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y) 01879 tend.boxes[tend.boxn++] = b; 01880 P->start.theta = -M_PI / 2, P->start.constrained = TRUE; 01881 smode = FALSE; 01882 } 01883 boxes[boxn++] = rank_box(sp, g, ND_rank(tn)); 01884 b = hend.nb = maximal_bbox(sp, hn, e, NULL); 01885 #ifndef WITH_CGRAPH 01886 endpath(P, hackflag ? &fwdedgeb : e, REGULAREDGE, &hend, spline_merge(aghead(e))); 01887 #else 01888 endpath(P, hackflag ? &fwdedgeb.out : e, REGULAREDGE, &hend, spline_merge(aghead(e))); 01889 #endif 01890 b.UR.y = hend.boxes[hend.boxn - 1].UR.y; 01891 b.LL.y = hend.boxes[hend.boxn - 1].LL.y; 01892 b = makeregularend(b, TOP, 01893 ND_coord(hn).y + GD_rank(agraphof(hn))[ND_rank(hn)].ht2); 01894 if (b.LL.x < b.UR.x && b.LL.y < b.UR.y) 01895 hend.boxes[hend.boxn++] = b; 01896 completeregularpath(P, segfirst, e, &tend, &hend, boxes, boxn, 01897 longedge); 01898 if (splines) ps = routesplines(P, &pn); 01899 else ps = routepolylines (P, &pn); 01900 if ((et == ET_LINE) && (pn > 4)) { 01901 /* Here we have used the polyline case to handle 01902 * an edge between two nodes on adjacent ranks. If the 01903 * results really is a polyline, straighten it. 01904 */ 01905 ps[1] = ps[0]; 01906 ps[3] = ps[2] = ps[pn-1]; 01907 pn = 4; 01908 } 01909 if (pn == 0) 01910 return; 01911 if (pointn + pn > numpts) { 01912 numpts = 2*(pointn+pn); 01913 pointfs = RALLOC(numpts, pointfs, pointf); 01914 } 01915 for (i = 0; i < pn; i++) { 01916 pointfs[pointn++] = ps[i]; 01917 } 01918 recover_slack(segfirst, P); 01919 #ifndef WITH_CGRAPH 01920 hn = hackflag ? aghead(&fwdedgeb) : aghead(e); 01921 #else 01922 hn = hackflag ? aghead(&fwdedgeb.out) : aghead(e); 01923 #endif 01924 } 01925 01926 /* make copies of the spline points, one per multi-edge */ 01927 01928 if (cnt == 1) { 01929 clip_and_install(fe, hn, pointfs, pointn, &sinfo); 01930 return; 01931 } 01932 dx = sp->Multisep * (cnt - 1) / 2; 01933 for (i = 1; i < pointn - 1; i++) 01934 pointfs[i].x -= dx; 01935 01936 if (numpts > numpts2) { 01937 numpts2 = numpts; 01938 pointfs2 = RALLOC(numpts2, pointfs2, pointf); 01939 } 01940 for (i = 0; i < pointn; i++) 01941 pointfs2[i] = pointfs[i]; 01942 clip_and_install(fe, hn, pointfs2, pointn, &sinfo); 01943 for (j = 1; j < cnt; j++) { 01944 e = edges[ind + j]; 01945 if (ED_tree_index(e) & BWDEDGE) { 01946 #ifndef WITH_CGRAPH 01947 MAKEFWDEDGE(&fwdedge, e); 01948 e = &fwdedge; 01949 #else 01950 MAKEFWDEDGE(&fwdedge.out, e); 01951 e = &fwdedge.out; 01952 #endif 01953 } 01954 for (i = 1; i < pointn - 1; i++) 01955 pointfs[i].x += sp->Multisep; 01956 for (i = 0; i < pointn; i++) 01957 pointfs2[i] = pointfs[i]; 01958 clip_and_install(e, aghead(e), pointfs2, pointn, &sinfo); 01959 } 01960 } 01961 01962 /* regular edges */ 01963 01964 #define DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT 01965 #ifdef DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT 01966 static void 01967 completeregularpath(path * P, edge_t * first, edge_t * last, 01968 pathend_t * tendp, pathend_t * hendp, boxf * boxes, 01969 int boxn, int flag) 01970 { 01971 edge_t *uleft, *uright, *lleft, *lright; 01972 int i, fb, lb; 01973 splines *spl; 01974 pointf *pp; 01975 int pn; 01976 01977 fb = lb = -1; 01978 uleft = uright = NULL; 01979 uleft = top_bound(first, -1), uright = top_bound(first, 1); 01980 if (uleft) { 01981 if (!(spl = getsplinepoints(uleft))) return; 01982 pp = spl->list[0].list; 01983 pn = spl->list[0].size; 01984 } 01985 if (uright) { 01986 if (!(spl = getsplinepoints(uright))) return; 01987 pp = spl->list[0].list; 01988 pn = spl->list[0].size; 01989 } 01990 lleft = lright = NULL; 01991 lleft = bot_bound(last, -1), lright = bot_bound(last, 1); 01992 if (lleft) { 01993 if (!(spl = getsplinepoints(lleft))) return; 01994 pp = spl->list[spl->size - 1].list; 01995 pn = spl->list[spl->size - 1].size; 01996 } 01997 if (lright) { 01998 if (!(spl = getsplinepoints(lright))) return; 01999 pp = spl->list[spl->size - 1].list; 02000 pn = spl->list[spl->size - 1].size; 02001 } 02002 for (i = 0; i < tendp->boxn; i++) 02003 add_box(P, tendp->boxes[i]); 02004 fb = P->nbox + 1; 02005 lb = fb + boxn - 3; 02006 for (i = 0; i < boxn; i++) 02007 add_box(P, boxes[i]); 02008 for (i = hendp->boxn - 1; i >= 0; i--) 02009 add_box(P, hendp->boxes[i]); 02010 adjustregularpath(P, fb, lb); 02011 } 02012 #else 02013 void refineregularends(edge_t * left, edge_t * right, pathend_t * endp, 02014 int dir, boxf b, boxf * boxes, int *boxnp); 02015 02016 /* box subdivision is obsolete, I think... ek */ 02017 static void 02018 completeregularpath(path * P, edge_t * first, edge_t * last, 02019 pathend_t * tendp, pathend_t * hendp, boxf * boxes, 02020 int boxn, int flag) 02021 { 02022 edge_t *uleft, *uright, *lleft, *lright; 02023 boxf uboxes[NSUB], lboxes[NSUB]; 02024 boxf b; 02025 int uboxn, lboxn, i, y, fb, lb; 02026 02027 fb = lb = -1; 02028 uleft = uright = NULL; 02029 if (flag || ND_rank(agtail(first)) + 1 != ND_rank(aghead(last))) 02030 uleft = top_bound(first, -1), uright = top_bound(first, 1); 02031 refineregularends(uleft, uright, tendp, 1, boxes[0], uboxes, &uboxn); 02032 lleft = lright = NULL; 02033 if (flag || ND_rank(agtail(first)) + 1 != ND_rank(aghead(last))) 02034 lleft = bot_bound(last, -1), lright = bot_bound(last, 1); 02035 refineregularends(lleft, lright, hendp, -1, boxes[boxn - 1], lboxes, 02036 &lboxn); 02037 for (i = 0; i < tendp->boxn; i++) 02038 add_box(P, tendp->boxes[i]); 02039 if (ND_rank(agtail(first)) + 1 == ND_rank(aghead(last))) { 02040 if ((!uleft && !uright) && (lleft || lright)) { 02041 b = boxes[0]; 02042 y = b.UR.y - b.LL.y; 02043 for (i = 0; i < NSUB; i++) { 02044 uboxes[i] = b; 02045 uboxes[i].UR.y = b.UR.y - y * i / NSUB; 02046 uboxes[i].LL.y = b.UR.y - y * (i + 1) / NSUB; 02047 } 02048 uboxn = NSUB; 02049 } else if ((uleft || uright) && (!lleft && !lright)) { 02050 b = boxes[boxn - 1]; 02051 y = b.UR.y - b.LL.y; 02052 for (i = 0; i < NSUB; i++) { 02053 lboxes[i] = b; 02054 lboxes[i].UR.y = b.UR.y - y * i / NSUB; 02055 lboxes[i].LL.y = b.UR.y - y * (i + 1) / NSUB; 02056 } 02057 lboxn = NSUB; 02058 } 02059 for (i = 0; i < uboxn; i++) { 02060 uboxes[i].LL.x = MAX(uboxes[i].LL.x, lboxes[i].LL.x); 02061 uboxes[i].UR.x = MIN(uboxes[i].UR.x, lboxes[i].UR.x); 02062 } 02063 for (i = 0; i < uboxn; i++) 02064 add_box(P, uboxes[i]); 02065 } else { 02066 for (i = 0; i < uboxn; i++) 02067 add_box(P, uboxes[i]); 02068 fb = P->nbox; 02069 lb = fb + boxn - 3; 02070 for (i = 1; i < boxn - 1; i++) 02071 add_box(P, boxes[i]); 02072 for (i = 0; i < lboxn; i++) 02073 add_box(P, lboxes[i]); 02074 } 02075 for (i = hendp->boxn - 1; i >= 0; i--) 02076 add_box(P, hendp->boxes[i]); 02077 adjustregularpath(P, fb, lb); 02078 } 02079 #endif 02080 02081 /* makeregularend: 02082 * Add box to fill between node and interrank space. Needed because 02083 * nodes in a given rank can differ in height. 02084 * for now, regular edges always go from top to bottom 02085 */ 02086 static boxf makeregularend(boxf b, int side, int y) 02087 { 02088 boxf newb; 02089 switch (side) { 02090 case BOTTOM: 02091 newb = boxfof(b.LL.x, y, b.UR.x, b.LL.y); 02092 break; 02093 case TOP: 02094 newb = boxfof(b.LL.x, b.UR.y, b.UR.x, y); 02095 break; 02096 } 02097 return newb; 02098 } 02099 02100 #ifndef DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT 02101 void refineregularends(left, right, endp, dir, b, boxes, boxnp) 02102 edge_t *left, *right; 02103 pathend_t *endp; 02104 int dir; 02105 box b; 02106 box *boxes; 02107 int *boxnp; 02108 { 02109 splines *lspls, *rspls; 02110 point pp, cp; 02111 box eb; 02112 box *bp; 02113 int y, i, j, k; 02114 int nsub; 02115 02116 y = b.UR.y - b.LL.y; 02117 if ((y == 1) || (!left && !right)) { 02118 boxes[0] = b; 02119 *boxnp = 1; 02120 return; 02121 } 02122 nsub = MIN(NSUB, y); 02123 for (i = 0; i < nsub; i++) { 02124 boxes[i] = b; 02125 boxes[i].UR.y = b.UR.y - y * i / nsub; 02126 boxes[i].LL.y = b.UR.y - y * (i + 1) / nsub; 02127 if (boxes[i].UR.y == boxes[i].LL.y) 02128 abort(); 02129 } 02130 *boxnp = nsub; 02131 /* only break big boxes */ 02132 for (j = 0; j < endp->boxn; j++) { 02133 eb = endp->boxes[j]; 02134 y = eb.UR.y - eb.LL.y; 02135 #ifdef STEVE_AND_LEFTY_GRASPING_AT_STRAWS 02136 if (y < 15) 02137 continue; 02138 #else 02139 if (y < nsub) 02140 continue; 02141 #endif 02142 for (k = endp->boxn - 1; k > j; k--) 02143 endp->boxes[k + (nsub - 1)] = endp->boxes[k]; 02144 for (i = 0; i < nsub; i++) { 02145 bp = &endp->boxes[j + ((dir == 1) ? i : (nsub - i - 1))]; 02146 *bp = eb; 02147 bp->UR.y = eb.UR.y - y * i / nsub; 02148 bp->LL.y = eb.UR.y - y * (i + 1) / nsub; 02149 if (bp->UR.y == bp->LL.y) 02150 abort(); 02151 } 02152 endp->boxn += (nsub - 1); 02153 j += nsub - 1; 02154 } 02155 if (left) { 02156 if (!(lspls = getsplinepoints(left))) return; 02157 pp = spline_at_y(lspls, boxes[0].UR.y); 02158 for (i = 0; i < nsub; i++) { 02159 cp = spline_at_y(lspls, boxes[i].LL.y); 02160 /*boxes[i].LL.x = AVG (pp.x, cp.x); */ 02161 boxes[i].LL.x = MAX(pp.x, cp.x); 02162 pp = cp; 02163 } 02164 pp = spline_at_y(lspls, (dir == 1) ? 02165 endp->boxes[1].UR.y : endp->boxes[1].LL.y); 02166 for (i = 1; i < endp->boxn; i++) { 02167 cp = spline_at_y(lspls, (dir == 1) ? 02168 endp->boxes[i].LL.y : endp->boxes[i].UR.y); 02169 endp->boxes[i].LL.x = MIN(endp->nb.UR.x, MAX(pp.x, cp.x)); 02170 pp = cp; 02171 } 02172 i = (dir == 1) ? 0 : *boxnp - 1; 02173 if (boxes[i].LL.x > endp->boxes[endp->boxn - 1].UR.x - MINW) 02174 boxes[i].LL.x = endp->boxes[endp->boxn - 1].UR.x - MINW; 02175 } 02176 if (right) { 02177 if (!(rspls = getsplinepoints(right))) return; 02178 pp = spline_at_y(rspls, boxes[0].UR.y); 02179 for (i = 0; i < nsub; i++) { 02180 cp = spline_at_y(rspls, boxes[i].LL.y); 02181 /*boxes[i].UR.x = AVG (pp.x, cp.x); */ 02182 boxes[i].UR.x = AVG(pp.x, cp.x); 02183 pp = cp; 02184 } 02185 pp = spline_at_y(rspls, (dir == 1) ? 02186 endp->boxes[1].UR.y : endp->boxes[1].LL.y); 02187 for (i = 1; i < endp->boxn; i++) { 02188 cp = spline_at_y(rspls, (dir == 1) ? 02189 endp->boxes[i].LL.y : endp->boxes[i].UR.y); 02190 endp->boxes[i].UR.x = MAX(endp->nb.LL.x, AVG(pp.x, cp.x)); 02191 pp = cp; 02192 } 02193 i = (dir == 1) ? 0 : *boxnp - 1; 02194 if (boxes[i].UR.x < endp->boxes[endp->boxn - 1].LL.x + MINW) 02195 boxes[i].UR.x = endp->boxes[endp->boxn - 1].LL.x + MINW; 02196 } 02197 } 02198 #endif 02199 02200 /* adjustregularpath: 02201 * make sure the path is wide enough. 02202 * the % 2 was so that in rank boxes would only be grown if 02203 * they were == 0 while inter-rank boxes could be stretched to a min 02204 * width. 02205 * The list of boxes has three parts: tail boxes, path boxes, and head 02206 * boxes. (Note that because of back edges, the tail boxes might actually 02207 * belong to the head node, and vice versa.) fb is the index of the 02208 * first interrank path box and lb is the last interrank path box. 02209 * If fb > lb, there are none. 02210 * 02211 * The second for loop was added by ek long ago, and apparently is intended 02212 * to guarantee an overlap between adjacent boxes of at least MINW. 02213 * It doesn't do this, and the ifdef'ed part has the potential of moving 02214 * a box within a node for more complex paths. 02215 */ 02216 static void adjustregularpath(path * P, int fb, int lb) 02217 { 02218 boxf *bp1, *bp2; 02219 int i, x; 02220 02221 for (i = fb-1; i < lb+1; i++) { 02222 bp1 = &P->boxes[i]; 02223 if ((i - fb) % 2 == 0) { 02224 if (bp1->LL.x >= bp1->UR.x) { 02225 x = (bp1->LL.x + bp1->UR.x) / 2; 02226 bp1->LL.x = x - HALFMINW, bp1->UR.x = x + HALFMINW; 02227 } 02228 } else { 02229 if (bp1->LL.x + MINW > bp1->UR.x) { 02230 x = (bp1->LL.x + bp1->UR.x) / 2; 02231 bp1->LL.x = x - HALFMINW, bp1->UR.x = x + HALFMINW; 02232 } 02233 } 02234 } 02235 for (i = 0; i < P->nbox - 1; i++) { 02236 bp1 = &P->boxes[i], bp2 = &P->boxes[i + 1]; 02237 if (i >= fb && i <= lb && (i - fb) % 2 == 0) { 02238 if (bp1->LL.x + MINW > bp2->UR.x) 02239 bp2->UR.x = bp1->LL.x + MINW; 02240 if (bp1->UR.x - MINW < bp2->LL.x) 02241 bp2->LL.x = bp1->UR.x - MINW; 02242 } else if (i + 1 >= fb && i < lb && (i + 1 - fb) % 2 == 0) { 02243 if (bp1->LL.x + MINW > bp2->UR.x) 02244 bp1->LL.x = bp2->UR.x - MINW; 02245 if (bp1->UR.x - MINW < bp2->LL.x) 02246 bp1->UR.x = bp2->LL.x + MINW; 02247 } 02248 } 02249 } 02250 02251 static boxf rank_box(spline_info_t* sp, graph_t * g, int r) 02252 { 02253 boxf b; 02254 node_t /* *right0, *right1, */ * left0, *left1; 02255 02256 b = sp->Rank_box[r]; 02257 if (b.LL.x == b.UR.x) { 02258 left0 = GD_rank(g)[r].v[0]; 02259 /* right0 = GD_rank(g)[r].v[GD_rank(g)[r].n - 1]; */ 02260 left1 = GD_rank(g)[r + 1].v[0]; 02261 /* right1 = GD_rank(g)[r + 1].v[GD_rank(g)[r + 1].n - 1]; */ 02262 b.LL.x = sp->LeftBound; 02263 b.LL.y = ND_coord(left1).y + GD_rank(g)[r + 1].ht2; 02264 b.UR.x = sp->RightBound; 02265 b.UR.y = ND_coord(left0).y - GD_rank(g)[r].ht1; 02266 sp->Rank_box[r] = b; 02267 } 02268 return b; 02269 } 02270 02271 /* returns count of vertically aligned edges starting at n */ 02272 static int straight_len(node_t * n) 02273 { 02274 int cnt = 0; 02275 node_t *v; 02276 02277 v = n; 02278 while (1) { 02279 v = aghead(ND_out(v).list[0]); 02280 if (ND_node_type(v) != VIRTUAL) 02281 break; 02282 if ((ND_out(v).size != 1) || (ND_in(v).size != 1)) 02283 break; 02284 if (ND_coord(v).x != ND_coord(n).x) 02285 break; 02286 cnt++; 02287 } 02288 return cnt; 02289 } 02290 02291 static edge_t *straight_path(edge_t * e, int cnt, pointf * plist, int *np) 02292 { 02293 int n = *np; 02294 edge_t *f = e; 02295 02296 while (cnt--) 02297 f = ND_out(aghead(f)).list[0]; 02298 plist[(*np)++] = plist[n - 1]; 02299 plist[(*np)++] = plist[n - 1]; 02300 plist[(*np)] = ND_coord(agtail(f)); /* will be overwritten by next spline */ 02301 02302 return f; 02303 } 02304 02305 static void recover_slack(edge_t * e, path * p) 02306 { 02307 int b; 02308 node_t *vn; 02309 02310 b = 0; /* skip first rank box */ 02311 for (vn = aghead(e); 02312 ND_node_type(vn) == VIRTUAL && !sinfo.splineMerge(vn); 02313 vn = aghead(ND_out(vn).list[0])) { 02314 while ((b < p->nbox) && (p->boxes[b].LL.y > ND_coord(vn).y)) 02315 b++; 02316 if (b >= p->nbox) 02317 break; 02318 if (p->boxes[b].UR.y < ND_coord(vn).y) 02319 continue; 02320 if (ND_label(vn)) 02321 resize_vn(vn, p->boxes[b].LL.x, p->boxes[b].UR.x, 02322 p->boxes[b].UR.x + ND_rw(vn)); 02323 else 02324 resize_vn(vn, p->boxes[b].LL.x, (p->boxes[b].LL.x + 02325 p->boxes[b].UR.x) / 2, 02326 p->boxes[b].UR.x); 02327 } 02328 } 02329 02330 static void resize_vn(vn, lx, cx, rx) 02331 node_t *vn; 02332 int lx, cx, rx; 02333 { 02334 ND_coord(vn).x = cx; 02335 ND_lw(vn) = cx - lx, ND_rw(vn) = rx - cx; 02336 } 02337 02338 /* side > 0 means right. side < 0 means left */ 02339 static edge_t *top_bound(edge_t * e, int side) 02340 { 02341 edge_t *f, *ans = NULL; 02342 int i; 02343 02344 for (i = 0; (f = ND_out(agtail(e)).list[i]); i++) { 02345 #if 0 /* were we out of our minds? */ 02346 if (ED_tail_port(e).p.x != ED_tail_port(f).p.x) 02347 continue; 02348 #endif 02349 if (side * (ND_order(aghead(f)) - ND_order(aghead(e))) <= 0) 02350 continue; 02351 if ((ED_spl(f) == NULL) 02352 && ((ED_to_orig(f) == NULL) || (ED_spl(ED_to_orig(f)) == NULL))) 02353 continue; 02354 if ((ans == NULL) 02355 || (side * (ND_order(aghead(ans)) - ND_order(aghead(f))) > 0)) 02356 ans = f; 02357 } 02358 return ans; 02359 } 02360 02361 static edge_t *bot_bound(edge_t * e, int side) 02362 { 02363 edge_t *f, *ans = NULL; 02364 int i; 02365 02366 for (i = 0; (f = ND_in(aghead(e)).list[i]); i++) { 02367 #if 0 /* same here */ 02368 if (ED_head_port(e).p.x != ED_head_port(f).p.x) 02369 continue; 02370 #endif 02371 if (side * (ND_order(agtail(f)) - ND_order(agtail(e))) <= 0) 02372 continue; 02373 if ((ED_spl(f) == NULL) 02374 && ((ED_to_orig(f) == NULL) || (ED_spl(ED_to_orig(f)) == NULL))) 02375 continue; 02376 if ((ans == NULL) 02377 || (side * (ND_order(agtail(ans)) - ND_order(agtail(f))) > 0)) 02378 ans = f; 02379 } 02380 return ans; 02381 } 02382 02383 /* common routines */ 02384 02385 static int cl_vninside(graph_t * cl, node_t * n) 02386 { 02387 return (BETWEEN(GD_bb(cl).LL.x, (double)(ND_coord(n).x), GD_bb(cl).UR.x) && 02388 BETWEEN(GD_bb(cl).LL.y, (double)(ND_coord(n).y), GD_bb(cl).UR.y)); 02389 } 02390 02391 /* All nodes belong to some cluster, which may be the root graph. 02392 * For the following, we only want a cluster if it is a real cluster 02393 * It is not clear this will handle all potential problems. It seems one 02394 * could have hcl and tcl contained in cl, which would also cause problems. 02395 */ 02396 #define REAL_CLUSTER(n) (ND_clust(n)==agraphof(n)?NULL:ND_clust(n)) 02397 02398 /* returns the cluster of (adj) that interferes with n, 02399 */ 02400 static Agraph_t *cl_bound(n, adj) 02401 node_t *n, *adj; 02402 { 02403 graph_t *rv, *cl, *tcl, *hcl; 02404 edge_t *orig; 02405 02406 rv = NULL; 02407 if (ND_node_type(n) == NORMAL) 02408 tcl = hcl = ND_clust(n); 02409 else { 02410 orig = ED_to_orig(ND_out(n).list[0]); 02411 tcl = ND_clust(agtail(orig)); 02412 hcl = ND_clust(aghead(orig)); 02413 } 02414 if (ND_node_type(adj) == NORMAL) { 02415 cl = REAL_CLUSTER(adj); 02416 if (cl && (cl != tcl) && (cl != hcl)) 02417 rv = cl; 02418 } else { 02419 orig = ED_to_orig(ND_out(adj).list[0]); 02420 cl = REAL_CLUSTER(agtail(orig)); 02421 if (cl && (cl != tcl) && (cl != hcl) && cl_vninside(cl, adj)) 02422 rv = cl; 02423 else { 02424 cl = REAL_CLUSTER(aghead(orig)); 02425 if (cl && (cl != tcl) && (cl != hcl) && cl_vninside(cl, adj)) 02426 rv = cl; 02427 } 02428 } 02429 return rv; 02430 } 02431 02432 /* maximal_bbox: 02433 * Return an initial bounding box to be used for building the 02434 * beginning or ending of the path of boxes. 02435 * Height reflects height of tallest node on rank. 02436 * The extra space provided by FUDGE allows begin/endpath to create a box 02437 * FUDGE-2 away from the node, so the routing can avoid the node and the 02438 * box is at least 2 wide. 02439 */ 02440 #define FUDGE 4 02441 02442 static boxf maximal_bbox(spline_info_t* sp, node_t* vn, edge_t* ie, edge_t* oe) 02443 { 02444 double b, nb; 02445 graph_t *g = agraphof(vn), *left_cl, *right_cl; 02446 node_t *left, *right; 02447 boxf rv; 02448 02449 left_cl = right_cl = NULL; 02450 02451 /* give this node all the available space up to its neighbors */ 02452 b = (double)(ND_coord(vn).x - ND_lw(vn) - FUDGE); 02453 if ((left = neighbor(vn, ie, oe, -1))) { 02454 if ((left_cl = cl_bound(vn, left))) 02455 nb = GD_bb(left_cl).UR.x + (double)(sp->Splinesep); 02456 else { 02457 nb = (double)(ND_coord(left).x + ND_mval(left)); 02458 if (ND_node_type(left) == NORMAL) 02459 nb += GD_nodesep(g) / 2.; 02460 else 02461 nb += (double)(sp->Splinesep); 02462 } 02463 if (nb < b) 02464 b = nb; 02465 rv.LL.x = ROUND(b); 02466 } else 02467 rv.LL.x = MIN(ROUND(b), sp->LeftBound); 02468 02469 /* we have to leave room for our own label! */ 02470 if ((ND_node_type(vn) == VIRTUAL) && (ND_label(vn))) 02471 b = (double)(ND_coord(vn).x + 10); 02472 else 02473 b = (double)(ND_coord(vn).x + ND_rw(vn) + FUDGE); 02474 if ((right = neighbor(vn, ie, oe, 1))) { 02475 if ((right_cl = cl_bound(vn, right))) 02476 nb = GD_bb(right_cl).LL.x - (double)(sp->Splinesep); 02477 else { 02478 nb = ND_coord(right).x - ND_lw(right); 02479 if (ND_node_type(right) == NORMAL) 02480 nb -= GD_nodesep(g) / 2.; 02481 else 02482 nb -= (double)(sp->Splinesep); 02483 } 02484 if (nb > b) 02485 b = nb; 02486 rv.UR.x = ROUND(b); 02487 } else 02488 rv.UR.x = MAX(ROUND(b), sp->RightBound); 02489 02490 if ((ND_node_type(vn) == VIRTUAL) && (ND_label(vn))) { 02491 rv.UR.x -= ND_rw(vn); 02492 if (rv.UR.x < rv.LL.x) rv.UR.x = ND_coord(vn).x; 02493 } 02494 02495 rv.LL.y = ND_coord(vn).y - GD_rank(g)[ND_rank(vn)].ht1; 02496 rv.UR.y = ND_coord(vn).y + GD_rank(g)[ND_rank(vn)].ht2; 02497 return rv; 02498 } 02499 02500 static node_t *neighbor(vn, ie, oe, dir) 02501 node_t *vn; 02502 edge_t *ie, *oe; 02503 int dir; 02504 { 02505 int i; 02506 node_t *n, *rv = NULL; 02507 rank_t *rank = &(GD_rank(agraphof(vn))[ND_rank(vn)]); 02508 02509 for (i = ND_order(vn) + dir; ((i >= 0) && (i < rank->n)); i += dir) { 02510 n = rank->v[i]; 02511 if ((ND_node_type(n) == VIRTUAL) && (ND_label(n))) { 02512 rv = n; 02513 break; 02514 } 02515 if (ND_node_type(n) == NORMAL) { 02516 rv = n; 02517 break; 02518 } 02519 if (pathscross(n, vn, ie, oe) == FALSE) { 02520 rv = n; 02521 break; 02522 } 02523 } 02524 return rv; 02525 } 02526 02527 static boolean pathscross(n0, n1, ie1, oe1) 02528 node_t *n0, *n1; 02529 edge_t *ie1, *oe1; 02530 { 02531 edge_t *e0, *e1; 02532 node_t *na, *nb; 02533 int order, cnt; 02534 02535 order = (ND_order(n0) > ND_order(n1)); 02536 if ((ND_out(n0).size != 1) && (ND_out(n0).size != 1)) 02537 return FALSE; 02538 e1 = oe1; 02539 if (ND_out(n0).size == 1 && e1) { 02540 e0 = ND_out(n0).list[0]; 02541 for (cnt = 0; cnt < 2; cnt++) { 02542 if ((na = aghead(e0)) == (nb = aghead(e1))) 02543 break; 02544 if (order != (ND_order(na) > ND_order(nb))) 02545 return TRUE; 02546 if ((ND_out(na).size != 1) || (ND_node_type(na) == NORMAL)) 02547 break; 02548 e0 = ND_out(na).list[0]; 02549 if ((ND_out(nb).size != 1) || (ND_node_type(nb) == NORMAL)) 02550 break; 02551 e1 = ND_out(nb).list[0]; 02552 } 02553 } 02554 e1 = ie1; 02555 if (ND_in(n0).size == 1 && e1) { 02556 e0 = ND_in(n0).list[0]; 02557 for (cnt = 0; cnt < 2; cnt++) { 02558 if ((na = agtail(e0)) == (nb = agtail(e1))) 02559 break; 02560 if (order != (ND_order(na) > ND_order(nb))) 02561 return TRUE; 02562 if ((ND_in(na).size != 1) || (ND_node_type(na) == NORMAL)) 02563 break; 02564 e0 = ND_in(na).list[0]; 02565 if ((ND_in(nb).size != 1) || (ND_node_type(nb) == NORMAL)) 02566 break; 02567 e1 = ND_in(nb).list[0]; 02568 } 02569 } 02570 return FALSE; 02571 } 02572 02573 #ifdef DEBUG 02574 void showpath(path * p) 02575 { 02576 int i; 02577 pointf LL, UR; 02578 02579 fprintf(stderr, "%%!PS\n"); 02580 for (i = 0; i < p->nbox; i++) { 02581 LL = p->boxes[i].LL; 02582 UR = p->boxes[i].UR; 02583 fprintf(stderr, 02584 "newpath %.04f %.04f moveto %.04f %.04f lineto %.04f %.04f lineto %.04f %.04f lineto closepath stroke\n", 02585 LL.x, LL.y, UR.x, LL.y, UR.x, UR.y, LL.x, UR.y); 02586 } 02587 fprintf(stderr, "showpage\n"); 02588 } 02589 #endif
1.7.5