Graphviz  2.29.20120524.0446
lib/fdpgen/tlayout.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 /* tlayout.c:
00015  * Written by Emden R. Gansner
00016  *
00017  * Module for initial layout, using point nodes and ports.
00018  * 
00019  * Note: If interior nodes are not connected, they tend to fly apart,
00020  * despite being tied to port nodes. This occurs because, as initially
00021  * coded, as the nodes tend to straighten into a line, the radius
00022  * grows causing more expansion. Is the problem really here and not
00023  * with disconnected nodes in xlayout? If here, we can either forbid
00024  * expansion or eliminate repulsion between nodes only connected
00025  * via port nodes.
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include "config.h"
00030 #endif
00031 
00032 /* uses PRIVATE interface */
00033 #define FDP_PRIVATE 1
00034 
00035 #ifdef HAVE_SYS_TYPES_H
00036 #include <sys/types.h>
00037 #endif
00038 #ifdef HAVE_STDLIB_H
00039 #include <stdlib.h>
00040 #endif
00041 #include <time.h>
00042 #ifndef WIN32
00043 #include <unistd.h>
00044 #endif
00045 #include <ctype.h>
00046 #include <dbg.h>
00047 #include <grid.h>
00048 #include <neato.h>
00049 
00050 #ifndef HAVE_SRAND48
00051 #define srand48 srand
00052 #endif
00053 #ifndef HAVE_DRAND48
00054 extern double drand48(void);
00055 #endif
00056 
00057 #include "tlayout.h"
00058 #include "globals.h"
00059 
00060 #define D_useGrid   (fdp_parms.useGrid)
00061 #define D_useNew    (fdp_parms.useNew)
00062 #define D_numIters  (fdp_parms.numIters)
00063 #define D_unscaled  (fdp_parms.unscaled)
00064 #define D_C         (fdp_parms.C)
00065 #define D_Tfact     (fdp_parms.Tfact)
00066 #define D_K         (fdp_parms.K)
00067 #define D_T0        (fdp_parms.T0)
00068 
00069   /* Actual parameters used; initialized using fdp_parms, then possibly
00070    * updated with graph-specific values.
00071    */
00072 typedef struct {
00073     int useGrid;        /* use grid for speed up */
00074     int useNew;         /* encode x-K into attractive force */
00075     long seed;          /* seed for position RNG */
00076     int numIters;       /* actual iterations in layout */
00077     int maxIters;       /* max iterations in layout */
00078     int unscaled;       /* % of iterations used in pass 1 */
00079     double C;           /* Repulsion factor in xLayout */
00080     double Tfact;       /* scale temp from default expression */
00081     double K;           /* spring constant; ideal distance */
00082     double T0;          /* initial temperature */
00083     int smode;          /* seed mode */
00084     double Cell;        /* grid cell size */
00085     double Cell2;       /* Cell*Cell */
00086     double K2;          /* K*K */
00087     double Wd;          /* half-width of boundary */
00088     double Ht;          /* half-height of boundary */
00089     double Wd2;         /* Wd*Wd */
00090     double Ht2;         /* Ht*Ht */
00091     int pass1;          /* iterations used in pass 1 */
00092     int loopcnt;        /* actual iterations in this pass */
00093 } parms_t;
00094 
00095 static parms_t parms;
00096 
00097 #define T_useGrid   (parms.useGrid)
00098 #define T_useNew    (parms.useNew)
00099 #define T_seed      (parms.seed)
00100 #define T_numIters  (parms.numIters)
00101 #define T_maxIters  (parms.maxIters)
00102 #define T_unscaled  (parms.unscaled)
00103 #define T_C         (parms.C)
00104 #define T_Tfact     (parms.Tfact)
00105 #define T_K         (parms.K)
00106 #define T_T0        (parms.T0)
00107 #define T_smode     (parms.smode)
00108 #define T_Cell      (parms.Cell)
00109 #define T_Cell2     (parms.Cell2)
00110 #define T_K2        (parms.K2)
00111 #define T_Wd        (parms.Wd)
00112 #define T_Ht        (parms.Ht)
00113 #define T_Wd2       (parms.Wd2)
00114 #define T_Ht2       (parms.Ht2)
00115 #define T_pass1     (parms.pass1)
00116 #define T_loopcnt   (parms.loopcnt)
00117 
00118 #define EXPFACTOR  1.2
00119 #define DFLT_maxIters 600
00120 #define DFLT_K  0.3
00121 #define DFLT_Cell  0.0
00122 #define DFLT_seed  1
00123 #define DFLT_smode INIT_RANDOM
00124 
00125 static double cool(double temp, int t)
00126 {
00127     return (T_T0 * (T_maxIters - t)) / T_maxIters;
00128 }
00129 
00130 /* reset_params:
00131  */
00132 static void reset_params(void)
00133 {
00134     T_T0 = -1.0;
00135 }
00136 
00137 /* init_params:
00138  * Set parameters for expansion phase based on initial
00139  * layout parameters. If T0 is not set, we set it here
00140  * based on the size of the graph. In this case, we
00141  * return 1, so that fdp_tLayout can unset T0, to be
00142  * reset by a recursive call to fdp_tLayout. 
00143  */
00144 static int init_params(graph_t * g, xparams * xpms)
00145 {
00146     int ret = 0;
00147 
00148     if (T_T0 == -1.0) {
00149         int nnodes = agnnodes(g);
00150 
00151         T_T0 = T_Tfact * T_K * sqrt(nnodes) / 5;
00152 #ifdef DEBUG
00153         if (Verbose) {
00154             prIndent();
00155             fprintf(stderr, "tlayout %s(%s) : T0 %f\n", g->name, GORIG(g->root)->name, T_T0);
00156         }
00157 #endif
00158         ret = 1;
00159     }
00160 
00161     xpms->T0 = cool(T_T0, T_pass1);
00162     xpms->K = T_K;
00163     xpms->C = T_C;
00164     xpms->numIters = T_maxIters - T_pass1;
00165 
00166     if (T_numIters >= 0) {
00167         if (T_numIters <= T_pass1) {
00168             T_loopcnt = T_numIters;
00169             xpms->loopcnt = 0;
00170         } else if (T_numIters <= T_maxIters) {
00171             T_loopcnt = T_pass1;
00172             xpms->loopcnt = T_numIters - T_pass1;
00173         }
00174     } else {
00175         T_loopcnt = T_pass1;
00176         xpms->loopcnt = xpms->numIters;
00177     }
00178     return ret;
00179 }
00180 
00181 /* fdp_initParams:
00182  * Initialize parameters based on root graph attributes.
00183  */
00184 void fdp_initParams(graph_t * g)
00185 {
00186     T_useGrid = D_useGrid;
00187     T_useNew = D_useNew;
00188     T_numIters = D_numIters;
00189     T_unscaled = D_unscaled;
00190     T_Cell = DFLT_Cell;
00191     T_C = D_C;
00192     T_Tfact = D_Tfact;
00193 #ifndef WITH_CGRAPH
00194     T_maxIters = late_int(g, agfindattr(g, "maxiter"), DFLT_maxIters, 0);
00195     D_K = T_K = late_double(g, agfindattr(g, "K"), DFLT_K, 0.0);
00196 #else /* WITH_CGRAPH */
00197     T_maxIters = late_int(g, agattr(g,AGRAPH, "maxiter", NULL), DFLT_maxIters, 0);
00198     D_K = T_K = late_double(g, agattr(g,AGRAPH, "K", NULL), DFLT_K, 0.0);
00199 #endif /* WITH_CGRAPH */
00200     if (D_T0 == -1.0) {
00201 #ifndef WITH_CGRAPH
00202         T_T0 = late_double(g, agfindattr(g, "T0"), -1.0, 0.0);
00203 #else /* WITH_CGRAPH */
00204         T_T0 = late_double(g, agattr(g,AGRAPH, "T0", NULL), -1.0, 0.0);
00205 #endif /* WITH_CGRAPH */
00206     } else
00207         T_T0 = D_T0;
00208     T_seed = DFLT_seed;
00209     T_smode = setSeed (g, DFLT_smode, &T_seed);
00210     if (T_smode == INIT_SELF) {
00211         agerr(AGWARN, "fdp does not support start=self - ignoring\n");
00212         T_seed = DFLT_smode;
00213     }
00214 
00215     T_pass1 = (T_unscaled * T_maxIters) / 100;
00216     T_K2 = T_K * T_K;
00217 
00218     if (T_useGrid) {
00219         if (T_Cell <= 0.0)
00220             T_Cell = 3 * T_K;
00221         T_Cell2 = T_Cell * T_Cell;
00222     }
00223 #ifdef DEBUG
00224     if (Verbose) {
00225         prIndent();
00226         fprintf(stderr,
00227                 "Params %s : K %f T0 %f Tfact %f maxIters %d unscaled %d\n",
00228                 g->name, 
00229                 T_K, T_T0, T_Tfact, T_maxIters, T_unscaled);
00230     }
00231 #endif
00232 }
00233 
00234 static void
00235 doRep(node_t * p, node_t * q, double xdelta, double ydelta, double dist2)
00236 {
00237     double force;
00238     double dist;
00239 
00240     while (dist2 == 0.0) {
00241         xdelta = 5 - rand() % 10;
00242         ydelta = 5 - rand() % 10;
00243         dist2 = xdelta * xdelta + ydelta * ydelta;
00244     }
00245     if (T_useNew) {
00246         dist = sqrt(dist2);
00247         force = T_K2 / (dist * dist2);
00248     } else
00249         force = T_K2 / dist2;
00250     if (IS_PORT(p) && IS_PORT(q))
00251         force *= 10.0;
00252     DISP(q)[0] += xdelta * force;
00253     DISP(q)[1] += ydelta * force;
00254     DISP(p)[0] -= xdelta * force;
00255     DISP(p)[1] -= ydelta * force;
00256 }
00257 
00258 /* applyRep:
00259  * Repulsive force = (K*K)/d
00260  *  or K*K/d*d
00261  */
00262 static void applyRep(Agnode_t * p, Agnode_t * q)
00263 {
00264     double xdelta, ydelta;
00265 
00266     xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00267     ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00268     doRep(p, q, xdelta, ydelta, xdelta * xdelta + ydelta * ydelta);
00269 }
00270 
00271 static void doNeighbor(Grid * grid, int i, int j, node_list * nodes)
00272 {
00273     cell *cellp = findGrid(grid, i, j);
00274     node_list *qs;
00275     Agnode_t *p;
00276     Agnode_t *q;
00277     double xdelta, ydelta;
00278     double dist2;
00279 
00280     if (cellp) {
00281 #ifdef DEBUG
00282         if (Verbose >= 3) {
00283             prIndent();
00284             fprintf(stderr, "  doNeighbor (%d,%d) : %d\n", i, j,
00285                     gLength(cellp));
00286         }
00287 #endif
00288         for (; nodes != 0; nodes = nodes->next) {
00289             p = nodes->node;
00290             for (qs = cellp->nodes; qs != 0; qs = qs->next) {
00291                 q = qs->node;
00292                 xdelta = (ND_pos(q))[0] - (ND_pos(p))[0];
00293                 ydelta = (ND_pos(q))[1] - (ND_pos(p))[1];
00294                 dist2 = xdelta * xdelta + ydelta * ydelta;
00295                 if (dist2 < T_Cell2)
00296                     doRep(p, q, xdelta, ydelta, dist2);
00297             }
00298         }
00299     }
00300 }
00301 
00302 static int gridRepulse(Dt_t * dt, cell * cellp, Grid * grid)
00303 {
00304     node_list *nodes = cellp->nodes;
00305     int i = cellp->p.i;
00306     int j = cellp->p.j;
00307     node_list *p;
00308     node_list *q;
00309 
00310     NOTUSED(dt);
00311 #ifdef DEBUG
00312     if (Verbose >= 3) {
00313         prIndent();
00314         fprintf(stderr, "gridRepulse (%d,%d) : %d\n", i, j,
00315                 gLength(cellp));
00316     }
00317 #endif
00318     for (p = nodes; p != 0; p = p->next) {
00319         for (q = nodes; q != 0; q = q->next)
00320             if (p != q)
00321                 applyRep(p->node, q->node);
00322     }
00323 
00324     doNeighbor(grid, i - 1, j - 1, nodes);
00325     doNeighbor(grid, i - 1, j, nodes);
00326     doNeighbor(grid, i - 1, j + 1, nodes);
00327     doNeighbor(grid, i, j - 1, nodes);
00328     doNeighbor(grid, i, j + 1, nodes);
00329     doNeighbor(grid, i + 1, j - 1, nodes);
00330     doNeighbor(grid, i + 1, j, nodes);
00331     doNeighbor(grid, i + 1, j + 1, nodes);
00332 
00333     return 0;
00334 }
00335 
00336 /* applyAttr:
00337  * Attractive force = weight*(d*d)/K
00338  *  or        force = (d - L(e))*weight(e)
00339  */
00340 static void applyAttr(Agnode_t * p, Agnode_t * q, Agedge_t * e)
00341 {
00342     double xdelta, ydelta;
00343     double force;
00344     double dist;
00345     double dist2;
00346 
00347     xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00348     ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00349     dist2 = xdelta * xdelta + ydelta * ydelta;
00350     while (dist2 == 0.0) {
00351         xdelta = 5 - rand() % 10;
00352         ydelta = 5 - rand() % 10;
00353         dist2 = xdelta * xdelta + ydelta * ydelta;
00354     }
00355     dist = sqrt(dist2);
00356     if (T_useNew)
00357         force = (ED_factor(e) * (dist - ED_dist(e))) / dist;
00358     else
00359         force = (ED_factor(e) * dist) / ED_dist(e);
00360     DISP(q)[0] -= xdelta * force;
00361     DISP(q)[1] -= ydelta * force;
00362     DISP(p)[0] += xdelta * force;
00363     DISP(p)[1] += ydelta * force;
00364 }
00365 
00366 static void updatePos(Agraph_t * g, double temp, bport_t * pp)
00367 {
00368     Agnode_t *n;
00369     double temp2;
00370     double len2;
00371     double x, y, d;
00372     double dx, dy;
00373 
00374     temp2 = temp * temp;
00375     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00376         if (ND_pinned(n) & P_FIX)
00377             continue;
00378         dx = DISP(n)[0];
00379         dy = DISP(n)[1];
00380         len2 = dx * dx + dy * dy;
00381 
00382         /* limit by temperature */
00383         if (len2 < temp2) {
00384             x = ND_pos(n)[0] + dx;
00385             y = ND_pos(n)[1] + dy;
00386         } else {
00387             double fact = temp / (sqrt(len2));
00388             x = ND_pos(n)[0] + dx * fact;
00389             y = ND_pos(n)[1] + dy * fact;
00390         }
00391 
00392         /* if ports, limit by boundary */
00393         if (pp) {
00394             d = sqrt((x * x) / T_Wd2 + (y * y) / T_Ht2);
00395             if (IS_PORT(n)) {
00396                 ND_pos(n)[0] = x / d;
00397                 ND_pos(n)[1] = y / d;
00398             } else if (d >= 1.0) {
00399                 ND_pos(n)[0] = 0.95 * x / d;
00400                 ND_pos(n)[1] = 0.95 * y / d;
00401             } else {
00402                 ND_pos(n)[0] = x;
00403                 ND_pos(n)[1] = y;
00404             }
00405         } else {
00406             ND_pos(n)[0] = x;
00407             ND_pos(n)[1] = y;
00408         }
00409     }
00410 }
00411 
00412 #define FLOOR(d) ((int)floor(d))
00413 
00414 /* gAdjust:
00415  */
00416 static void gAdjust(Agraph_t * g, double temp, bport_t * pp, Grid * grid)
00417 {
00418     Agnode_t *n;
00419     Agedge_t *e;
00420 
00421     if (temp <= 0.0)
00422         return;
00423 
00424     clearGrid(grid);
00425 
00426     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00427         DISP(n)[0] = DISP(n)[1] = 0;
00428         addGrid(grid, FLOOR((ND_pos(n))[0] / T_Cell), FLOOR((ND_pos(n))[1] / T_Cell),
00429                 n);
00430     }
00431 
00432     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00433         for (e = agfstout(g, n); e; e = agnxtout(g, e))
00434             if (n != aghead(e))
00435                 applyAttr(n, aghead(e), e);
00436     }
00437     walkGrid(grid, gridRepulse);
00438 
00439 
00440     updatePos(g, temp, pp);
00441 }
00442 
00443 /* adjust:
00444  */
00445 static void adjust(Agraph_t * g, double temp, bport_t * pp)
00446 {
00447     Agnode_t *n;
00448     Agnode_t *n1;
00449     Agedge_t *e;
00450 
00451     if (temp <= 0.0)
00452         return;
00453 
00454     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00455         DISP(n)[0] = DISP(n)[1] = 0;
00456     }
00457 
00458     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00459         for (n1 = agnxtnode(g, n); n1; n1 = agnxtnode(g, n1)) {
00460             applyRep(n, n1);
00461         }
00462         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00463             if (n != aghead(e))
00464                 applyAttr(n, aghead(e), e);
00465         }
00466     }
00467 
00468     updatePos(g, temp, pp);
00469 }
00470 
00471 /* initPositions:
00472  * Create initial layout of nodes
00473  * TODO :
00474  *  Position nodes near neighbors with positions.
00475  *  Use bbox to reset K.
00476  */
00477 static pointf initPositions(graph_t * g, bport_t * pp)
00478 {
00479     int nG = agnnodes(g) - NPORTS(g);
00480     double size;
00481     Agnode_t *np;
00482     int n_pos = 0;              /* no. of nodes with position info */
00483     box bb = { {0, 0}, {0, 0} };
00484     pointf ctr;                 /* center of boundary ellipse */
00485     long local_seed;
00486     double PItimes2 = M_PI * 2.0;
00487 
00488     for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00489         if (ND_pinned(np)) {
00490             if (n_pos) {
00491                 bb.LL.x = MIN(ND_pos(np)[0], bb.LL.x);
00492                 bb.LL.y = MIN(ND_pos(np)[1], bb.LL.y);
00493                 bb.UR.x = MAX(ND_pos(np)[0], bb.UR.x);
00494                 bb.UR.y = MAX(ND_pos(np)[1], bb.UR.y);
00495             } else {
00496                 bb.UR.x = bb.LL.x = ND_pos(np)[0];
00497                 bb.UR.y = bb.LL.y = ND_pos(np)[1];
00498             }
00499             n_pos++;
00500         }
00501     }
00502 
00503     size = T_K * (sqrt((double) nG) + 1.0);
00504     T_Wd = T_Ht = EXPFACTOR * (size / 2.0);
00505     if (n_pos == 1) {
00506         ctr.x = bb.LL.x;
00507         ctr.y = bb.LL.y;
00508     } else if (n_pos > 1) {
00509         double alpha, area, width, height, quot;
00510         ctr.x = (bb.LL.x + bb.UR.x) / 2.0;
00511         ctr.y = (bb.LL.y + bb.UR.y) / 2.0;
00512         width = EXPFACTOR * (bb.UR.x - bb.LL.x);
00513         height = EXPFACTOR * (bb.UR.y - bb.LL.y);
00514         area = 4.0 * T_Wd * T_Ht;
00515         quot = (width * height) / area;
00516         if (quot >= 1.0) {      /* If bbox has large enough area, use it */
00517             T_Wd = width / 2.0;
00518             T_Ht = height / 2.0;
00519         } else if (quot > 0.0) {        /* else scale up to have enough area */
00520             quot = 2.0 * sqrt(quot);
00521             T_Wd = width / quot;
00522             T_Ht = height / quot;
00523         } else {                /* either width or height is 0 */
00524             if (width > 0) {
00525                 height = area / width;
00526                 T_Wd = width / 2.0;
00527                 T_Ht = height / 2.0;
00528             } else if (height > 0) {
00529                 width = area / height;
00530                 T_Wd = width / 2.0;
00531                 T_Ht = height / 2.0;
00532             }
00533             /* If width = height = 0, use Wd and Ht as defined above for
00534              * the case the n_pos == 0.
00535              */
00536         }
00537 
00538         /* Construct enclosing ellipse */
00539         alpha = atan2(T_Ht, T_Wd);
00540         T_Wd = T_Wd / cos(alpha);
00541         T_Ht = T_Ht / sin(alpha);
00542     } else {
00543         ctr.x = ctr.y = 0;
00544     }
00545     T_Wd2 = T_Wd * T_Wd;
00546     T_Ht2 = T_Ht * T_Ht;
00547 
00548     /* Set seed value */
00549     if (T_smode == INIT_RANDOM)
00550         local_seed = T_seed;
00551     else {
00552 #if defined(MSWIN32) || defined(WIN32)
00553         local_seed = time(NULL);
00554 #else
00555         local_seed = getpid() ^ time(NULL);
00556 #endif
00557     }
00558     srand48(local_seed);
00559 
00560     /* If ports, place ports on and nodes within an ellipse centered at origin
00561      * with halfwidth Wd and halfheight Ht. 
00562      * If no ports, place nodes within a rectangle centered at origin
00563      * with halfwidth Wd and halfheight Ht. Nodes with a given position
00564      * are translated. Wd and Ht are set to contain all positioned points.
00565      * The reverse translation will be applied to all
00566      * nodes at the end of the layout.
00567      * TODO: place unfixed points using adjacent ports or fixed pts.
00568      */
00569     if (pp) {
00570 /* fprintf (stderr, "initPos %s ctr (%g,%g) Wd %g Ht %g\n", g->name, ctr.x, ctr.y, Wd, Ht); */
00571         while (pp->e) {         /* position ports on ellipse */
00572             np = pp->n;
00573             ND_pos(np)[0] = T_Wd * cos(pp->alpha) + ctr.x;
00574             ND_pos(np)[1] = T_Ht * sin(pp->alpha) + ctr.y;
00575             ND_pinned(np) = P_SET;
00576 /* fprintf (stderr, "%s pt (%g,%g) %g\n", np->name, ND_pos(np)[0], ND_pos(np)[1], pp->alpha); */
00577             pp++;
00578         }
00579         for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00580             if (IS_PORT(np))
00581                 continue;
00582             if (ND_pinned(np)) {
00583                 ND_pos(np)[0] -= ctr.x;
00584                 ND_pos(np)[1] -= ctr.y;
00585             } else {
00586                 pointf p = { 0.0, 0.0 };
00587                 int cnt = 0;
00588                 node_t *op;
00589                 edge_t *ep;
00590                 for (ep = agfstedge(g, np); ep; ep = agnxtedge(g, ep, np)) {
00591                     if (aghead(ep) == agtail(ep))
00592                         continue;
00593                     op = (aghead(ep) == np ? agtail(ep) : aghead(ep));
00594                     if (!hasPos(op))
00595                         continue;
00596                     if (cnt) {
00597                         p.x = (p.x * cnt + ND_pos(op)[0]) / (cnt + 1);
00598                         p.y = (p.y * cnt + ND_pos(op)[1]) / (cnt + 1);
00599                     } else {
00600                         p.x = ND_pos(op)[0];
00601                         p.y = ND_pos(op)[1];
00602                     }
00603                     cnt++;
00604                 }
00605                 if (cnt > 1) {
00606                     ND_pos(np)[0] = p.x;
00607                     ND_pos(np)[1] = p.y;
00608 /* fprintf (stderr, "%s 1 (%g,%g)\n", np->name, p.x, p.y); */
00609                 } else if (cnt == 1) {
00610                     ND_pos(np)[0] = 0.98 * p.x + 0.1 * ctr.x;
00611                     ND_pos(np)[1] = 0.9 * p.y + 0.1 * ctr.y;
00612 /* fprintf (stderr, "%s %d (%g,%g)\n", np->name, cnt, ND_pos(np)[0], ND_pos(np)[1]); */
00613                 } else {
00614                     double angle = PItimes2 * drand48();
00615                     double radius = 0.9 * drand48();
00616                     ND_pos(np)[0] = radius * T_Wd * cos(angle);
00617                     ND_pos(np)[1] = radius * T_Ht * sin(angle);
00618 /* fprintf (stderr, "%s 0 (%g,%g)\n", np->name, ND_pos(np)[0], ND_pos(np)[1]); */
00619                 }
00620                 ND_pinned(np) = P_SET;
00621             }
00622         }
00623     } else {
00624         if (n_pos) {            /* If positioned nodes */
00625             for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00626                 if (ND_pinned(np)) {
00627                     ND_pos(np)[0] -= ctr.x;
00628                     ND_pos(np)[1] -= ctr.y;
00629                 } else {
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         } else {                /* No ports or positions; place randomly */
00635             for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00636                 ND_pos(np)[0] = T_Wd * (2.0 * drand48() - 1.0);
00637                 ND_pos(np)[1] = T_Ht * (2.0 * drand48() - 1.0);
00638             }
00639         }
00640     }
00641 
00642     return ctr;
00643 }
00644 
00645 void dumpstat(graph_t * g)
00646 {
00647     double dx, dy;
00648     double l, max2 = 0.0;
00649     node_t *np;
00650     edge_t *ep;
00651     for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00652         dx = DISP(np)[0];
00653         dy = DISP(np)[1];
00654         l = dx * dx + dy * dy;
00655         if (l > max2)
00656             max2 = l;
00657         fprintf(stderr, "%s: (%f,%f) (%f,%f)\n", agnameof(np),
00658                 ND_pos(np)[0], ND_pos(np)[1], DISP(np)[0], DISP(np)[1]);
00659     }
00660     fprintf(stderr, "max delta = %f\n", sqrt(max2));
00661     for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
00662         for (ep = agfstout(g, np); ep; ep = agnxtout(g, ep)) {
00663             dx = ND_pos(np)[0] - ND_pos(aghead(ep))[0];
00664             dy = ND_pos(np)[1] - ND_pos(aghead(ep))[1];
00665             fprintf(stderr, "  %s --  %s  (%f)\n", agnameof(np),
00666                     agnameof(aghead(ep)), sqrt(dx * dx + dy * dy));
00667         }
00668     }
00669 }
00670 
00671 /* fdp_tLayout:
00672  * Given graph g with ports nodes, layout g respecting ports.
00673  * If some node have position information, it may be useful to
00674  * reset temperature and other parameters to reflect this.
00675  */
00676 void fdp_tLayout(graph_t * g, xparams * xpms)
00677 {
00678     int i;
00679     int reset;
00680     bport_t *pp = PORTS(g);
00681     double temp;
00682     Grid *grid;
00683     pointf ctr;
00684     Agnode_t *n;
00685 
00686     reset = init_params(g, xpms);
00687     temp = T_T0;
00688 
00689     ctr = initPositions(g, pp);
00690 
00691     if (T_useGrid) {
00692         grid = mkGrid(agnnodes(g));
00693         adjustGrid(grid, agnnodes(g));
00694         for (i = 0; i < T_loopcnt; i++) {
00695             temp = cool(temp, i);
00696             gAdjust(g, temp, pp, grid);
00697         }
00698         delGrid(grid);
00699     } else {
00700         for (i = 0; i < T_loopcnt; i++) {
00701             temp = cool(temp, i);
00702             adjust(g, temp, pp);
00703         }
00704     }
00705 
00706     if ((ctr.x != 0.0) || (ctr.y != 0.0)) {
00707         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00708             ND_pos(n)[0] += ctr.x;
00709             ND_pos(n)[1] += ctr.y;
00710         }
00711     }
00712 /* dumpstat (g); */
00713     if (reset)
00714         reset_params();
00715 }