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 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif
00034
00035
00036 #define FDP_PRIVATE 1
00037
00038 #ifdef HAVE_SYS_TYPES_H
00039 #include <sys/types.h>
00040 #endif
00041 #ifdef HAVE_STDLIB_H
00042 #include <stdlib.h>
00043 #endif
00044 #include <time.h>
00045 #ifndef WIN32
00046 #include <unistd.h>
00047 #endif
00048 #include <ctype.h>
00049 #include <dbg.h>
00050 #include <grid.h>
00051 #include <neato.h>
00052
00053 #ifndef HAVE_SRAND48
00054 #define srand48 srand
00055 #endif
00056 #ifndef HAVE_DRAND48
00057 extern double drand48(void);
00058 #endif
00059
00060 #include "tlayout.h"
00061 #include "globals.h"
00062
00063 #define D_useGrid (fdp_parms.useGrid)
00064 #define D_useNew (fdp_parms.useNew)
00065 #define D_numIters (fdp_parms.numIters)
00066 #define D_unscaled (fdp_parms.unscaled)
00067 #define D_C (fdp_parms.C)
00068 #define D_Tfact (fdp_parms.Tfact)
00069 #define D_K (fdp_parms.K)
00070 #define D_T0 (fdp_parms.T0)
00071
00072
00073
00074
00075 typedef struct {
00076 int useGrid;
00077 int useNew;
00078 long seed;
00079 int numIters;
00080 int maxIters;
00081 int unscaled;
00082 double C;
00083 double Tfact;
00084 double K;
00085 double T0;
00086 int smode;
00087 double Cell;
00088 double Cell2;
00089 double K2;
00090 double Wd;
00091 double Ht;
00092 double Wd2;
00093 double Ht2;
00094 int pass1;
00095 int loopcnt;
00096 } parms_t;
00097
00098 static parms_t parms;
00099
00100 #define T_useGrid (parms.useGrid)
00101 #define T_useNew (parms.useNew)
00102 #define T_seed (parms.seed)
00103 #define T_numIters (parms.numIters)
00104 #define T_maxIters (parms.maxIters)
00105 #define T_unscaled (parms.unscaled)
00106 #define T_C (parms.C)
00107 #define T_Tfact (parms.Tfact)
00108 #define T_K (parms.K)
00109 #define T_T0 (parms.T0)
00110 #define T_smode (parms.smode)
00111 #define T_Cell (parms.Cell)
00112 #define T_Cell2 (parms.Cell2)
00113 #define T_K2 (parms.K2)
00114 #define T_Wd (parms.Wd)
00115 #define T_Ht (parms.Ht)
00116 #define T_Wd2 (parms.Wd2)
00117 #define T_Ht2 (parms.Ht2)
00118 #define T_pass1 (parms.pass1)
00119 #define T_loopcnt (parms.loopcnt)
00120
00121 #define EXPFACTOR 1.2
00122 #define DFLT_maxIters 600
00123 #define DFLT_K 0.3
00124 #define DFLT_Cell 0.0
00125 #define DFLT_seed 1
00126 #define DFLT_smode INIT_RANDOM
00127
00128 static double cool(double temp, int t)
00129 {
00130 return (T_T0 * (T_maxIters - t)) / T_maxIters;
00131 }
00132
00133
00134
00135 static void reset_params(void)
00136 {
00137 T_T0 = -1.0;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147 static int init_params(graph_t * g, xparams * xpms)
00148 {
00149 int ret = 0;
00150
00151 if (T_T0 == -1.0) {
00152 int nnodes = agnnodes(g);
00153
00154 T_T0 = T_Tfact * T_K * sqrt(nnodes) / 5;
00155 #ifdef DEBUG
00156 if (Verbose) {
00157 prIndent();
00158 fprintf(stderr, "tlayout %s(%s) : T0 %f\n", g->name, GORIG(g->root)->name, T_T0);
00159 }
00160 #endif
00161 ret = 1;
00162 }
00163
00164 xpms->T0 = cool(T_T0, T_pass1);
00165 xpms->K = T_K;
00166 xpms->C = T_C;
00167 xpms->numIters = T_maxIters - T_pass1;
00168
00169 if (T_numIters >= 0) {
00170 if (T_numIters <= T_pass1) {
00171 T_loopcnt = T_numIters;
00172 xpms->loopcnt = 0;
00173 } else if (T_numIters <= T_maxIters) {
00174 T_loopcnt = T_pass1;
00175 xpms->loopcnt = T_numIters - T_pass1;
00176 }
00177 } else {
00178 T_loopcnt = T_pass1;
00179 xpms->loopcnt = xpms->numIters;
00180 }
00181 return ret;
00182 }
00183
00184
00185
00186
00187 void fdp_initParams(graph_t * g)
00188 {
00189 T_useGrid = D_useGrid;
00190 T_useNew = D_useNew;
00191 T_numIters = D_numIters;
00192 T_unscaled = D_unscaled;
00193 T_Cell = DFLT_Cell;
00194 T_C = D_C;
00195 T_Tfact = D_Tfact;
00196 T_maxIters = late_int(g, agfindattr(g, "maxiter"), DFLT_maxIters, 0);
00197 D_K = T_K = late_double(g, agfindattr(g, "K"), DFLT_K, 0.0);
00198 if (D_T0 == -1.0) {
00199 T_T0 = late_double(g, agfindattr(g, "T0"), -1.0, 0.0);
00200 } else
00201 T_T0 = D_T0;
00202 T_seed = DFLT_seed;
00203 T_smode = setSeed (g, DFLT_smode, &T_seed);
00204 if (T_smode == INIT_SELF) {
00205 agerr(AGWARN, "fdp does not support start=self - ignoring\n");
00206 T_seed = DFLT_smode;
00207 }
00208
00209 T_pass1 = (T_unscaled * T_maxIters) / 100;
00210 T_K2 = T_K * T_K;
00211
00212 if (T_useGrid) {
00213 if (T_Cell <= 0.0)
00214 T_Cell = 3 * T_K;
00215 T_Cell2 = T_Cell * T_Cell;
00216 }
00217 #ifdef DEBUG
00218 if (Verbose) {
00219 prIndent();
00220 fprintf(stderr,
00221 "Params %s : K %f T0 %f Tfact %f maxIters %d unscaled %d\n",
00222 g->name,
00223 T_K, T_T0, T_Tfact, T_maxIters, T_unscaled);
00224 }
00225 #endif
00226 }
00227
00228 static void
00229 doRep(node_t * p, node_t * q, double xdelta, double ydelta, double dist2)
00230 {
00231 double force;
00232 double dist;
00233
00234 while (dist2 == 0.0) {
00235 xdelta = 5 - rand() % 10;
00236 ydelta = 5 - rand() % 10;
00237 dist2 = xdelta * xdelta + ydelta * ydelta;
00238 }
00239 if (T_useNew) {
00240 dist = sqrt(dist2);
00241 force = T_K2 / (dist * dist2);
00242 } else
00243 force = T_K2 / dist2;
00244 if (IS_PORT(p) && IS_PORT(q))
00245 force *= 10.0;
00246 DISP(q)[0] += xdelta * force;
00247 DISP(q)[1] += ydelta * force;
00248 DISP(p)[0] -= xdelta * force;
00249 DISP(p)[1] -= ydelta * force;
00250 }
00251
00252
00253
00254
00255
00256 static void applyRep(Agnode_t * p, Agnode_t * q)
00257 {
00258 double xdelta, ydelta;
00259
00260 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00261 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00262 doRep(p, q, xdelta, ydelta, xdelta * xdelta + ydelta * ydelta);
00263 }
00264
00265 static void doNeighbor(Grid * grid, int i, int j, node_list * nodes)
00266 {
00267 cell *cellp = findGrid(grid, i, j);
00268 node_list *qs;
00269 Agnode_t *p;
00270 Agnode_t *q;
00271 double xdelta, ydelta;
00272 double dist2;
00273
00274 if (cellp) {
00275 #ifdef DEBUG
00276 if (Verbose >= 3) {
00277 prIndent();
00278 fprintf(stderr, " doNeighbor (%d,%d) : %d\n", i, j,
00279 gLength(cellp));
00280 }
00281 #endif
00282 for (; nodes != 0; nodes = nodes->next) {
00283 p = nodes->node;
00284 for (qs = cellp->nodes; qs != 0; qs = qs->next) {
00285 q = qs->node;
00286 xdelta = q->u.pos[0] - p->u.pos[0];
00287 ydelta = q->u.pos[1] - p->u.pos[1];
00288 dist2 = xdelta * xdelta + ydelta * ydelta;
00289 if (dist2 < T_Cell2)
00290 doRep(p, q, xdelta, ydelta, dist2);
00291 }
00292 }
00293 }
00294 }
00295
00296 static int gridRepulse(Dt_t * dt, cell * cellp, Grid * grid)
00297 {
00298 node_list *nodes = cellp->nodes;
00299 int i = cellp->p.i;
00300 int j = cellp->p.j;
00301 node_list *p;
00302 node_list *q;
00303
00304 NOTUSED(dt);
00305 #ifdef DEBUG
00306 if (Verbose >= 3) {
00307 prIndent();
00308 fprintf(stderr, "gridRepulse (%d,%d) : %d\n", i, j,
00309 gLength(cellp));
00310 }
00311 #endif
00312 for (p = nodes; p != 0; p = p->next) {
00313 for (q = nodes; q != 0; q = q->next)
00314 if (p != q)
00315 applyRep(p->node, q->node);
00316 }
00317
00318 doNeighbor(grid, i - 1, j - 1, nodes);
00319 doNeighbor(grid, i - 1, j, nodes);
00320 doNeighbor(grid, i - 1, j + 1, nodes);
00321 doNeighbor(grid, i, j - 1, nodes);
00322 doNeighbor(grid, i, j + 1, nodes);
00323 doNeighbor(grid, i + 1, j - 1, nodes);
00324 doNeighbor(grid, i + 1, j, nodes);
00325 doNeighbor(grid, i + 1, j + 1, nodes);
00326
00327 return 0;
00328 }
00329
00330
00331
00332
00333
00334 static void applyAttr(Agnode_t * p, Agnode_t * q, Agedge_t * e)
00335 {
00336 double xdelta, ydelta;
00337 double force;
00338 double dist;
00339 double dist2;
00340
00341 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00342 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00343 dist2 = xdelta * xdelta + ydelta * ydelta;
00344 while (dist2 == 0.0) {
00345 xdelta = 5 - rand() % 10;
00346 ydelta = 5 - rand() % 10;
00347 dist2 = xdelta * xdelta + ydelta * ydelta;
00348 }
00349 dist = sqrt(dist2);
00350 if (T_useNew)
00351 force = (ED_factor(e) * (dist - ED_dist(e))) / dist;
00352 else
00353 force = (ED_factor(e) * dist) / ED_dist(e);
00354 DISP(q)[0] -= xdelta * force;
00355 DISP(q)[1] -= ydelta * force;
00356 DISP(p)[0] += xdelta * force;
00357 DISP(p)[1] += ydelta * force;
00358 }
00359
00360 static void updatePos(Agraph_t * g, double temp, bport_t * pp)
00361 {
00362 Agnode_t *n;
00363 double temp2;
00364 double len2;
00365 double x, y, d;
00366 double dx, dy;
00367
00368 temp2 = temp * temp;
00369 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00370 if (ND_pinned(n) & P_FIX)
00371 continue;
00372 dx = DISP(n)[0];
00373 dy = DISP(n)[1];
00374 len2 = dx * dx + dy * dy;
00375
00376
00377 if (len2 < temp2) {
00378 x = ND_pos(n)[0] + dx;
00379 y = ND_pos(n)[1] + dy;
00380 } else {
00381 double fact = temp / (sqrt(len2));
00382 x = ND_pos(n)[0] + dx * fact;
00383 y = ND_pos(n)[1] + dy * fact;
00384 }
00385
00386
00387 if (pp) {
00388 d = sqrt((x * x) / T_Wd2 + (y * y) / T_Ht2);
00389 if (IS_PORT(n)) {
00390 ND_pos(n)[0] = x / d;
00391 ND_pos(n)[1] = y / d;
00392 } else if (d >= 1.0) {
00393 ND_pos(n)[0] = 0.95 * x / d;
00394 ND_pos(n)[1] = 0.95 * y / d;
00395 } else {
00396 ND_pos(n)[0] = x;
00397 ND_pos(n)[1] = y;
00398 }
00399 } else {
00400 ND_pos(n)[0] = x;
00401 ND_pos(n)[1] = y;
00402 }
00403 }
00404 }
00405
00406 #define FLOOR(d) ((int)floor(d))
00407
00408
00409
00410 static void gAdjust(Agraph_t * g, double temp, bport_t * pp, Grid * grid)
00411 {
00412 Agnode_t *n;
00413 Agedge_t *e;
00414
00415 if (temp <= 0.0)
00416 return;
00417
00418 clearGrid(grid);
00419
00420 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00421 DISP(n)[0] = DISP(n)[1] = 0;
00422 addGrid(grid, FLOOR(n->u.pos[0] / T_Cell), FLOOR(n->u.pos[1] / T_Cell),
00423 n);
00424 }
00425
00426 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00427 for (e = agfstout(g, n); e; e = agnxtout(g, e))
00428 if (n != e->head)
00429 applyAttr(n, e->head, e);
00430 }
00431 walkGrid(grid, gridRepulse);
00432
00433
00434 updatePos(g, temp, pp);
00435 }
00436
00437
00438
00439 static void adjust(Agraph_t * g, double temp, bport_t * pp)
00440 {
00441 Agnode_t *n;
00442 Agnode_t *n1;
00443 Agedge_t *e;
00444
00445 if (temp <= 0.0)
00446 return;
00447
00448 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00449 DISP(n)[0] = DISP(n)[1] = 0;
00450 }
00451
00452 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00453 for (n1 = agnxtnode(g, n); n1; n1 = agnxtnode(g, n1)) {
00454 applyRep(n, n1);
00455 }
00456 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00457 if (n != e->head)
00458 applyAttr(n, e->head, e);
00459 }
00460 }
00461
00462 updatePos(g, temp, pp);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471 static pointf initPositions(graph_t * g, bport_t * pp)
00472 {
00473 int nG = agnnodes(g) - NPORTS(g);
00474 double size;
00475 Agnode_t *np;
00476 int n_pos = 0;
00477 box bb = { {0, 0}, {0, 0} };
00478 pointf ctr;
00479 long local_seed;
00480 double PItimes2 = M_PI * 2.0;
00481
00482 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00483 if (ND_pinned(np)) {
00484 if (n_pos) {
00485 bb.LL.x = MIN(ND_pos(np)[0], bb.LL.x);
00486 bb.LL.y = MIN(ND_pos(np)[1], bb.LL.y);
00487 bb.UR.x = MAX(ND_pos(np)[0], bb.UR.x);
00488 bb.UR.y = MAX(ND_pos(np)[1], bb.UR.y);
00489 } else {
00490 bb.UR.x = bb.LL.x = ND_pos(np)[0];
00491 bb.UR.y = bb.LL.y = ND_pos(np)[1];
00492 }
00493 n_pos++;
00494 }
00495 }
00496
00497 size = T_K * (sqrt((double) nG) + 1.0);
00498 T_Wd = T_Ht = EXPFACTOR * (size / 2.0);
00499 if (n_pos == 1) {
00500 ctr.x = bb.LL.x;
00501 ctr.y = bb.LL.y;
00502 } else if (n_pos > 1) {
00503 double alpha, area, width, height, quot;
00504 ctr.x = (bb.LL.x + bb.UR.x) / 2.0;
00505 ctr.y = (bb.LL.y + bb.UR.y) / 2.0;
00506 width = EXPFACTOR * (bb.UR.x - bb.LL.x);
00507 height = EXPFACTOR * (bb.UR.y - bb.LL.y);
00508 area = 4.0 * T_Wd * T_Ht;
00509 quot = (width * height) / area;
00510 if (quot >= 1.0) {
00511 T_Wd = width / 2.0;
00512 T_Ht = height / 2.0;
00513 } else if (quot > 0.0) {
00514 quot = 2.0 * sqrt(quot);
00515 T_Wd = width / quot;
00516 T_Ht = height / quot;
00517 } else {
00518 if (width > 0) {
00519 height = area / width;
00520 T_Wd = width / 2.0;
00521 T_Ht = height / 2.0;
00522 } else if (height > 0) {
00523 width = area / height;
00524 T_Wd = width / 2.0;
00525 T_Ht = height / 2.0;
00526 }
00527
00528
00529
00530 }
00531
00532
00533 alpha = atan2(T_Ht, T_Wd);
00534 T_Wd = T_Wd / cos(alpha);
00535 T_Ht = T_Ht / sin(alpha);
00536 } else {
00537 ctr.x = ctr.y = 0;
00538 }
00539 T_Wd2 = T_Wd * T_Wd;
00540 T_Ht2 = T_Ht * T_Ht;
00541
00542
00543 if (T_smode == INIT_RANDOM)
00544 local_seed = T_seed;
00545 else {
00546 #ifdef MSWIN32
00547 local_seed = time(NULL);
00548 #else
00549 local_seed = getpid() ^ time(NULL);
00550 #endif
00551 }
00552 srand48(local_seed);
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 if (pp) {
00564
00565 while (pp->e) {
00566 np = pp->n;
00567 ND_pos(np)[0] = T_Wd * cos(pp->alpha) + ctr.x;
00568 ND_pos(np)[1] = T_Ht * sin(pp->alpha) + ctr.y;
00569 ND_pinned(np) = P_SET;
00570
00571 pp++;
00572 }
00573 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00574 if (IS_PORT(np))
00575 continue;
00576 if (ND_pinned(np)) {
00577 ND_pos(np)[0] -= ctr.x;
00578 ND_pos(np)[1] -= ctr.y;
00579 } else {
00580 pointf p = { 0.0, 0.0 };
00581 int cnt = 0;
00582 node_t *op;
00583 edge_t *ep;
00584 for (ep = agfstedge(g, np); ep; ep = agnxtedge(g, ep, np)) {
00585 if (ep->head == ep->tail)
00586 continue;
00587 op = (ep->head == np ? ep->tail : ep->head);
00588 if (!hasPos(op))
00589 continue;
00590 if (cnt) {
00591 p.x = (p.x * cnt + ND_pos(op)[0]) / (cnt + 1);
00592 p.y = (p.y * cnt + ND_pos(op)[1]) / (cnt + 1);
00593 } else {
00594 p.x = ND_pos(op)[0];
00595 p.y = ND_pos(op)[1];
00596 }
00597 cnt++;
00598 }
00599 if (cnt > 1) {
00600 ND_pos(np)[0] = p.x;
00601 ND_pos(np)[1] = p.y;
00602
00603 } else if (cnt == 1) {
00604 ND_pos(np)[0] = 0.98 * p.x + 0.1 * ctr.x;
00605 ND_pos(np)[1] = 0.9 * p.y + 0.1 * ctr.y;
00606
00607 } else {
00608 double angle = PItimes2 * drand48();
00609 double radius = 0.9 * drand48();
00610 ND_pos(np)[0] = radius * T_Wd * cos(angle);
00611 ND_pos(np)[1] = radius * T_Ht * sin(angle);
00612
00613 }
00614 ND_pinned(np) = P_SET;
00615 }
00616 }
00617 } else {
00618 if (n_pos) {
00619 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00620 if (ND_pinned(np)) {
00621 ND_pos(np)[0] -= ctr.x;
00622 ND_pos(np)[1] -= ctr.y;
00623 } else {
00624 ND_pos(np)[0] = T_Wd * (2.0 * drand48() - 1.0);
00625 ND_pos(np)[1] = T_Ht * (2.0 * drand48() - 1.0);
00626 }
00627 }
00628 } else {
00629 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00630 ND_pos(np)[0] = T_Wd * (2.0 * drand48() - 1.0);
00631 ND_pos(np)[1] = T_Ht * (2.0 * drand48() - 1.0);
00632 }
00633 }
00634 }
00635
00636 return ctr;
00637 }
00638
00639 void dumpstat(graph_t * g)
00640 {
00641 double dx, dy;
00642 double l, max2 = 0.0;
00643 node_t *np;
00644 edge_t *ep;
00645 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00646 dx = DISP(np)[0];
00647 dy = DISP(np)[1];
00648 l = dx * dx + dy * dy;
00649 if (l > max2)
00650 max2 = l;
00651 fprintf(stderr, "%s: (%f,%f) (%f,%f)\n", np->name,
00652 ND_pos(np)[0], ND_pos(np)[1], DISP(np)[0], DISP(np)[1]);
00653 }
00654 fprintf(stderr, "max delta = %f\n", sqrt(max2));
00655 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00656 for (ep = agfstout(g, np); ep; ep = agnxtout(g, ep)) {
00657 dx = ND_pos(np)[0] - ND_pos(ep->head)[0];
00658 dy = ND_pos(np)[1] - ND_pos(ep->head)[1];
00659 fprintf(stderr, " %s -- %s (%f)\n", np->name,
00660 ep->head->name, sqrt(dx * dx + dy * dy));
00661 }
00662 }
00663 }
00664
00665
00666
00667
00668
00669
00670 void fdp_tLayout(graph_t * g, xparams * xpms)
00671 {
00672 int i;
00673 int reset;
00674 bport_t *pp = PORTS(g);
00675 double temp;
00676 Grid *grid;
00677 pointf ctr;
00678 Agnode_t *n;
00679
00680 reset = init_params(g, xpms);
00681 temp = T_T0;
00682
00683 ctr = initPositions(g, pp);
00684
00685 if (T_useGrid) {
00686 grid = mkGrid(agnnodes(g));
00687 adjustGrid(grid, agnnodes(g));
00688 for (i = 0; i < T_loopcnt; i++) {
00689 temp = cool(temp, i);
00690 gAdjust(g, temp, pp, grid);
00691 }
00692 delGrid(grid);
00693 } else {
00694 for (i = 0; i < T_loopcnt; i++) {
00695 temp = cool(temp, i);
00696 adjust(g, temp, pp);
00697 }
00698 }
00699
00700 if ((ctr.x != 0.0) || (ctr.y != 0.0)) {
00701 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00702 ND_pos(n)[0] += ctr.x;
00703 ND_pos(n)[1] += ctr.y;
00704 }
00705 }
00706
00707 if (reset)
00708 reset_params();
00709 }