/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/fdpgen/tlayout.c

Go to the documentation of this file.
00001 /* $Id: tlayout.c,v 1.7 2006/07/27 02:20:56 erg Exp $ $Revision: 1.7 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 /* tlayout.c:
00018  * Written by Emden R. Gansner
00019  *
00020  * Module for initial layout, using point nodes and ports.
00021  * 
00022  * Note: If interior nodes are not connected, they tend to fly apart,
00023  * despite being tied to port nodes. This occurs because, as initially
00024  * coded, as the nodes tend to straighten into a line, the radius
00025  * grows causing more expansion. Is the problem really here and not
00026  * with disconnected nodes in xlayout? If here, we can either forbid
00027  * expansion or eliminate repulsion between nodes only connected
00028  * via port nodes.
00029  */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif
00034 
00035 /* uses PRIVATE interface */
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   /* Actual parameters used; initialized using fdp_parms, then possibly
00073    * updated with graph-specific values.
00074    */
00075 typedef struct {
00076     int useGrid;        /* use grid for speed up */
00077     int useNew;         /* encode x-K into attractive force */
00078     long seed;          /* seed for position RNG */
00079     int numIters;       /* actual iterations in layout */
00080     int maxIters;       /* max iterations in layout */
00081     int unscaled;       /* % of iterations used in pass 1 */
00082     double C;           /* Repulsion factor in xLayout */
00083     double Tfact;       /* scale temp from default expression */
00084     double K;           /* spring constant; ideal distance */
00085     double T0;          /* initial temperature */
00086     int smode;          /* seed mode */
00087     double Cell;        /* grid cell size */
00088     double Cell2;       /* Cell*Cell */
00089     double K2;          /* K*K */
00090     double Wd;          /* half-width of boundary */
00091     double Ht;          /* half-height of boundary */
00092     double Wd2;         /* Wd*Wd */
00093     double Ht2;         /* Ht*Ht */
00094     int pass1;          /* iterations used in pass 1 */
00095     int loopcnt;        /* actual iterations in this pass */
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 /* reset_params:
00134  */
00135 static void reset_params(void)
00136 {
00137     T_T0 = -1.0;
00138 }
00139 
00140 /* init_params:
00141  * Set parameters for expansion phase based on initial
00142  * layout parameters. If T0 is not set, we set it here
00143  * based on the size of the graph. In this case, we
00144  * return 1, so that fdp_tLayout can unset T0, to be
00145  * reset by a recursive call to fdp_tLayout. 
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 /* fdp_initParams:
00185  * Initialize parameters based on root graph attributes.
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 /* applyRep:
00253  * Repulsive force = (K*K)/d
00254  *  or K*K/d*d
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 /* applyAttr:
00331  * Attractive force = weight*(d*d)/K
00332  *  or        force = (d - L(e))*weight(e)
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         /* limit by temperature */
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         /* if ports, limit by boundary */
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 /* gAdjust:
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 /* adjust:
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 /* initPositions:
00466  * Create initial layout of nodes
00467  * TODO :
00468  *  Position nodes near neighbors with positions.
00469  *  Use bbox to reset K.
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;              /* no. of nodes with position info */
00477     box bb = { {0, 0}, {0, 0} };
00478     pointf ctr;                 /* center of boundary ellipse */
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) {      /* If bbox has large enough area, use it */
00511             T_Wd = width / 2.0;
00512             T_Ht = height / 2.0;
00513         } else if (quot > 0.0) {        /* else scale up to have enough area */
00514             quot = 2.0 * sqrt(quot);
00515             T_Wd = width / quot;
00516             T_Ht = height / quot;
00517         } else {                /* either width or height is 0 */
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             /* If width = height = 0, use Wd and Ht as defined above for
00528              * the case the n_pos == 0.
00529              */
00530         }
00531 
00532         /* Construct enclosing ellipse */
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     /* Set seed value */
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     /* If ports, place ports on and nodes within an ellipse centered at origin
00555      * with halfwidth Wd and halfheight Ht. 
00556      * If no ports, place nodes within a rectangle centered at origin
00557      * with halfwidth Wd and halfheight Ht. Nodes with a given position
00558      * are translated. Wd and Ht are set to contain all positioned points.
00559      * The reverse translation will be applied to all
00560      * nodes at the end of the layout.
00561      * TODO: place unfixed points using adjacent ports or fixed pts.
00562      */
00563     if (pp) {
00564 /* fprintf (stderr, "initPos %s ctr (%g,%g) Wd %g Ht %g\n", g->name, ctr.x, ctr.y, Wd, Ht); */
00565         while (pp->e) {         /* position ports on ellipse */
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 /* fprintf (stderr, "%s pt (%g,%g) %g\n", np->name, ND_pos(np)[0], ND_pos(np)[1], pp->alpha); */
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 /* fprintf (stderr, "%s 1 (%g,%g)\n", np->name, p.x, p.y); */
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 /* fprintf (stderr, "%s %d (%g,%g)\n", np->name, cnt, ND_pos(np)[0], ND_pos(np)[1]); */
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 /* fprintf (stderr, "%s 0 (%g,%g)\n", np->name, ND_pos(np)[0], ND_pos(np)[1]); */
00613                 }
00614                 ND_pinned(np) = P_SET;
00615             }
00616         }
00617     } else {
00618         if (n_pos) {            /* If positioned nodes */
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 {                /* No ports or positions; place randomly */
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 /* fdp_tLayout:
00666  * Given graph g with ports nodes, layout g respecting ports.
00667  * If some node have position information, it may be useful to
00668  * reset temperature and other parameters to reflect this.
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 /* dumpstat (g); */
00707     if (reset)
00708         reset_params();
00709 }

Generated on Mon Mar 31 19:03:26 2008 for Graphviz by  doxygen 1.5.1