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 #ifdef FIX
00026 Allow sep to be absolute additive (margin of n points)
00027 Increase less between tries
00028 #endif
00029
00030
00031 #define FDP_PRIVATE 1
00032
00033 #include <xlayout.h>
00034 #include <adjust.h>
00035 #include <dbg.h>
00036
00037
00038
00039
00040
00041
00042
00043 #define BOX
00044
00045 #define DFLT_overlap "9:portho"
00046
00047 #define WD2(n) ((ND_width(n))*X_fact)
00048 #define HT2(n) ((ND_height(n))*X_fact)
00049
00050 static xparams xParams = {
00051 60,
00052 0.0,
00053 0.3,
00054 1.5,
00055 0
00056 };
00057 static double K2;
00058 static double X_fact;
00059 static double X_nonov;
00060 static double X_ov;
00061
00062 static double RAD(Agnode_t * n)
00063 {
00064 double w = WD2(n);
00065 double h = HT2(n);
00066 return sqrt(w * w + h * h);
00067 }
00068
00069
00070
00071
00072 static void xinit_params(graph_t* g, int n, xparams * xpms)
00073 {
00074 xParams.K = xpms->K;
00075 xParams.numIters = xpms->numIters;
00076 xParams.T0 = xpms->T0;
00077 xParams.loopcnt = xpms->loopcnt;
00078 if (xpms->C > 0.0)
00079 xParams.C = xpms->C;
00080 K2 = xParams.K * xParams.K;
00081 if (xParams.T0 == 0.0)
00082 xParams.T0 = xParams.K * sqrt(n) / 5;
00083 #ifdef DEBUG
00084 if (Verbose) {
00085 prIndent();
00086 fprintf(stderr,
00087 "xLayout %s(%s) : n = %d K = %f T0 = %f loop %d C %f\n",
00088 g->name, GORIG(g->root)->name,
00089 xParams.numIters, xParams.K, xParams.T0, xParams.loopcnt,
00090 xParams.C);
00091 }
00092 #endif
00093 }
00094
00095 #define X_T0 xParams.T0
00096 #define X_K xParams.K
00097 #define X_numIters xParams.numIters
00098 #define X_loopcnt xParams.loopcnt
00099 #define X_C xParams.C
00100
00101
00102 static double cool(int t)
00103 {
00104 return (X_T0 * (X_numIters - t)) / X_numIters;
00105 }
00106
00107 #define EPSILON 0.01
00108
00109 #ifdef MS
00110
00111
00112
00113 static double dist(pointf p, pointf q)
00114 {
00115 double dx, dy;
00116
00117 dx = p.x - q.x;
00118 dy = p.y - q.y;
00119 return (sqrt(dx * dx + dy * dy));
00120 }
00121
00122
00123
00124
00125 static void bBox(node_t * p, pointf * ll, pointf * ur)
00126 {
00127 double w2 = WD2(p);
00128 double h2 = HT2(p);
00129
00130 ur->x = ND_pos(p)[0] + w2;
00131 ur->y = ND_pos(p)[1] + h2;
00132 ll->x = ND_pos(p)[0] - w2;
00133 ll->y = ND_pos(p)[1] - h2;
00134 }
00135
00136
00137
00138
00139 static double boxDist(node_t * p, node_t * q)
00140 {
00141 pointf p_ll, p_ur;
00142 pointf q_ll, q_ur;
00143
00144 bBox(p, &p_ll, &p_ur);
00145 bBox(q, &q_ll, &q_ur);
00146
00147 if (q_ll.x > p_ur.x) {
00148 if (q_ll.y > p_ur.y) {
00149 return (dist(p_ur, q_ll));
00150 } else if (q_ll.y >= p_ll.y) {
00151 return (q_ll.x - p_ur.x);
00152 } else {
00153 if (q_ur.y >= p_ll.y)
00154 return (q_ll.x - p_ur.x);
00155 else {
00156 p_ur.y = p_ll.y;
00157 q_ll.y = q_ur.y;
00158 return (dist(p_ur, q_ll));
00159 }
00160 }
00161 } else if (q_ll.x >= p_ll.x) {
00162 if (q_ll.y > p_ur.y) {
00163 return (q_ll.y - p_ur.x);
00164 } else if (q_ll.y >= p_ll.y) {
00165 return 0.0;
00166 } else {
00167 if (q_ur.y >= p_ll.y)
00168 return 0.0;
00169 else
00170 return (p_ll.y - q_ur.y);
00171 }
00172 } else {
00173 if (q_ll.y > p_ur.y) {
00174 if (q_ur.x >= p_ll.x)
00175 return (q_ll.y - p_ur.y);
00176 else {
00177 p_ur.x = p_ll.x;
00178 q_ll.x = q_ur.x;
00179 return (dist(p_ur, q_ll));
00180 }
00181 } else if (q_ll.y >= p_ll.y) {
00182 if (q_ur.x >= p_ll.x)
00183 return 0.0;
00184 else
00185 return (p_ll.x - q_ur.x);
00186 } else {
00187 if (q_ur.x >= p_ll.x) {
00188 if (q_ur.y >= p_ll.y)
00189 return 0.0;
00190 else
00191 return (p_ll.y - q_ur.y);
00192 } else {
00193 if (q_ur.y >= p_ll.y)
00194 return (p_ll.x - q_ur.x);
00195 else
00196 return (dist(p_ll, q_ur));
00197 }
00198 }
00199 }
00200 }
00201 #endif
00202
00203
00204
00205
00206 static int overlap(node_t * p, node_t * q)
00207 {
00208 #if defined(BOX)
00209 double xdelta, ydelta;
00210 int ret;
00211
00212 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00213 if (xdelta < 0)
00214 xdelta = -xdelta;
00215 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00216 if (ydelta < 0)
00217 ydelta = -ydelta;
00218 ret = ((xdelta <= (WD2(p) + WD2(q))) && (ydelta <= (HT2(p) + HT2(q))));
00219 return ret;
00220 #else
00221 double dist2, xdelta, ydelta;
00222 double din;
00223
00224 din = RAD(p) + RAD(q);
00225 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00226 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00227 dist2 = xdelta * xdelta + ydelta * ydelta;
00228 return (dist2 <= (din * din));
00229 #endif
00230 }
00231
00232
00233
00234
00235 static int cntOverlaps(graph_t * g)
00236 {
00237 node_t *p;
00238 node_t *q;
00239 int cnt = 0;
00240
00241 for (p = agfstnode(g); p; p = agnxtnode(g, p)) {
00242 for (q = agnxtnode(g, p); q; q = agnxtnode(g, q)) {
00243 cnt += overlap(p, q);
00244 }
00245 }
00246 return cnt;
00247 }
00248
00249
00250
00251
00252 static int
00253 doRep(node_t * p, node_t * q, double xdelta, double ydelta, double dist2)
00254 {
00255 int ov;
00256 double force;
00257
00258 #if defined(DEBUG) || defined(MS) || defined(ALT)
00259 double dist;
00260 #endif
00261
00262
00263 while (dist2 == 0.0) {
00264 xdelta = 5 - rand() % 10;
00265 ydelta = 5 - rand() % 10;
00266 dist2 = xdelta * xdelta + ydelta * ydelta;
00267 }
00268 #if defined(MS)
00269 dout = boxDist(p, q);
00270 if (dout < EPSILON)
00271 dout = EPSILON;
00272 dist = sqrt(dist2);
00273 force = K2 / (dout * dist);
00274 #elif defined(ALT)
00275 force = K2 / dist2;
00276 dist = sqrt(dist2);
00277 din = RAD(p) + RAD(q);
00278 if (ov = overlap(p, q)) {
00279 factor = X_C;
00280 } else {
00281 ov = 0;
00282 if (dist <= din + X_K)
00283 factor = X_C * (X_K - (dist - din)) / X_K;
00284 else
00285 factor = 0.0;
00286 }
00287 force *= factor;
00288 #elif defined(ORIG)
00289 force = K2 / dist2;
00290 if ((ov = overlap(p, q)))
00291 force *= X_C;
00292 #else
00293 if ((ov = overlap(p, q)))
00294 force = X_ov / dist2;
00295 else
00296 force = X_nonov / dist2;
00297 #endif
00298 #ifdef DEBUG
00299 if (Verbose == 4) {
00300 prIndent();
00301 dist = sqrt(dist2);
00302 fprintf(stderr, " ov Fr %f dist %f\n", force * dist, dist);
00303 }
00304 #endif
00305 DISP(q)[0] += xdelta * force;
00306 DISP(q)[1] += ydelta * force;
00307 DISP(p)[0] -= xdelta * force;
00308 DISP(p)[1] -= ydelta * force;
00309 return ov;
00310 }
00311
00312
00313
00314
00315
00316 static int applyRep(Agnode_t * p, Agnode_t * q)
00317 {
00318 double xdelta, ydelta;
00319
00320 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00321 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00322 return doRep(p, q, xdelta, ydelta, xdelta * xdelta + ydelta * ydelta);
00323 }
00324
00325 static void applyAttr(Agnode_t * p, Agnode_t * q)
00326 {
00327 double xdelta, ydelta;
00328 double force;
00329 double dist;
00330 double dout;
00331 double din;
00332
00333 #if defined(MS)
00334 dout = boxDist(p, q);
00335 if (dout == 0.0)
00336 return;
00337 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00338 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00339 dist = sqrt(xdelta * xdelta + ydelta * ydelta);
00340 force = (dout * dout) / (X_K * dist);
00341 #elif defined(ALT)
00342 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00343 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00344 dist = sqrt(xdelta * xdelta + ydelta * ydelta);
00345 din = RAD(p) + RAD(q);
00346 if (dist < X_K + din)
00347 return;
00348 dout = dist - din;
00349 force = (dout * dout) / ((X_K + din) * dist);
00350 #else
00351 if (overlap(p, q)) {
00352 #ifdef DEBUG
00353 if (Verbose == 4) {
00354 prIndent();
00355 fprintf(stderr, "ov 1 Fa 0 din %f\n", RAD(p) + RAD(q));
00356 }
00357 #endif
00358 return;
00359 }
00360 xdelta = ND_pos(q)[0] - ND_pos(p)[0];
00361 ydelta = ND_pos(q)[1] - ND_pos(p)[1];
00362 dist = sqrt(xdelta * xdelta + ydelta * ydelta);
00363 din = RAD(p) + RAD(q);
00364 dout = dist - din;
00365 force = (dout * dout) / ((X_K + din) * dist);
00366 #endif
00367 #ifdef DEBUG
00368 if (Verbose == 4) {
00369 prIndent();
00370 fprintf(stderr, " ov 0 Fa %f din %f \n", force * dist, din);
00371 }
00372 #endif
00373 DISP(q)[0] -= xdelta * force;
00374 DISP(q)[1] -= ydelta * force;
00375 DISP(p)[0] += xdelta * force;
00376 DISP(p)[1] += ydelta * force;
00377 }
00378
00379
00380
00381
00382
00383 static int adjust(Agraph_t * g, double temp)
00384 {
00385 Agnode_t *n;
00386 Agnode_t *n1;
00387 Agedge_t *e;
00388 double temp2;
00389 double len;
00390 double len2;
00391 double disp[NDIM];
00392 int overlaps = 0;
00393
00394 #ifdef DEBUG
00395 if (Verbose == 4)
00396 fprintf(stderr, "=================\n");
00397 #endif
00398
00399 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00400 DISP(n)[0] = DISP(n)[1] = 0;
00401 }
00402
00403 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00404 int ov;
00405 for (n1 = agnxtnode(g, n); n1; n1 = agnxtnode(g, n1)) {
00406 ov = applyRep(n, n1);
00407
00408
00409 overlaps += ov;
00410 }
00411 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00412 applyAttr(n, e->head);
00413 }
00414 }
00415 if (overlaps == 0)
00416 return 0;
00417
00418 temp2 = temp * temp;
00419 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00420 if (ND_pinned(n) == P_PIN)
00421 continue;
00422 disp[0] = DISP(n)[0];
00423 disp[1] = DISP(n)[1];
00424 len2 = disp[0] * disp[0] + disp[1] * disp[1];
00425
00426 if (len2 < temp2) {
00427 ND_pos(n)[0] += disp[0];
00428 ND_pos(n)[1] += disp[1];
00429 } else {
00430
00431 len = sqrt(len2);
00432 ND_pos(n)[0] += (disp[0] * temp) / len;
00433 ND_pos(n)[1] += (disp[1] * temp) / len;
00434 }
00435 }
00436 return overlaps;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 static int x_layout(graph_t * g, xparams * pxpms, int tries)
00452 {
00453 int i;
00454 int try;
00455 int ov;
00456 double temp;
00457 int nnodes = agnnodes(g);
00458 int nedges = agnedges(g);
00459 double K;
00460 xparams xpms;
00461 double marg;
00462
00463 marg = expFactor (g);
00464 X_fact = marg*0.5;
00465 ov = cntOverlaps(g);
00466 if (ov == 0)
00467 return 0;
00468
00469 try = 0;
00470 xpms = *pxpms;
00471 K = xpms.K;
00472 while (ov && (try < tries)) {
00473 xinit_params(g, nnodes, &xpms);
00474 X_ov = X_C * K2;
00475 X_nonov = (nedges*X_ov*2.0)/(nnodes*(nnodes-1));
00476 #ifdef DEBUG
00477 if (Verbose) {
00478 prIndent();
00479 fprintf(stderr, "try %d (%d): %d overlaps on %s(%s) \n", try, tries, ov,
00480 g->name, GORIG(g->root)->name);
00481 }
00482 #endif
00483
00484 for (i = 0; i < X_loopcnt; i++) {
00485 temp = cool(i);
00486 if (temp <= 0.0)
00487 break;
00488 ov = adjust(g, temp);
00489 if (ov == 0)
00490 break;
00491 }
00492 try++;
00493 xpms.K += K;
00494 }
00495 #ifdef DEBUG
00496 if (Verbose && ov)
00497 fprintf(stderr, "Warning: %d overlaps remain on %s(%s)\n", ov,
00498 g->name, GORIG(g->root)->name);
00499 #endif
00500
00501 return ov;
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517 void fdp_xLayout(graph_t * g, xparams * xpms)
00518 {
00519 int tries;
00520 char* ovlp = agget (g, "overlap");
00521 char* cp;
00522 char* rest;
00523
00524 if (Verbose) {
00525 #ifdef DEBUG
00526 prIndent();
00527 #endif
00528 fprintf (stderr, "xLayout ");
00529 }
00530 if (!ovlp || (*ovlp == '\0')) {
00531 ovlp = DFLT_overlap;
00532 }
00533 if ((cp = strchr(ovlp, ':'))) {
00534 cp++;
00535 rest = cp;
00536 tries = atoi (ovlp);
00537 if (tries < 0) tries = 0;
00538 }
00539 else {
00540 tries = 0;
00541 rest = ovlp;
00542 }
00543 if (Verbose) {
00544 #ifdef DEBUG
00545 prIndent();
00546 #endif
00547 fprintf (stderr, "tries = %d, mode = %s\n", tries, rest);
00548 }
00549 if (tries && !x_layout(g, xpms, tries))
00550 return;
00551 removeOverlapAs(g, rest);
00552
00553 }