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
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define FDP_PRIVATE 1
00036
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 #ifdef HAVE_LIMITS_H
00041 #include <limits.h>
00042 #else
00043 #ifdef HAVE_VALUES_H
00044 #include <values.h>
00045 #endif
00046 #endif
00047 #include <tlayout.h>
00048 #include <neatoprocs.h>
00049 #include <adjust.h>
00050 #include <comp.h>
00051 #include <pack.h>
00052 #include <assert.h>
00053 #include <clusteredges.h>
00054 #include <dbg.h>
00055
00056 typedef struct {
00057 graph_t* rootg;
00058 attrsym_t *G_coord;
00059 attrsym_t *G_width;
00060 attrsym_t *G_height;
00061 int gid;
00062 pack_info pack;
00063 } layout_info;
00064
00065 #define NEW_EDGE(e) (ED_to_virt(e) == 0)
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 static void
00077 finalCC(graph_t * g, int c_cnt, graph_t ** cc, point * pts, graph_t * rg,
00078 layout_info* infop)
00079 {
00080 attrsym_t * G_width = infop->G_width;
00081 attrsym_t * G_height = infop->G_height;
00082 graph_t *cg;
00083 box b, bb;
00084 boxf bbf;
00085 point pt;
00086 int margin;
00087 graph_t **cp = cc;
00088 point *pp = pts;
00089 int isRoot = (rg == infop->rootg);
00090 int isEmpty = 0;
00091
00092
00093 if (c_cnt) {
00094 cg = *cp++;
00095 bb = GD_bb(cg);
00096 if (c_cnt > 1) {
00097 pt = *pp++;
00098 bb.LL.x += pt.x;
00099 bb.LL.y += pt.y;
00100 bb.UR.x += pt.x;
00101 bb.UR.y += pt.y;
00102 while ((cg = *cp++)) {
00103 b = GD_bb(cg);
00104 pt = *pp++;
00105 b.LL.x += pt.x;
00106 b.LL.y += pt.y;
00107 b.UR.x += pt.x;
00108 b.UR.y += pt.y;
00109 bb.LL.x = MIN(bb.LL.x, b.LL.x);
00110 bb.LL.y = MIN(bb.LL.y, b.LL.y);
00111 bb.UR.x = MAX(bb.UR.x, b.UR.x);
00112 bb.UR.y = MAX(bb.UR.y, b.UR.y);
00113 }
00114 }
00115 } else {
00116 bb.LL.x = 0;
00117 bb.LL.y = 0;
00118 bb.UR.x = late_int(rg, G_width, POINTS(DEFAULT_NODEWIDTH), 3);
00119 bb.UR.y = late_int(rg, G_height, POINTS(DEFAULT_NODEHEIGHT), 3);
00120 isEmpty = 1;
00121 }
00122
00123 if (GD_label(rg)) {
00124 point p;
00125 int d;
00126
00127 isEmpty = 0;
00128 PF2P(GD_label(rg)->dimen, p);
00129 d = p.x - (bb.UR.x - bb.LL.x);
00130 if (d > 0) {
00131 d /= 2;
00132 bb.LL.x -= d;
00133 bb.UR.x += d;
00134 }
00135 }
00136
00137 if (isRoot || isEmpty)
00138 margin = 0;
00139 else
00140 margin = CL_OFFSET;
00141 pt.x = -bb.LL.x + margin;
00142 pt.y = -bb.LL.y + margin + GD_border(rg)[BOTTOM_IX].y;
00143 bb.LL.x = 0;
00144 bb.LL.y = 0;
00145 bb.UR.x += pt.x + margin;
00146 bb.UR.y += pt.y + margin + GD_border(rg)[TOP_IX].y;
00147
00148
00149 if (c_cnt) {
00150 cp = cc;
00151 pp = pts;
00152 while ((cg = *cp++)) {
00153 point p;
00154 node_t *n;
00155 pointf del;
00156
00157 if (pp) {
00158 p = *pp++;
00159 p.x += pt.x;
00160 p.y += pt.y;
00161 } else {
00162 p = pt;
00163 }
00164 del = cvt2ptf(p);
00165 for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) {
00166 ND_pos(n)[0] += del.x;
00167 ND_pos(n)[1] += del.y;
00168 }
00169 }
00170 }
00171
00172 bbf.LL = cvt2ptf(bb.LL);
00173 bbf.UR = cvt2ptf(bb.UR);
00174 BB(g) = bbf;
00175
00176 }
00177
00178
00179
00180
00181
00182 static node_t *mkDeriveNode(graph_t * dg, char *name)
00183 {
00184 node_t *dn;
00185
00186 dn = agnode(dg, name);
00187 ND_alg(dn) = (void *) NEW(dndata);
00188 ND_pos(dn) = N_GNEW(GD_ndim(dg), double);
00189
00190 return dn;
00191 }
00192
00193 static void freeDeriveNode(node_t * n)
00194 {
00195 free(ND_alg(n));
00196 free(ND_pos(n));
00197 }
00198
00199 static void freeGData(graph_t * g)
00200 {
00201 free(GD_alg(g));
00202 }
00203
00204 static void freeDerivedGraph(graph_t * g, graph_t ** cc)
00205 {
00206 graph_t *cg;
00207 node_t *dn;
00208 node_t *dnxt;
00209 edge_t *e;
00210
00211 while ((cg = *cc++)) {
00212 freeGData(cg);
00213 }
00214 if (PORTS(g))
00215 free(PORTS(g));
00216 freeGData(g);
00217 for (dn = agfstnode(g); dn; dn = dnxt) {
00218 dnxt = agnxtnode(g, dn);
00219 for (e = agfstout(g, dn); e; e = agnxtout(g, e)) {
00220 free (ED_to_virt(e));
00221 }
00222 freeDeriveNode(dn);
00223 }
00224 agclose(g);
00225 }
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 static void evalPositions(graph_t * g, graph_t* rootg)
00237 {
00238 int i;
00239 graph_t *subg;
00240 node_t *n;
00241 boxf bb;
00242 boxf sbb;
00243
00244 bb = BB(g);
00245
00246
00247 if (g != rootg) {
00248 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00249 if (PARENT(n) != g)
00250 continue;
00251 ND_pos(n)[0] += bb.LL.x;
00252 ND_pos(n)[1] += bb.LL.y;
00253 }
00254 }
00255
00256
00257 for (i = 1; i <= GD_n_cluster(g); i++) {
00258 subg = GD_clust(g)[i];
00259 if (g != rootg) {
00260 sbb = BB(subg);
00261 sbb.LL.x += bb.LL.x;
00262 sbb.LL.y += bb.LL.y;
00263 sbb.UR.x += bb.LL.x;
00264 sbb.UR.y += bb.LL.y;
00265 BB(subg) = sbb;
00266 }
00267 evalPositions(subg, rootg);
00268 }
00269 }
00270
00271 #define CL_CHUNK 10
00272
00273 typedef struct {
00274 graph_t **cl;
00275 int sz;
00276 int cnt;
00277 } clist_t;
00278
00279 static void initCList(clist_t * clist)
00280 {
00281 clist->cl = 0;
00282 clist->sz = 0;
00283 clist->cnt = 0;
00284 }
00285
00286
00287
00288
00289
00290
00291
00292 static void addCluster(clist_t * clist, graph_t * subg)
00293 {
00294 clist->cnt++;
00295 if (clist->cnt >= clist->sz) {
00296 clist->sz += CL_CHUNK;
00297 clist->cl = RALLOC(clist->sz, clist->cl, graph_t *);
00298 }
00299 clist->cl[clist->cnt] = subg;
00300 }
00301
00302 #define BSZ 1000
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 static char *portName(graph_t * g, bport_t * p)
00313 {
00314 edge_t *e = p->e;
00315 node_t *h = e->head;
00316 node_t *t = e->tail;
00317 static char buf[BSZ + 1];
00318 int len = 8;
00319
00320 len += strlen(g->name) + strlen(h->name) + strlen(t->name);
00321 if (len >= BSZ)
00322 sprintf(buf, "_port_%s_%s_%s_%d", g->name, t->name, h->name,
00323 e->id);
00324 else
00325 sprintf(buf, "_port_%s_(%d)_(%d)_%d", g->name, ND_id(t), ND_id(h),
00326 e->id);
00327 return buf;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 static void chkPos(graph_t* g, node_t* n, layout_info* infop, boxf* bbp)
00339 {
00340 char *p;
00341 char *pp;
00342 boxf bb;
00343 char c;
00344 graph_t *parent;
00345 attrsym_t *G_coord = infop->G_coord;
00346
00347 p = agxget(g, G_coord->index);
00348 if (p[0]) {
00349 if (g != infop->rootg) {
00350 parent =
00351 agusergraph((agfstin(g->meta_node->graph, g->meta_node))->
00352 tail);
00353 pp = agxget(parent, G_coord->index);
00354 if ((pp == p) || !strcmp(p, pp))
00355 return;
00356 }
00357 c = '\0';
00358 if (sscanf(p, "%lf,%lf,%lf,%lf%c",
00359 &bb.LL.x, &bb.LL.y, &bb.UR.x, &bb.UR.y, &c) >= 4) {
00360 if (PSinputscale > 0.0) {
00361 bb.LL.x /= PSinputscale;
00362 bb.LL.y /= PSinputscale;
00363 bb.UR.x /= PSinputscale;
00364 bb.UR.y /= PSinputscale;
00365 }
00366 if (c == '!')
00367 ND_pinned(n) = P_PIN;
00368 else if (c == '?')
00369 ND_pinned(n) = P_FIX;
00370 else
00371 ND_pinned(n) = P_SET;
00372 *bbp = bb;
00373 } else
00374 agerr(AGWARN, "graph %s, coord %s, expected four doubles\n",
00375 g->name, p);
00376 }
00377 }
00378
00379
00380
00381
00382
00383 static void addEdge(edge_t * de, edge_t * e)
00384 {
00385 short cnt = ED_count(de);
00386 edge_t **el;
00387
00388 el = (edge_t **) (ED_to_virt(de));
00389 el = ALLOC(cnt + 1, el, edge_t *);
00390 el[cnt] = e;
00391 ED_to_virt(de) = (edge_t *) el;
00392 ED_count(de)++;
00393 }
00394
00395
00396
00397
00398 static void
00399 copyAttr (graph_t* g, graph_t* dg, char* attr)
00400 {
00401 char* ov_val;
00402 Agsym_t* ov;
00403
00404 if ((ov = agfindattr(g, attr))) {
00405 ov_val = agxget(g,ov->index);
00406 ov = agfindattr(dg, attr);
00407 if (ov)
00408 agxset (dg, ov->index, ov_val);
00409 else
00410 agraphattr(dg, attr, ov_val);
00411 }
00412 }
00413
00414
00415
00416
00417
00418
00419
00420
00421 static graph_t *deriveGraph(graph_t * g, layout_info * infop)
00422 {
00423 graph_t *dg;
00424 node_t *dn;
00425 graph_t *subg;
00426 char name[100];
00427 bport_t *pp;
00428 node_t *n;
00429 edge_t *de;
00430 int i, id = 0;
00431
00432 sprintf(name, "_dg_%d", infop->gid++);
00433 if (Verbose >= 2)
00434 fprintf(stderr, "derive graph %s of %s\n", name, g->name);
00435 dg = agopen(name, AGRAPHSTRICT);
00436 GD_alg(dg) = (void *) NEW(gdata);
00437 #ifdef DEBUG
00438 GORIG(dg) = g;
00439 #endif
00440 GD_ndim(dg) = GD_ndim(g);
00441
00442
00443
00444 copyAttr(g,dg,"overlap");
00445 copyAttr(g,dg,"sep");
00446 copyAttr(g,dg,"K");
00447
00448
00449 for (i = 1; i <= GD_n_cluster(g); i++) {
00450 boxf fix_bb = {{ MAXDOUBLE, MAXDOUBLE },{ -MAXDOUBLE, -MAXDOUBLE }};
00451 subg = GD_clust(g)[i];
00452
00453 do_graph_label(subg);
00454 dn = mkDeriveNode(dg, subg->name);
00455 ND_clust(dn) = subg;
00456 ND_id(dn) = id++;
00457 if (infop->G_coord)
00458 chkPos(subg, dn, infop, &fix_bb);
00459 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00460 DNODE(n) = dn;
00461 #ifdef UNIMPLEMENTED
00462
00463
00464
00465
00466
00467 if (ND_pinned(n)) {
00468 fix_bb.LL.x = MIN(fix_bb.LL.x, ND_pos(n)[0]);
00469 fix_bb.LL.y = MIN(fix_bb.LL.y, ND_pos(n)[1]);
00470 fix_bb.UR.x = MAX(fix_bb.UR.x, ND_pos(n)[0]);
00471 fix_bb.UR.y = MAX(fix_bb.UR.y, ND_pos(n)[1]);
00472 ND_pinned(dn) = MAX(ND_pinned(dn), ND_pinned(n));
00473 }
00474 #endif
00475 }
00476 if (ND_pinned(dn)) {
00477 ND_pos(dn)[0] = (fix_bb.LL.x + fix_bb.UR.x) / 2;
00478 ND_pos(dn)[1] = (fix_bb.LL.y + fix_bb.UR.y) / 2;
00479 }
00480 }
00481
00482
00483 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00484 if (!DNODE(n)) {
00485 if (PARENT(n) && (PARENT(n) != GPARENT(g))) {
00486 agerr (AGERR, "node \"%s\" is contained in two non-comparable clusters \"%s\" and \"%s\"\n", n->name, g->name, PARENT(n)->name);
00487 exit (1);
00488 }
00489 PARENT(n) = g;
00490 if (IS_CLUST_NODE(n))
00491 continue;
00492 dn = mkDeriveNode(dg, n->name);
00493 DNODE(n) = dn;
00494 ND_id(dn) = id++;
00495 ND_width(dn) = ND_width(n);
00496 ND_height(dn) = ND_height(n);
00497 ND_xsize(dn) = ND_xsize(n);
00498 ND_ysize(dn) = ND_ysize(n);
00499 ND_shape(dn) = ND_shape(n);
00500 ND_shape_info(dn) = ND_shape_info(n);
00501 if (ND_pinned(n)) {
00502 ND_pos(dn)[0] = ND_pos(n)[0];
00503 ND_pos(dn)[1] = ND_pos(n)[1];
00504 ND_pinned(dn) = ND_pinned(n);
00505 }
00506 ANODE(dn) = n;
00507 }
00508 }
00509
00510
00511 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00512 edge_t *e;
00513 node_t *hd;
00514 node_t *tl = DNODE(n);
00515 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00516 hd = DNODE(e->head);
00517 if (hd == tl)
00518 continue;
00519 if (hd > tl)
00520 de = agedge(dg, tl, hd);
00521 else
00522 de = agedge(dg, hd, tl);
00523 ED_dist(de) = ED_dist(e);
00524 ED_factor(de) = ED_factor(e);
00525
00526 WDEG(hd)++;
00527 WDEG(tl)++;
00528 if (NEW_EDGE(de)) {
00529 DEG(hd)++;
00530 DEG(tl)++;
00531 }
00532 addEdge(de, e);
00533 }
00534 }
00535
00536
00537 if ((pp = PORTS(g))) {
00538 bport_t *pq;
00539 node_t *m;
00540 int sz = NPORTS(g);
00541
00542
00543 PORTS(dg) = pq = N_NEW(sz + 1, bport_t);
00544 sz = 0;
00545 while (pp->e) {
00546 m = DNODE(pp->n);
00547
00548 if (m) {
00549 dn = mkDeriveNode(dg, portName(g, pp));
00550 sz++;
00551 ND_id(dn) = id++;
00552 if (dn > m)
00553 de = agedge(dg, m, dn);
00554 else
00555 de = agedge(dg, dn, m);
00556 ED_dist(de) = ED_dist(pp->e);
00557 ED_factor(de) = ED_factor(pp->e);
00558 addEdge(de, pp->e);
00559 WDEG(dn)++;
00560 WDEG(m)++;
00561 DEG(dn)++;
00562 DEG(m)++;
00563 pq->n = dn;
00564 pq->alpha = pp->alpha;
00565 pq->e = de;
00566 pq++;
00567 }
00568 pp++;
00569 }
00570 NPORTS(dg) = sz;
00571 }
00572
00573 return dg;
00574 }
00575
00576 typedef struct {
00577 edge_t *e;
00578 double alpha;
00579 double dist2;
00580 } erec;
00581
00582
00583
00584
00585 static int ecmp(const void *v1, const void *v2)
00586 {
00587 erec *e1 = (erec *) v1;
00588 erec *e2 = (erec *) v2;
00589 if (e1->alpha > e2->alpha)
00590 return 1;
00591 else if (e1->alpha < e2->alpha)
00592 return -1;
00593 else if (e1->dist2 > e2->dist2)
00594 return 1;
00595 else if (e1->dist2 < e2->dist2)
00596 return -1;
00597 else
00598 return 0;
00599 }
00600
00601 #define ANG (M_PI/90)
00602
00603
00604
00605
00606
00607
00608 static erec *getEdgeList(node_t * n, graph_t * g)
00609 {
00610 erec *erecs;
00611 int deg = DEG(n);
00612 int i;
00613 double dx, dy;
00614 edge_t *e;
00615 node_t *m;
00616
00617
00618 erecs = N_NEW(deg + 1, erec);
00619 i = 0;
00620 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00621 if (e->head == n)
00622 m = e->tail;
00623 else
00624 m = e->head;
00625 dx = ND_pos(m)[0] - ND_pos(n)[0];
00626 dy = ND_pos(m)[1] - ND_pos(n)[1];
00627 erecs[i].e = e;
00628 erecs[i].alpha = atan2(dy, dx);
00629 erecs[i].dist2 = dx * dx + dy * dy;
00630 i++;
00631 }
00632 assert(i == deg);
00633 qsort(erecs, deg, sizeof(erec), ecmp);
00634
00635
00636 if (deg >= 2) {
00637 int j;
00638 double a, inc, delta, bnd;
00639
00640 i = 0;
00641 while (i < deg - 1) {
00642 a = erecs[i].alpha;
00643 j = i + 1;
00644 while ((j < deg) && (erecs[j].alpha == a))
00645 j++;
00646 if (j == i + 1)
00647 i = j;
00648 else {
00649 if (j == deg)
00650 bnd = M_PI;
00651 else
00652 bnd = erecs[j].alpha;
00653 delta = (bnd - a) / (j - i);
00654 if (delta > ANG)
00655 delta = ANG;
00656 inc = 0;
00657 for (; i < j; i++) {
00658 erecs[i].alpha += inc;
00659 inc += delta;
00660 }
00661 }
00662 }
00663 }
00664
00665 return erecs;
00666 }
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 static int
00677 genPorts(node_t * n, erec * er, bport_t * pp, int idx, double bnd)
00678 {
00679 node_t *other;
00680 int cnt;
00681 edge_t *e = er->e;
00682 edge_t *el;
00683 edge_t **ep;
00684 double angle, delta;
00685 int i, j, inc;
00686
00687 cnt = ED_count(e);
00688
00689 if (e->head == n)
00690 other = e->tail;
00691 else
00692 other = e->head;
00693
00694 delta = (bnd - er->alpha) / cnt;
00695 angle = er->alpha;
00696 if (delta > ANG)
00697 delta = ANG;
00698
00699 if (n < other) {
00700 i = idx;
00701 inc = 1;
00702 } else {
00703 i = idx + cnt - 1;
00704 inc = -1;
00705 angle += delta * (cnt - 1);
00706 delta = -delta;
00707 }
00708
00709 ep = (edge_t **) (el = ED_to_virt(e));
00710 for (j = 0; j < ED_count(e); j++, ep++) {
00711 el = *ep;
00712 pp[i].e = el;
00713 pp[i].n = (DNODE(el->tail) == n ? el->tail : el->head);
00714 pp[i].alpha = angle;
00715 i += inc;
00716 angle += delta;
00717 }
00718 return (idx + cnt);
00719 }
00720
00721
00722
00723
00724
00725
00726
00727
00728 static graph_t *expandCluster(node_t * n, graph_t * cg)
00729 {
00730 erec *es;
00731 erec *ep;
00732 erec *next;
00733 graph_t *sg = ND_clust(n);
00734 bport_t *pp;
00735 int sz = WDEG(n);
00736 int idx = 0;
00737 double bnd;
00738
00739 if (sz != 0) {
00740
00741 pp = N_NEW(sz + 1, bport_t);
00742
00743
00744 es = ep = getEdgeList(n, cg);
00745
00746
00747 while (ep->e) {
00748 next = ep + 1;
00749 if (next->e)
00750 bnd = next->alpha;
00751 else
00752 bnd = 2 * M_PI + es->alpha;
00753 idx = genPorts(n, ep, pp, idx, bnd);
00754 ep = next;
00755 }
00756 assert(idx == sz);
00757
00758 PORTS(sg) = pp;
00759 NPORTS(sg) = sz;
00760 free(es);
00761 }
00762 return sg;
00763 }
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783 static void
00784 setClustNodes(graph_t* root)
00785 {
00786 boxf bb;
00787 graph_t* p;
00788 pointf ctr;
00789 node_t *n;
00790 double w, h;
00791 int h2, w2, h_i;
00792 pointf *vertices;
00793
00794 for (n = agfstnode(root); n; n = agnxtnode(root, n)) {
00795 if (!IS_CLUST_NODE(n)) continue;
00796
00797 p = PARENT(n);
00798 bb = BB(p);
00799 w = bb.UR.x - bb.LL.x;
00800 h = bb.UR.y - bb.LL.y;
00801 ctr.x = w / 2.0;
00802 ctr.y = h / 2.0;
00803 w2 = POINTS(w / 2.0);
00804 h2 = POINTS(h / 2.0);
00805 h_i = POINTS(h);
00806 ND_pos(n)[0] = ctr.x;
00807 ND_pos(n)[1] = ctr.y;
00808 ND_width(n) = w;
00809 ND_height(n) = h;
00810 ND_xsize(n) = POINTS(w);
00811 ND_lw_i(n) = ND_rw_i(n) = w2;
00812 ND_ht_i(n) = ND_ysize(n) = h_i;
00813
00814 vertices = ((polygon_t *) ND_shape_info(n))->vertices;
00815 vertices[0].x = ND_rw_i(n);
00816 vertices[0].y = h2;
00817 vertices[1].x = -ND_lw_i(n);
00818 vertices[1].y = h2;
00819 vertices[2].x = -ND_lw_i(n);
00820 vertices[2].y = -h2;
00821 vertices[3].x = ND_rw_i(n);
00822 vertices[3].y = -h2;
00823 }
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 void layout(graph_t * g, layout_info * infop)
00854 {
00855 point *pts = NULL;
00856 graph_t *dg;
00857 node_t *dn;
00858 node_t *n;
00859 graph_t *cg;
00860 graph_t *sg;
00861 graph_t **cc;
00862 graph_t **pg;
00863 int c_cnt;
00864 int pinned;
00865 xparams xpms;
00866
00867 #ifdef DEBUG
00868 incInd();
00869 #endif
00870 if (Verbose) {
00871 #ifdef DEBUG
00872 prIndent();
00873 #endif
00874 fprintf (stderr, "layout %s\n", g->name);
00875 }
00876
00877 for (n = agfstnode(g); n; n = agnxtnode(g, n))
00878 DNODE(n) = 0;
00879
00880 dg = deriveGraph(g, infop);
00881 cc = pg = findCComp(dg, &c_cnt, &pinned);
00882
00883 while ((cg = *pg++)) {
00884 fdp_tLayout(cg, &xpms);
00885 for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) {
00886 if (ND_clust(n)) {
00887 point pt;
00888 sg = expandCluster(n, cg);
00889 layout(sg, infop);
00890
00891 ND_width(n) = BB(sg).UR.x;
00892 ND_height(n) = BB(sg).UR.y;
00893 pt = cvt2pt(BB(sg).UR);
00894 ND_xsize(n) = pt.x;
00895 ND_ysize(n) = pt.y;
00896 } else if (IS_PORT(n))
00897 agdelete(cg, n);
00898 }
00899
00900
00901 if (agnnodes(cg) >= 2) {
00902 if (g == infop->rootg)
00903 normalize (cg);
00904 fdp_xLayout(cg, &xpms);
00905 }
00906
00907
00908 }
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920 if (c_cnt > 1) {
00921 boolean *bp;
00922 if (pinned) {
00923 bp = N_NEW(c_cnt, boolean);
00924 bp[0] = TRUE;
00925 } else
00926 bp = 0;
00927 infop->pack.fixed = bp;
00928 pts = putGraphs(c_cnt, cc, NULL, &infop->pack);
00929 if (bp)
00930 free(bp);
00931 } else {
00932 pts = NULL;
00933 if (c_cnt == 1)
00934 compute_bb(cc[0]);
00935 }
00936
00937
00938 finalCC(dg, c_cnt, cc, pts, g, infop);
00939 free (pts);
00940
00941
00942
00943
00944 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
00945 if ((sg = ND_clust(dn))) {
00946 BB(sg).LL.x = ND_pos(dn)[0] - ND_width(dn) / 2;
00947 BB(sg).LL.y = ND_pos(dn)[1] - ND_height(dn) / 2;
00948 BB(sg).UR.x = BB(sg).LL.x + ND_width(dn);
00949 BB(sg).UR.y = BB(sg).LL.y + ND_height(dn);
00950 } else if ((n = ANODE(dn))) {
00951 ND_pos(n)[0] = ND_pos(dn)[0];
00952 ND_pos(n)[1] = ND_pos(dn)[1];
00953 }
00954 }
00955 BB(g) = BB(dg);
00956 #ifdef DEBUG
00957 if (g == infop->rootg)
00958 dump(g, 1, 0);
00959 #endif
00960
00961
00962 freeDerivedGraph(dg, cc);
00963 free(cc);
00964 if (Verbose) {
00965 #ifdef DEBUG
00966 prIndent ();
00967 #endif
00968 fprintf (stderr, "end %s\n", g->name);
00969 }
00970 #ifdef DEBUG
00971 decInd();
00972 #endif
00973 }
00974
00975
00976
00977
00978 static void setBB(graph_t * g)
00979 {
00980 int i;
00981 GD_bb(g).LL = cvt2pt(BB(g).LL);
00982 GD_bb(g).UR = cvt2pt(BB(g).UR);
00983 for (i = 1; i <= GD_n_cluster(g); i++) {
00984 setBB(GD_clust(g)[i]);
00985 }
00986 }
00987
00988
00989
00990
00991
00992 void init_info(graph_t * g, layout_info * infop)
00993 {
00994 infop->G_coord = agfindattr(g, "coords");
00995 infop->G_width = agfindattr(g, "width");
00996 infop->G_height = agfindattr(g, "height");
00997 infop->rootg = g;
00998 infop->gid = 0;
00999 infop->pack.margin = getPack(g, CL_OFFSET / 2, CL_OFFSET / 2);
01000 infop->pack.doSplines = 0;
01001 infop->pack.mode = getPackMode(g, l_node);
01002 }
01003
01004
01005
01006
01007
01008
01009
01010
01011 static void
01012 mkClusters (graph_t * g, clist_t* pclist, graph_t* parent)
01013 {
01014 node_t* mn;
01015 edge_t* me;
01016 graph_t* mg;
01017 graph_t* subg;
01018 clist_t list;
01019 clist_t* clist;
01020
01021 if (pclist == NULL) {
01022 clist = &list;
01023 initCList(clist);
01024 }
01025 else
01026 clist = pclist;
01027 mg = g->meta_node->graph;
01028 for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
01029 mn = me->head;
01030 subg = agusergraph(mn);
01031 if (!strncmp(subg->name, "cluster", 7)) {
01032 GD_alg(subg) = (void *) NEW(gdata);
01033 GD_ndim(subg) = GD_ndim(parent);
01034 LEVEL(subg) = LEVEL(parent) + 1;
01035 GPARENT(subg) = parent;
01036 addCluster(clist, subg);
01037 mkClusters(subg, NULL, subg);
01038 }
01039 else {
01040 mkClusters(subg, clist, parent);
01041 }
01042 }
01043 if (pclist == NULL) {
01044 GD_n_cluster(g) = list.cnt;
01045 if (list.cnt)
01046 GD_clust(g) = RALLOC(list.cnt + 1, list.cl, graph_t*);
01047 }
01048 }
01049
01050 void fdp_init_graph(Agraph_t * g)
01051 {
01052 setEdgeType (g, ET_LINE);
01053 GD_alg(g) = (void *) NEW(gdata);
01054 g->u.ndim = late_int(g, agfindattr(g, "dim"), 2, 2);
01055 Ndim = g->u.ndim = MIN(g->u.ndim, MAXDIM);
01056
01057 mkClusters (g, NULL, g);
01058 fdp_initParams(g);
01059 fdp_init_node_edge(g);
01060 }
01061
01062 void fdpLayout(graph_t * g)
01063 {
01064 layout_info info;
01065
01066 init_info(g, &info);
01067 layout(g, &info);
01068 setClustNodes(g);
01069 evalPositions(g,g);
01070
01071
01072
01073
01074
01075
01076
01077 setBB(g);
01078 }
01079
01080 static void
01081 fdpSplines (graph_t * g)
01082 {
01083 int trySplines = 0;
01084 int et = EDGE_TYPE(g);
01085
01086 if (et != ET_LINE) {
01087 if (et == ET_COMPOUND) {
01088 trySplines = splineEdges(g, compoundEdges, ET_SPLINE);
01089
01090 if (trySplines)
01091 Nop = 2;
01092 }
01093 if (trySplines || (et == ET_SPLINE)) {
01094 if (HAS_CLUST_EDGE(g)) {
01095 agerr(AGWARN,
01096 "splines and cluster edges not supported - using line segments\n");
01097 } else {
01098 spline_edges1(g, ET_SPLINE);
01099 }
01100 }
01101 }
01102 if (State < GVSPLINES)
01103 spline_edges1(g, ET_LINE);
01104 }
01105
01106 void fdp_layout(graph_t * g)
01107 {
01108 fdp_init_graph(g);
01109 fdpLayout(g);
01110 neato_set_aspect(g);
01111
01112 if (EDGE_TYPE(g) != ET_NONE) fdpSplines (g);
01113
01114 dotneato_postprocess(g);
01115 }