|
Graphviz
2.29.20120524.0446
|
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 }
1.7.5