00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "dot.h"
00027
00028 static int nsiter2(graph_t * g);
00029 static void create_aux_edges(graph_t * g);
00030 static void remove_aux_edges(graph_t * g);
00031 static void set_xcoords(graph_t * g);
00032 static void set_ycoords(graph_t * g);
00033 static void set_aspect(graph_t * g);
00034 static void expand_leaves(graph_t * g);
00035 static void make_lrvn(graph_t * g);
00036 static void contain_nodes(graph_t * g);
00037 static boolean idealsize(graph_t * g, double);
00038
00039 #ifdef DEBUG
00040 static void
00041 dumpNS (graph_t * g)
00042 {
00043 node_t* n = GD_nlist(g);
00044 elist el;
00045 edge_t* e;
00046 int i;
00047
00048 while (n) {
00049 el = ND_out(n);
00050 for (i = 0; i < el.size; i++) {
00051 e = el.list[i];
00052 fprintf (stderr, "%s(%x) -> %s(%x) : %d\n", e->tail->name,e->tail, e->head->name, e->head,
00053 ED_minlen(e));
00054 }
00055 n = ND_next(n);
00056 }
00057 }
00058 #endif
00059
00060 static void
00061 largeMinlen (int l)
00062 {
00063 agerr (AGERR, "Edge length %d larger than maximum %u allowed.\nCheck for overwide node(s).\n", l, USHRT_MAX);
00064 exit (1);
00065 }
00066
00067
00068
00069
00070
00071
00072
00073 static void
00074 connectGraph (graph_t* g)
00075 {
00076 int i, j, r, found;
00077 node_t* tp;
00078 node_t* hp;
00079 node_t* sn;
00080 edge_t* e;
00081 rank_t* rp;
00082
00083 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00084 rp = GD_rank(g)+r;
00085 found =FALSE;
00086 tp = NULL;
00087 for (i = 0; i < rp->n; i++) {
00088 tp = rp->v[i];
00089 if (ND_save_out(tp).list) {
00090 for (j = 0; (e = ND_save_out(tp).list[j]); j++) {
00091 if ((ND_rank(e->head) > r) || (ND_rank(e->tail) > r)) {
00092 found = TRUE;
00093 break;
00094 }
00095 }
00096 if (found) break;
00097 }
00098 if (ND_save_in(tp).list) {
00099 for (j = 0; (e = ND_save_in(tp).list[j]); j++) {
00100 if ((ND_rank(e->tail) > r) || (ND_rank(e->head) > r)) {
00101 found = TRUE;
00102 break;
00103 }
00104 }
00105 if (found) break;
00106 }
00107 }
00108 if (found || !tp) continue;
00109 tp = rp->v[0];
00110 if (r < GD_maxrank(g)) hp = (rp+1)->v[0];
00111 else hp = (rp-1)->v[0];
00112 assert (hp);
00113 sn = virtual_node(g);
00114 ND_node_type(sn) = SLACKNODE;
00115 make_aux_edge(sn, tp, 0, 0);
00116 make_aux_edge(sn, hp, 0, 0);
00117 ND_rank(sn) = MIN(ND_rank(tp), ND_rank(hp));
00118 }
00119 }
00120
00121 void dot_position(graph_t * g)
00122 {
00123 if (GD_nlist(g) == NULL)
00124 return;
00125 mark_lowclusters(g);
00126 set_ycoords(g);
00127 if (Concentrate)
00128 dot_concentrate(g);
00129 expand_leaves(g);
00130 if (flat_edges(g))
00131 set_ycoords(g);
00132 create_aux_edges(g);
00133 if (rank(g, 2, nsiter2(g))) {
00134 connectGraph (g);
00135 assert(rank(g, 2, nsiter2(g)) == 0);
00136 }
00137 set_xcoords(g);
00138 set_aspect(g);
00139 remove_aux_edges(g);
00140
00141
00142 }
00143
00144 static int nsiter2(graph_t * g)
00145 {
00146 int maxiter = INT_MAX;
00147 char *s;
00148
00149 if ((s = agget(g, "nslimit")))
00150 maxiter = atof(s) * agnnodes(g);
00151 return maxiter;
00152 }
00153
00154 static int go(node_t * u, node_t * v)
00155 {
00156 int i;
00157 edge_t *e;
00158
00159 if (u == v)
00160 return TRUE;
00161 for (i = 0; (e = ND_out(u).list[i]); i++) {
00162 if (go(e->head, v))
00163 return TRUE;
00164 }
00165 return FALSE;
00166 }
00167
00168 static int canreach(node_t * u, node_t * v)
00169 {
00170 return go(u, v);
00171 }
00172
00173 edge_t *make_aux_edge(node_t * u, node_t * v, int len, int wt)
00174 {
00175 edge_t *e;
00176
00177 e = NEW(edge_t);
00178 e->tail = u;
00179 e->head = v;
00180 if (len > USHRT_MAX)
00181 largeMinlen (len);
00182 ED_minlen(e) = len;
00183 ED_weight(e) = wt;
00184 fast_edge(e);
00185 return e;
00186 }
00187
00188 static void allocate_aux_edges(graph_t * g)
00189 {
00190 int i, j, n_in;
00191 node_t *n;
00192
00193
00194 for (n = GD_nlist(g); n; n = ND_next(n)) {
00195 ND_save_in(n) = ND_in(n);
00196 ND_save_out(n) = ND_out(n);
00197 for (i = 0; ND_out(n).list[i]; i++);
00198 for (j = 0; ND_in(n).list[j]; j++);
00199 n_in = i + j;
00200 alloc_elist(n_in + 3, ND_in(n));
00201 alloc_elist(3, ND_out(n));
00202 }
00203 }
00204
00205
00206
00207 static void
00208 make_LR_constraints(graph_t * g)
00209 {
00210 int i, j, k;
00211 int sw;
00212 int m0, m1;
00213 int width, sep[2];
00214 int nodesep;
00215 edge_t *e, *e0, *e1, *ff;
00216 node_t *u, *v, *t0, *h0;
00217 rank_t *rank = GD_rank(g);
00218
00219
00220 if (GD_has_labels(g) & EDGE_LABEL) {
00221 sep[0] = GD_nodesep(g);
00222 sep[1] = 5;
00223 }
00224 else {
00225 sep[1] = sep[0] = GD_nodesep(g);
00226 }
00227
00228 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
00229 int last;
00230 last = rank[i].v[0]->u.rank = 0;
00231 nodesep = sep[i & 1];
00232 for (j = 0; j < rank[i].n; j++) {
00233 u = rank[i].v[j];
00234 ND_mval(u) = ND_rw_i(u);
00235 if (ND_other(u).size > 0) {
00236
00237
00238
00239
00240
00241
00242
00243
00244 sw = 0;
00245 for (k = 0; (e = ND_other(u).list[k]); k++) {
00246 if (e->tail == e->head) {
00247 sw += selfRightSpace (e);
00248 }
00249 }
00250 ND_rw_i(u) += sw;
00251 }
00252 v = rank[i].v[j + 1];
00253 if (v) {
00254 width = ND_rw_i(u) + ND_lw_i(v) + nodesep;
00255 e0 = make_aux_edge(u, v, width, 0);
00256 last = (ND_rank(v) = last + width);
00257 }
00258
00259
00260 if ((e = (edge_t*)ND_alg(u))) {
00261 e0 = ND_save_out(u).list[0];
00262 e1 = ND_save_out(u).list[1];
00263 if (ND_order(e0->head) > ND_order(e1->head)) {
00264 ff = e0;
00265 e0 = e1;
00266 e1 = ff;
00267 }
00268 m0 = (ED_minlen(e) * GD_nodesep(g)) / 2;
00269 m1 = m0 + ND_rw_i(e0->head) + ND_lw_i(e0->tail);
00270
00271
00272 if (canreach(e0->tail, e0->head) == FALSE)
00273 make_aux_edge(e0->head, e0->tail, m1,
00274 ED_weight(e));
00275 m1 = m0 + ND_rw_i(e1->tail) + ND_lw_i(e1->head);
00276 if (canreach(e1->head, e1->tail) == FALSE)
00277 make_aux_edge(e1->tail, e1->head, m1,
00278 ED_weight(e));
00279 }
00280
00281
00282 for (k = 0; k < ND_flat_out(u).size; k++) {
00283 e = ND_flat_out(u).list[k];
00284 if (ND_order(e->tail) < ND_order(e->head)) {
00285 t0 = e->tail;
00286 h0 = e->head;
00287 } else {
00288 t0 = e->head;
00289 h0 = e->tail;
00290 }
00291
00292 width = ND_rw_i(t0) + ND_lw_i(h0);
00293 m0 = ED_minlen(e) * GD_nodesep(g) + width;
00294
00295 if ((e0 = find_fast_edge(t0, h0))) {
00296
00297
00298
00299 m0 = MAX(m0, width + GD_nodesep(g) + ROUND(ED_dist(e)));
00300 if (m0 > USHRT_MAX)
00301 largeMinlen (m0);
00302 ED_minlen(e0) = MAX(ED_minlen(e0), m0);
00303 }
00304 else if (!ED_label(e)) {
00305
00306
00307
00308
00309 make_aux_edge(t0, h0, m0, ED_weight(e));
00310 }
00311
00312
00313
00314 }
00315 }
00316 }
00317 }
00318
00319
00320 static void make_edge_pairs(graph_t * g)
00321 {
00322 int i, m0, m1;
00323 node_t *n, *sn;
00324 edge_t *e;
00325
00326 for (n = GD_nlist(g); n; n = ND_next(n)) {
00327 if (ND_save_out(n).list)
00328 for (i = 0; (e = ND_save_out(n).list[i]); i++) {
00329 sn = virtual_node(g);
00330 ND_node_type(sn) = SLACKNODE;
00331 m0 = (ED_head_port(e).p.x - ED_tail_port(e).p.x);
00332 if (m0 > 0)
00333 m1 = 0;
00334 else {
00335 m1 = -m0;
00336 m0 = 0;
00337 }
00338 #ifdef NOTDEF
00339
00340 if ((ND_save_out(n).size % 2 == 0)
00341 && (i == ND_save_out(n).size / 2 - 1)) {
00342 node_t *u = ND_save_out(n).list[i]->head;
00343 node_t *v = ND_save_out(n).list[i + 1]->head;
00344 int width = ND_rw_i(u) + ND_lw_i(v) + GD_nodesep(g);
00345 m0 = width / 2 - 1;
00346 }
00347 #endif
00348 make_aux_edge(sn, e->tail, m0 + 1, ED_weight(e));
00349 make_aux_edge(sn, e->head, m1 + 1, ED_weight(e));
00350 ND_rank(sn) =
00351 MIN(ND_rank(e->tail) - m0 - 1,
00352 ND_rank(e->head) - m1 - 1);
00353 }
00354 }
00355 }
00356
00357 static void contain_clustnodes(graph_t * g)
00358 {
00359 int c;
00360 edge_t *e;
00361
00362 if (g != g->root) {
00363 contain_nodes(g);
00364 if ((e = find_fast_edge(GD_ln(g),GD_rn(g))))
00365 ED_weight(e) += 128;
00366 else
00367 make_aux_edge(GD_ln(g), GD_rn(g), 1, 128);
00368 }
00369 for (c = 1; c <= GD_n_cluster(g); c++)
00370 contain_clustnodes(GD_clust(g)[c]);
00371 }
00372
00373 static int vnode_not_related_to(graph_t * g, node_t * v)
00374 {
00375 edge_t *e;
00376
00377 if (ND_node_type(v) != VIRTUAL)
00378 return FALSE;
00379 for (e = ND_save_out(v).list[0]; ED_to_orig(e); e = ED_to_orig(e));
00380 if (agcontains(g, e->tail))
00381 return FALSE;
00382 if (agcontains(g, e->head))
00383 return FALSE;
00384 return TRUE;
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 static void keepout_othernodes(graph_t * g)
00398 {
00399 int i, c, r;
00400 node_t *u, *v;
00401
00402 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00403 if (GD_rank(g)[r].n == 0)
00404 continue;
00405 v = GD_rank(g)[r].v[0];
00406 if (v == NULL)
00407 continue;
00408 for (i = ND_order(v) - 1; i >= 0; i--) {
00409 u = GD_rank(g->root)[r].v[i];
00410
00411 if ((ND_node_type(u) == NORMAL) || vnode_not_related_to(g, u)) {
00412 make_aux_edge(u, GD_ln(g), CL_OFFSET + ND_rw_i(u), 0);
00413 break;
00414 }
00415 }
00416 for (i = ND_order(v) + GD_rank(g)[r].n; i < GD_rank(g->root)[r].n;
00417 i++) {
00418 u = ND_rank(g->root)[r].v[i];
00419 if ((ND_node_type(u) == NORMAL) || vnode_not_related_to(g, u)) {
00420 make_aux_edge(GD_rn(g), u, CL_OFFSET + ND_lw_i(u), 0);
00421 break;
00422 }
00423 }
00424 }
00425
00426 for (c = 1; c <= GD_n_cluster(g); c++)
00427 keepout_othernodes(GD_clust(g)[c]);
00428 }
00429
00430
00431
00432
00433
00434
00435
00436 static void contain_subclust(graph_t * g)
00437 {
00438 int c;
00439 graph_t *subg;
00440
00441 make_lrvn(g);
00442 for (c = 1; c <= GD_n_cluster(g); c++) {
00443 subg = GD_clust(g)[c];
00444 make_lrvn(subg);
00445 make_aux_edge(GD_ln(g), GD_ln(subg),
00446 CL_OFFSET + GD_border(g)[LEFT_IX].x, 0);
00447 make_aux_edge(GD_rn(subg), GD_rn(g),
00448 CL_OFFSET + GD_border(g)[RIGHT_IX].x, 0);
00449 contain_subclust(subg);
00450 }
00451 }
00452
00453
00454
00455
00456
00457
00458
00459 static void separate_subclust(graph_t * g)
00460 {
00461 int i, j;
00462 graph_t *low, *high;
00463 graph_t *left, *right;
00464
00465 for (i = 1; i <= GD_n_cluster(g); i++)
00466 make_lrvn(GD_clust(g)[i]);
00467 for (i = 1; i <= GD_n_cluster(g); i++) {
00468 for (j = i + 1; j <= GD_n_cluster(g); j++) {
00469 low = GD_clust(g)[i];
00470 high = GD_clust(g)[j];
00471 if (GD_minrank(low) > GD_minrank(high)) {
00472 graph_t *temp = low;
00473 low = high;
00474 high = temp;
00475 }
00476 if (GD_maxrank(low) < GD_minrank(high))
00477 continue;
00478 if (ND_order(GD_rank(low)[GD_minrank(high)].v[0])
00479 < ND_order(GD_rank(high)[GD_minrank(high)].v[0])) {
00480 left = low;
00481 right = high;
00482 } else {
00483 left = high;
00484 right = low;
00485 }
00486 make_aux_edge(GD_rn(left), GD_ln(right), CL_OFFSET, 0);
00487 }
00488 separate_subclust(GD_clust(g)[i]);
00489 }
00490 }
00491
00492
00493
00494
00495
00496
00497 static void pos_clusters(graph_t * g)
00498 {
00499 if (GD_n_cluster(g) > 0) {
00500 contain_clustnodes(g);
00501 keepout_othernodes(g);
00502 contain_subclust(g);
00503 separate_subclust(g);
00504 }
00505 }
00506
00507 static void compress_graph(graph_t * g)
00508 {
00509 double x;
00510 point p;
00511
00512 if (GD_drawing(g)->ratio_kind != R_COMPRESS)
00513 return;
00514 p = GD_drawing(g)->size;
00515 if (p.x * p.y <= 1)
00516 return;
00517 contain_nodes(g);
00518 if (GD_flip(g) == FALSE)
00519 x = p.x;
00520 else
00521 x = p.y;
00522 make_aux_edge(GD_ln(g), GD_rn(g), (int) x, 1000);
00523 }
00524
00525 static void create_aux_edges(graph_t * g)
00526 {
00527 allocate_aux_edges(g);
00528 make_LR_constraints(g);
00529 make_edge_pairs(g);
00530 pos_clusters(g);
00531 compress_graph(g);
00532 }
00533
00534 static void remove_aux_edges(graph_t * g)
00535 {
00536 int i;
00537 node_t *n, *nnext, *nprev;
00538 edge_t *e;
00539
00540 for (n = GD_nlist(g); n; n = ND_next(n)) {
00541 for (i = 0; (e = ND_out(n).list[i]); i++)
00542 free(e);
00543 free_list(ND_out(n));
00544 free_list(ND_in(n));
00545 ND_out(n) = ND_save_out(n);
00546 ND_in(n) = ND_save_in(n);
00547 }
00548
00549 nprev = NULL;
00550 for (n = GD_nlist(g); n; n = nnext) {
00551 nnext = ND_next(n);
00552 if (ND_node_type(n) == SLACKNODE) {
00553 if (nprev)
00554 ND_next(nprev) = nnext;
00555 else
00556 GD_nlist(g) = nnext;
00557 free(n);
00558 } else
00559 nprev = n;
00560 }
00561 GD_nlist(g)->u.prev = NULL;
00562 }
00563
00564
00565
00566
00567 static void
00568 set_xcoords(graph_t * g)
00569 {
00570 int i, j;
00571 node_t *v;
00572 rank_t *rank = GD_rank(g);
00573
00574 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
00575 for (j = 0; j < rank[i].n; j++) {
00576 v = rank[i].v[j];
00577 ND_coord_i(v).x = ND_rank(v);
00578 ND_rank(v) = i;
00579 }
00580 }
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596 static void adjustEqual(graph_t * g, int delta)
00597 {
00598 int r, avail, half, deltop, delbottom;
00599 graph_t *root = g->root;
00600 rank_t *rank = GD_rank(root);
00601 int maxr = GD_maxrank(g);
00602 int minr = GD_minrank(g);
00603
00604 deltop = rank[minr].ht2 - GD_ht2(g);
00605 delbottom = rank[maxr].ht1 - GD_ht1(g);
00606 avail = deltop + delbottom;
00607 if (avail >= delta) {
00608 half = (delta+1) / 2;
00609 if (deltop <= delbottom) {
00610 if (half <= deltop) {
00611 GD_ht2(g) += half;
00612 GD_ht1(g) += (delta - half);
00613 }
00614 else {
00615 GD_ht2(g) += deltop;
00616 GD_ht1(g) += (delta - deltop);
00617 }
00618 }
00619 else {
00620 if (half <= delbottom) {
00621 GD_ht1(g) += half;
00622 GD_ht2(g) += (delta - half);
00623 }
00624 else {
00625 GD_ht1(g) += delbottom;
00626 GD_ht2(g) += (delta - delbottom);
00627 }
00628 }
00629 }
00630 else {
00631 int gaps = maxr - minr + 2;
00632 int yoff = (delta + (gaps - 1)) / gaps;
00633 int y = yoff;
00634 for (r = GD_maxrank(root) - 1; r >= GD_minrank(root); r--) {
00635 if (rank[r].n > 0)
00636 rank[r].v[0]->u.coord.y += y;
00637 y += yoff;
00638 }
00639 GD_ht2(g) += yoff;
00640 GD_ht1(g) += yoff;
00641 }
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652 static void adjustSimple(graph_t * g, int delta)
00653 {
00654 int r, bottom, deltop, delbottom;
00655 graph_t *root = g->root;
00656 rank_t *rank = GD_rank(root);
00657 int maxr = GD_maxrank(g);
00658 int minr = GD_minrank(g);
00659
00660 bottom = (delta+1) / 2;
00661 delbottom = GD_ht1(g) + bottom - rank[maxr].ht1;
00662 if (delbottom > 0) {
00663 for (r = maxr; r >= minr; r--) {
00664 if (rank[r].n > 0)
00665 rank[r].v[0]->u.coord.y += delbottom;
00666 }
00667 deltop = GD_ht2(g) + (delta-bottom) + delbottom - rank[minr].ht2;
00668 }
00669 else
00670 deltop = GD_ht2(g) + (delta-bottom) - rank[minr].ht2;
00671 if (deltop > 0) {
00672 for (r = minr-1; r >= GD_minrank(root); r--) {
00673 if (rank[r].n > 0)
00674 rank[r].v[0]->u.coord.y += deltop;
00675 }
00676 }
00677 GD_ht2(g) += (delta - bottom);
00678 GD_ht1(g) += bottom;
00679 }
00680
00681
00682
00683
00684
00685
00686
00687 static void adjustRanks(graph_t * g, int equal)
00688 {
00689 int lht;
00690 int rht;
00691 int delta, maxr, minr;
00692 int c, ht1, ht2;
00693 rank_t *rank = GD_rank(g->root);
00694
00695 ht1 = GD_ht1(g);
00696 ht2 = GD_ht2(g);
00697
00698 for (c = 1; c <= GD_n_cluster(g); c++) {
00699 graph_t *subg = GD_clust(g)[c];
00700 adjustRanks(subg, equal);
00701 if (GD_maxrank(subg) == GD_maxrank(g))
00702 ht1 = MAX(ht1, GD_ht1(subg) + CL_OFFSET);
00703 if (GD_minrank(subg) == GD_minrank(g))
00704 ht2 = MAX(ht2, GD_ht2(subg) + CL_OFFSET);
00705 }
00706
00707 GD_ht1(g) = ht1;
00708 GD_ht2(g) = ht2;
00709
00710 if ((g != g->root) && GD_label(g)) {
00711 lht = MAX(GD_border(g)[LEFT_IX].y, GD_border(g)[RIGHT_IX].y);
00712 maxr = GD_maxrank(g);
00713 minr = GD_minrank(g);
00714 rht =
00715 ND_coord_i(rank[minr].v[0]).y - ND_coord_i(rank[maxr].v[0]).y;
00716 delta = lht - (rht + ht1 + ht2);
00717 if (delta > 0) {
00718 if (equal)
00719 adjustEqual(g, delta);
00720 else
00721 adjustSimple(g, delta);
00722 }
00723 }
00724
00725
00726 if (g != g->root) {
00727 rank[GD_minrank(g)].ht2 = MAX(rank[GD_minrank(g)].ht2, GD_ht2(g));
00728 rank[GD_maxrank(g)].ht1 = MAX(rank[GD_maxrank(g)].ht1, GD_ht1(g));
00729 }
00730 }
00731
00732
00733
00734
00735
00736
00737
00738 static int clust_ht(Agraph_t * g)
00739 {
00740 int c, ht1, ht2;
00741 graph_t *subg;
00742 rank_t *rank = GD_rank(g->root);
00743 int haveClustLabel = 0;
00744
00745 ht1 = GD_ht1(g);
00746 ht2 = GD_ht2(g);
00747
00748
00749 for (c = 1; c <= GD_n_cluster(g); c++) {
00750 subg = GD_clust(g)[c];
00751 haveClustLabel |= clust_ht(subg);
00752 if (GD_maxrank(subg) == GD_maxrank(g))
00753 ht1 = MAX(ht1, GD_ht1(subg) + CL_OFFSET);
00754 if (GD_minrank(subg) == GD_minrank(g))
00755 ht2 = MAX(ht2, GD_ht2(subg) + CL_OFFSET);
00756 }
00757
00758
00759
00760 if ((g != g->root) && GD_label(g)) {
00761 haveClustLabel = 1;
00762 if (!GD_flip(g->root)) {
00763 ht1 += GD_border(g)[BOTTOM_IX].y;
00764 ht2 += GD_border(g)[TOP_IX].y;
00765 }
00766 }
00767 GD_ht1(g) = ht1;
00768 GD_ht2(g) = ht2;
00769
00770
00771 if (g != g->root) {
00772 rank[GD_minrank(g)].ht2 = MAX(rank[GD_minrank(g)].ht2, ht2);
00773 rank[GD_maxrank(g)].ht1 = MAX(rank[GD_maxrank(g)].ht1, ht1);
00774 }
00775
00776 return haveClustLabel;
00777 }
00778
00779
00780 static void set_ycoords(graph_t * g)
00781 {
00782 int i, j, r, ht2, maxht, delta, d0, d1;
00783 node_t *n;
00784 edge_t *e;
00785 rank_t *rank = GD_rank(g);
00786 graph_t *clust;
00787 int lbl;
00788
00789 ht2 = maxht = 0;
00790
00791
00792 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00793 for (i = 0; i < rank[r].n; i++) {
00794 n = rank[r].v[i];
00795
00796
00797 ht2 = (ND_ht_i(n) + 1) / 2;
00798
00799
00800
00801 if (ND_other(n).list)
00802 for (j = 0; (e = ND_other(n).list[j]); j++) {
00803 if (e->tail == e->head) {
00804 if (ED_label(e))
00805 ht2 = MAX(ht2, ED_label(e)->dimen.y / 2);
00806 }
00807 }
00808
00809
00810 if (rank[r].pht2 < ht2)
00811 rank[r].pht2 = rank[r].ht2 = ht2;
00812 if (rank[r].pht1 < ht2)
00813 rank[r].pht1 = rank[r].ht1 = ht2;
00814
00815
00816 if ((clust = ND_clust(n))) {
00817 int yoff = (clust == g ? 0 : CL_OFFSET);
00818 if (ND_rank(n) == GD_minrank(clust))
00819 GD_ht2(clust) = MAX(GD_ht2(clust), ht2 + yoff);
00820 if (ND_rank(n) == GD_maxrank(clust))
00821 GD_ht1(clust) = MAX(GD_ht1(clust), ht2 + yoff);
00822 }
00823 }
00824 }
00825
00826
00827 lbl = clust_ht(g);
00828
00829
00830 maxht = 0;
00831 r = GD_maxrank(g);
00832 rank[r].v[0]->u.coord.y = rank[r].ht1;
00833 while (--r >= GD_minrank(g)) {
00834 d0 = rank[r + 1].pht2 + rank[r].pht1 + GD_ranksep(g);
00835 d1 = rank[r + 1].ht2 + rank[r].ht1 + CL_OFFSET;
00836 delta = MAX(d0, d1);
00837 if (rank[r].n > 0)
00838 rank[r].v[0]->u.coord.y = rank[r + 1].v[0]->u.coord.y + delta;
00839 #ifdef DEBUG
00840 else
00841 fprintf(stderr, "dot set_ycoords: rank %d is empty\n",
00842 rank[r].n);
00843 #endif
00844 maxht = MAX(maxht, delta);
00845 }
00846
00847
00848 if (GD_exact_ranksep(g)) {
00849 for (r = GD_maxrank(g) - 1; r >= GD_minrank(g); r--)
00850 if (rank[r].n > 0)
00851 rank[r].v[0]->u.coord.y =
00852 rank[r + 1].v[0]->u.coord.y + maxht;
00853 }
00854
00855 if (lbl && GD_flip(g))
00856 adjustRanks(g, GD_exact_ranksep(g));
00857
00858
00859 for (n = GD_nlist(g); n; n = ND_next(n))
00860 ND_coord_i(n).y = rank[ND_rank(n)].v[0]->u.coord.y;
00861 }
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 static void dot_compute_bb(graph_t * g, graph_t * root)
00872 {
00873 int r, c, x, offset;
00874 node_t *v;
00875 point LL, UR;
00876
00877 if (g == g->root) {
00878 LL.x = INT_MAX;
00879 UR.x = -INT_MAX;
00880 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
00881 if (GD_rank(g)[r].n == 0)
00882 continue;
00883 if ((v = GD_rank(g)[r].v[0]) == NULL)
00884 continue;
00885 if (ND_node_type(v) == NORMAL) {
00886 x = ND_coord_i(v).x - ND_lw_i(v);
00887 LL.x = MIN(LL.x, x);
00888 }
00889 v = GD_rank(g)[r].v[GD_rank(g)[r].n - 1];
00890 if (ND_node_type(v) == NORMAL) {
00891 x = ND_coord_i(v).x + ND_rw_i(v);
00892 UR.x = MAX(UR.x, x);
00893 }
00894 }
00895 offset = CL_OFFSET;
00896 for (c = 1; c <= GD_n_cluster(g); c++) {
00897 x = GD_clust(g)[c]->u.bb.LL.x - offset;
00898 LL.x = MIN(LL.x, x);
00899 x = GD_clust(g)[c]->u.bb.UR.x + offset;
00900 UR.x = MAX(UR.x, x);
00901 }
00902 } else {
00903 LL.x = ND_rank(GD_ln(g));
00904 UR.x = ND_rank(GD_rn(g));
00905 }
00906 LL.y = ND_rank(root)[GD_maxrank(g)].v[0]->u.coord.y - GD_ht1(g);
00907 UR.y = ND_rank(root)[GD_minrank(g)].v[0]->u.coord.y + GD_ht2(g);
00908 GD_bb(g).LL = LL;
00909 GD_bb(g).UR = UR;
00910 }
00911
00912 static void rec_bb(graph_t * g, graph_t * root)
00913 {
00914 int c;
00915 for (c = 1; c <= GD_n_cluster(g); c++)
00916 rec_bb(GD_clust(g)[c], root);
00917 dot_compute_bb(g, root);
00918 }
00919
00920
00921
00922
00923
00924 static void scale_bb(graph_t * g, graph_t * root, double xf, double yf)
00925 {
00926 int c;
00927
00928 for (c = 1; c <= GD_n_cluster(g); c++)
00929 scale_bb(GD_clust(g)[c], root, xf, yf);
00930 GD_bb(g).LL.x *= xf;
00931 GD_bb(g).LL.y *= yf;
00932 GD_bb(g).UR.x *= xf;
00933 GD_bb(g).UR.y *= yf;
00934 }
00935
00936
00937
00938
00939
00940
00941 static void set_aspect(graph_t * g)
00942 {
00943 double xf = 0.0, yf = 0.0, actual, desired;
00944 node_t *n;
00945 boolean scale_it, filled;
00946 point sz;
00947
00948 rec_bb(g, g);
00949 if ((GD_maxrank(g) > 0) && (GD_drawing(g)->ratio_kind)) {
00950 sz.x = GD_bb(g).UR.x - GD_bb(g).LL.x;
00951 sz.y = GD_bb(g).UR.y - GD_bb(g).LL.y;
00952 if (GD_flip(g)) {
00953 int t = sz.x;
00954 sz.x = sz.y;
00955 sz.y = t;
00956 }
00957 scale_it = TRUE;
00958 if (GD_drawing(g)->ratio_kind == R_AUTO)
00959 filled = idealsize(g, .5);
00960 else
00961 filled = (GD_drawing(g)->ratio_kind == R_FILL);
00962 if (filled) {
00963
00964 if (GD_drawing(g)->size.x <= 0)
00965 scale_it = FALSE;
00966 else {
00967 xf = (double) GD_drawing(g)->size.x / (double) sz.x;
00968 yf = (double) GD_drawing(g)->size.y / (double) sz.y;
00969 if ((xf < 1.0) || (yf < 1.0)) {
00970 if (xf < yf) {
00971 yf = yf / xf;
00972 xf = 1.0;
00973 } else {
00974 xf = xf / yf;
00975 yf = 1.0;
00976 }
00977 }
00978 }
00979 } else if (GD_drawing(g)->ratio_kind == R_EXPAND) {
00980 if (GD_drawing(g)->size.x <= 0)
00981 scale_it = FALSE;
00982 else {
00983 xf = (double) GD_drawing(g)->size.x /
00984 (double) GD_bb(g).UR.x;
00985 yf = (double) GD_drawing(g)->size.y /
00986 (double) GD_bb(g).UR.y;
00987 if ((xf > 1.0) && (yf > 1.0)) {
00988 double scale = MIN(xf, yf);
00989 xf = yf = scale;
00990 } else
00991 scale_it = FALSE;
00992 }
00993 } else if (GD_drawing(g)->ratio_kind == R_VALUE) {
00994 desired = GD_drawing(g)->ratio;
00995 actual = ((double) sz.y) / ((double) sz.x);
00996 if (actual < desired) {
00997 yf = desired / actual;
00998 xf = 1.0;
00999 } else {
01000 xf = actual / desired;
01001 yf = 1.0;
01002 }
01003 } else
01004 scale_it = FALSE;
01005 if (scale_it) {
01006 if (GD_flip(g)) {
01007 double t = xf;
01008 xf = yf;
01009 yf = t;
01010 }
01011 for (n = GD_nlist(g); n; n = ND_next(n)) {
01012 ND_coord_i(n).x = ND_coord_i(n).x * xf;
01013 ND_coord_i(n).y = ND_coord_i(n).y * yf;
01014 }
01015 scale_bb(g, g, xf, yf);
01016 }
01017 }
01018 }
01019
01020 static point resize_leaf(node_t * leaf, point lbound)
01021 {
01022 dot_nodesize(leaf, GD_flip(leaf->graph));
01023 ND_coord_i(leaf).y = lbound.y;
01024 ND_coord_i(leaf).x = lbound.x + ND_lw_i(leaf);
01025 lbound.x =
01026 lbound.x + ND_lw_i(leaf) + ND_rw_i(leaf) + GD_nodesep(leaf->graph);
01027 return lbound;
01028 }
01029
01030 static point place_leaf(node_t * leaf, point lbound, int order)
01031 {
01032 node_t *leader;
01033 graph_t *g = leaf->graph;
01034
01035 leader = UF_find(leaf);
01036 if (leaf != leader)
01037 fast_nodeapp(leader, leaf);
01038 ND_order(leaf) = order;
01039 ND_rank(leaf) = ND_rank(leader);
01040 GD_rank(g)[ND_rank(leaf)].v[ND_order(leaf)] = leaf;
01041 return resize_leaf(leaf, lbound);
01042 }
01043
01044
01045 static void make_leafslots(graph_t * g)
01046 {
01047 int i, j, r;
01048 node_t *v;
01049
01050 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
01051 j = 0;
01052 for (i = 0; i < GD_rank(g)[r].n; i++) {
01053 v = GD_rank(g)[r].v[i];
01054 ND_order(v) = j;
01055 if (ND_ranktype(v) == LEAFSET)
01056 j = j + ND_UF_size(v);
01057 else
01058 j++;
01059 }
01060 if (j <= GD_rank(g)[r].n)
01061 continue;
01062 GD_rank(g)[r].v = ALLOC(j + 1, GD_rank(g)[r].v, node_t *);
01063 for (i = GD_rank(g)[r].n - 1; i >= 0; i--) {
01064 v = GD_rank(g)[r].v[i];
01065 GD_rank(g)[r].v[ND_order(v)] = v;
01066 }
01067 GD_rank(g)[r].n = j;
01068 GD_rank(g)[r].v[j] = NULL;
01069 }
01070 }
01071
01072 static void do_leaves(graph_t * g, node_t * leader)
01073 {
01074 int j;
01075 point lbound;
01076 node_t *n;
01077 edge_t *e;
01078
01079 if (ND_UF_size(leader) <= 1)
01080 return;
01081 lbound.x = ND_coord_i(leader).x - ND_lw_i(leader);
01082 lbound.y = ND_coord_i(leader).y;
01083 lbound = resize_leaf(leader, lbound);
01084 if (ND_out(leader).size > 0) {
01085 n = ND_out(leader).list[0]->head;
01086 j = ND_order(leader) + 1;
01087 for (e = agfstin(g, n); e; e = agnxtin(g, e)) {
01088 if ((e->tail != leader) && (UF_find(e->tail) == leader)) {
01089 lbound = place_leaf(e->tail, lbound, j++);
01090 unmerge_oneway(e);
01091 elist_append(e, ND_in(e->head));
01092 }
01093 }
01094 } else {
01095 n = ND_in(leader).list[0]->tail;
01096 j = ND_order(leader) + 1;
01097 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
01098 if ((e->head != leader) && (UF_find(e->head) == leader)) {
01099 lbound = place_leaf(e->head, lbound, j++);
01100 unmerge_oneway(e);
01101 elist_append(e, ND_out(e->tail));
01102 }
01103 }
01104 }
01105 }
01106
01107 int ports_eq(edge_t * e, edge_t * f)
01108 {
01109 return ((ED_head_port(e).defined == ED_head_port(f).defined)
01110 && (((ED_head_port(e).p.x == ED_head_port(f).p.x) &&
01111 (ED_head_port(e).p.y == ED_head_port(f).p.y))
01112 || (ED_head_port(e).defined == FALSE))
01113 && (((ED_tail_port(e).p.x == ED_tail_port(f).p.x) &&
01114 (ED_tail_port(e).p.y == ED_tail_port(f).p.y))
01115 || (ED_tail_port(e).defined == FALSE))
01116 );
01117 }
01118
01119 static void expand_leaves(graph_t * g)
01120 {
01121 int i, d;
01122 node_t *n;
01123 edge_t *e, *f;
01124
01125 make_leafslots(g);
01126 for (n = GD_nlist(g); n; n = ND_next(n)) {
01127 if (ND_inleaf(n))
01128 do_leaves(g, ND_inleaf(n));
01129 if (ND_outleaf(n))
01130 do_leaves(g, ND_outleaf(n));
01131 if (ND_other(n).list)
01132 for (i = 0; (e = ND_other(n).list[i]); i++) {
01133 if ((d = ND_rank(e->head) - ND_rank(e->head)) == 0)
01134 continue;
01135 f = ED_to_orig(e);
01136 if (ports_eq(e, f) == FALSE) {
01137 zapinlist(&(ND_other(n)), e);
01138 if (d == 1)
01139 fast_edge(e);
01140
01141 i--;
01142 }
01143 }
01144 }
01145 }
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161 static void make_lrvn(graph_t * g)
01162 {
01163 node_t *ln, *rn;
01164
01165 if (GD_ln(g))
01166 return;
01167 ln = virtual_node(g->root);
01168 ND_node_type(ln) = SLACKNODE;
01169 rn = virtual_node(g->root);
01170 ND_node_type(rn) = SLACKNODE;
01171
01172 if (GD_label(g) && (g != g->root) && !GD_flip(g->root)) {
01173 int w = MAX(GD_border(g)[BOTTOM_IX].x, GD_border(g)[TOP_IX].x);
01174 make_aux_edge(ln, rn, w, 0);
01175 }
01176
01177 GD_ln(g) = ln;
01178 GD_rn(g) = rn;
01179 }
01180
01181
01182
01183
01184
01185 static void contain_nodes(graph_t * g)
01186 {
01187 int r;
01188 node_t *ln, *rn, *v;
01189
01190 make_lrvn(g);
01191 ln = GD_ln(g);
01192 rn = GD_rn(g);
01193 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
01194 if (GD_rank(g)[r].n == 0)
01195 continue;
01196 v = GD_rank(g)[r].v[0];
01197 if (v == NULL) {
01198 agerr(AGERR, "contain_nodes clust %s rank %d missing node\n",
01199 g->name, r);
01200 continue;
01201 }
01202 make_aux_edge(ln, v,
01203 ND_lw_i(v) + CL_OFFSET + GD_border(g)[LEFT_IX].x, 0);
01204 v = GD_rank(g)[r].v[GD_rank(g)[r].n - 1];
01205 make_aux_edge(v, rn,
01206 ND_rw_i(v) + CL_OFFSET + GD_border(g)[RIGHT_IX].x,
01207 0);
01208 }
01209 }
01210
01211
01212
01213
01214
01215 static boolean idealsize(graph_t * g, double minallowed)
01216 {
01217 double xf, yf, f, R;
01218 point b, relpage, margin;
01219
01220
01221 relpage = GD_drawing(g)->page;
01222 if (relpage.x == 0)
01223 return FALSE;
01224 margin = GD_drawing(g)->margin;
01225 relpage = sub_points(relpage, margin);
01226 relpage = sub_points(relpage, margin);
01227 b.x = GD_bb(g).UR.x;
01228 b.y = GD_bb(g).UR.y;
01229 xf = (double) relpage.x / b.x;
01230 yf = (double) relpage.y / b.y;
01231 if ((xf >= 1.0) && (yf >= 1.0))
01232 return FALSE;
01233
01234 f = MIN(xf, yf);
01235 xf = yf = MAX(f, minallowed);
01236
01237 R = ceil((xf * b.x) / relpage.x);
01238 xf = ((R * relpage.x) / b.x);
01239 R = ceil((yf * b.y) / relpage.y);
01240 yf = ((R * relpage.y) / b.y);
01241 GD_drawing(g)->size.x = b.x * xf;
01242 GD_drawing(g)->size.y = b.y * yf;
01243 return TRUE;
01244 }