00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 #include "config.h"
00020 #endif
00021
00022 #include "neato.h"
00023 #include "adjust.h"
00024
00025
00026 #define SCALE 10
00027 #define SCALE2 (SCALE/2)
00028
00029 typedef struct nitem {
00030 Dtlink_t link;
00031 int val;
00032 point pos;
00033 node_t *np;
00034 node_t *cnode;
00035 node_t *vnode;
00036 box bb;
00037 } nitem;
00038
00039 typedef int (*distfn) (box *, box *);
00040 typedef int (*intersectfn) (nitem *, nitem *);
00041
00042 static int cmpitem(Dt_t * d, int *p1, int *p2, Dtdisc_t * disc)
00043 {
00044 NOTUSED(d);
00045 NOTUSED(disc);
00046
00047 return (*p1 - *p2);
00048 }
00049
00050 static Dtdisc_t constr = {
00051 offsetof(nitem, val),
00052 sizeof(int),
00053 offsetof(nitem, link),
00054 NIL(Dtmake_f),
00055 NIL(Dtfree_f),
00056 (Dtcompar_f) cmpitem,
00057 NIL(Dthash_f),
00058 NIL(Dtmemory_f),
00059 NIL(Dtevent_f)
00060 };
00061
00062 static int distY(box * b1, box * b2)
00063 {
00064 return ((b1->UR.y - b1->LL.y) + (b2->UR.y - b2->LL.y)) / 2;
00065 }
00066
00067 static int distX(box * b1, box * b2)
00068 {
00069 return ((b1->UR.x - b1->LL.x) + (b2->UR.x - b2->LL.x)) / 2;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078 static int intersectX0(nitem * p, nitem * q)
00079 {
00080 int xdelta, ydelta;
00081 int v = ((p->bb.LL.x <= q->bb.UR.x) && (q->bb.LL.x <= p->bb.UR.x));
00082 if (v == 0)
00083 return 0;
00084 if (p->bb.UR.y < q->bb.LL.y)
00085 return 1;
00086 ydelta = distY(&p->bb,&q->bb) - (q->pos.y - p->pos.y);
00087 if (q->pos.x >= p->pos.x)
00088 xdelta = distX(&p->bb,&q->bb) - (q->pos.x - p->pos.x);
00089 else
00090 xdelta = distX(&p->bb,&q->bb) - (p->pos.x - q->pos.x);
00091 return (ydelta <= xdelta);
00092 }
00093
00094
00095
00096
00097
00098
00099
00100 static int intersectY0(nitem * p, nitem * q)
00101 {
00102 int xdelta, ydelta;
00103 int v = ((p->bb.LL.y <= q->bb.UR.y) && (q->bb.LL.y <= p->bb.UR.y));
00104 if (v == 0)
00105 return 0;
00106 if (p->bb.UR.x < q->bb.LL.x)
00107 return 1;
00108 xdelta = distX(&p->bb,&q->bb) - (q->pos.x - p->pos.x);
00109 if (q->pos.y >= p->pos.y)
00110 ydelta = distY(&p->bb,&q->bb) - (q->pos.y - p->pos.y);
00111 else
00112 ydelta = distY(&p->bb,&q->bb) - (p->pos.y - q->pos.y);
00113 return (xdelta <= ydelta);
00114 }
00115
00116 static int intersectY(nitem * p, nitem * q)
00117 {
00118 return ((p->bb.LL.y <= q->bb.UR.y) && (q->bb.LL.y <= p->bb.UR.y));
00119 }
00120
00121 static int intersectX(nitem * p, nitem * q)
00122 {
00123 return ((p->bb.LL.x <= q->bb.UR.x) && (q->bb.LL.x <= p->bb.UR.x));
00124 }
00125
00126
00127
00128 static void mapGraphs(graph_t * g, graph_t * cg, distfn dist)
00129 {
00130 node_t *n;
00131 edge_t *e;
00132 edge_t *ce;
00133 node_t *t;
00134 node_t *h;
00135 nitem *tp;
00136 nitem *hp;
00137 int delta;
00138
00139 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00140 tp = (nitem *) ND_alg(n);
00141 t = tp->cnode;
00142 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00143 hp = (nitem *) ND_alg(e->head);
00144 delta = dist(&tp->bb, &hp->bb);
00145 h = hp->cnode;
00146 ce = agedge(cg, t, h);
00147 ED_weight(ce) = 1;
00148 if (ED_minlen(ce) < delta) {
00149 if (ED_minlen(ce) == 0.0) {
00150 elist_append(ce, ND_out(t));
00151 elist_append(ce, ND_in(h));
00152 }
00153 ED_minlen(ce) = delta;
00154 }
00155 }
00156 }
00157 }
00158
00159 #ifdef DEBUG
00160 static int
00161 indegree (graph_t * g, node_t *n)
00162 {
00163 edge_t *e;
00164 int cnt = 0;
00165 for (e = agfstin(g,n); e; e = agnxtin(g,e)) cnt++;
00166 return cnt;
00167 }
00168
00169 static int
00170 outdegree (graph_t * g, node_t *n)
00171 {
00172 edge_t *e;
00173 int cnt = 0;
00174 for (e = agfstout(g,n); e; e = agnxtout(g,e)) cnt++;
00175 return cnt;
00176 }
00177
00178 static void
00179 validate(graph_t * g)
00180 {
00181 node_t *n;
00182 edge_t *e;
00183 int i, cnt;
00184
00185 cnt = 0;
00186 for (n = GD_nlist(g);n; n = ND_next(n)) {
00187 assert(outdegree(g,n) == ND_out(n).size);
00188 for (i = 0; (e = ND_out(n).list[i]); i++) {
00189 assert(e->tail == n);
00190 assert( e == agfindedge(g, n, e->head));
00191 }
00192 assert(indegree(g,n) == ND_in(n).size);
00193 for (i = 0; (e = ND_in(n).list[i]); i++) {
00194 assert(e->head == n);
00195 assert( e == agfindedge(g, e->tail, n));
00196 }
00197 cnt++;
00198 }
00199
00200 assert (agnnodes(g) == cnt);
00201 }
00202 #endif
00203
00204 #ifdef OLD
00205 static node_t *newNode(graph_t * g)
00206 {
00207 static int id = 0;
00208 char buf[100];
00209
00210 sprintf(buf, "n%d", id++);
00211 return agnode(g, buf);
00212 }
00213 #endif
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 static graph_t *mkNConstraintG(graph_t * g, Dt_t * list,
00224 intersectfn intersect, distfn dist)
00225 {
00226 nitem *p;
00227 nitem *nxp;
00228 graph_t *cg = agopen("cg", AGDIGRAPHSTRICT);
00229 node_t *n;
00230 edge_t *e;
00231 node_t *lastn = NULL;
00232
00233 for (p = (nitem *) dtflatten(list); p;
00234 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
00235 n = agnode(cg, p->np->name);
00236 ND_alg(n) = p;
00237 p->cnode = n;
00238 alloc_elist(0, ND_in(n));
00239 alloc_elist(0, ND_out(n));
00240 if (lastn) {
00241 ND_next(lastn) = n;
00242 lastn = n;
00243 } else {
00244 lastn = GD_nlist(cg) = n;
00245 }
00246 }
00247 for (p = (nitem *) dtflatten(list); p;
00248 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
00249 for (nxp = (nitem *) dtlink(link, (Dtlink_t *) p); nxp;
00250 nxp = (nitem *) dtlink(list, (Dtlink_t *) nxp)) {
00251 e = NULL;
00252 if (intersect(p, nxp)) {
00253 double delta = dist(&p->bb, &nxp->bb);
00254 e = agedge(cg, p->cnode, nxp->cnode);
00255 assert (delta <= 0xFFFF);
00256 ED_minlen(e) = delta;
00257 ED_weight(e) = 1;
00258 }
00259 if (e && agfindedge(g,p->np, nxp->np)) {
00260 ED_weight(e) = 100;
00261 }
00262 #if 0
00263 if (agfindedge(g,p->np, nxp->np)) {
00264 if (e == NULL)
00265 e = agedge(cg, p->cnode, nxp->cnode);
00266 ED_weight(e) = 100;
00267
00268
00269
00270
00271 if (SCALE > ED_minlen(e))
00272 ED_minlen(e) = SCALE;
00273 }
00274 #endif
00275 }
00276 }
00277
00278 for (p = (nitem *) dtflatten(list); p;
00279 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
00280 n = p->cnode;
00281 for (e = agfstout(cg,n); e; e = agnxtout(cg,e)) {
00282 elist_append(e, ND_out(n));
00283 elist_append(e, ND_in(e->head));
00284 }
00285 }
00286
00287
00288
00289
00290
00291
00292 return cg;
00293 }
00294
00295
00296 static graph_t *mkConstraintG(graph_t * g, Dt_t * list,
00297 intersectfn intersect, distfn dist)
00298 {
00299 nitem *p;
00300 nitem *nxt = NULL;
00301 nitem *nxp;
00302 graph_t *cg = agopen("cg", AGDIGRAPHSTRICT);
00303 graph_t *vg;
00304 node_t *prev = NULL;
00305 node_t *root = NULL;
00306 node_t *n = NULL;
00307 edge_t *e;
00308 int lcnt, cnt;
00309 int oldval = -INT_MAX;
00310 #ifdef OLD
00311 double root_val;
00312 #endif
00313 node_t *lastn = NULL;
00314
00315
00316 cnt = 0;
00317 for (p = (nitem *) dtflatten(list); p;
00318 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
00319 if (oldval != p->val) {
00320 oldval = p->val;
00321 cnt++;
00322 }
00323 }
00324
00325
00326 oldval = -INT_MAX;
00327 lcnt = 0;
00328 for (p = (nitem *) dtflatten(list); p;
00329 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
00330 if (oldval != p->val) {
00331 oldval = p->val;
00332
00333 n = agnode(cg, p->np->name);
00334 ND_alg(n) = p;
00335 if (root) {
00336 ND_next(lastn) = n;
00337 lastn = n;
00338 } else {
00339 root = n;
00340 #ifdef OLD
00341 root_val = p->val;
00342 #endif
00343 lastn = GD_nlist(cg) = n;
00344 }
00345 alloc_elist(lcnt, ND_in(n));
00346 if (prev) {
00347 if (prev == root)
00348 alloc_elist(2 * (cnt - 1), ND_out(prev));
00349 else
00350 alloc_elist(cnt - lcnt - 1, ND_out(prev));
00351 e = agedge(cg, prev, n);
00352 ED_minlen(e) = SCALE;
00353 ED_weight(e) = 1;
00354 elist_append(e, ND_out(prev));
00355 elist_append(e, ND_in(n));
00356 }
00357 lcnt++;
00358 prev = n;
00359 }
00360 p->cnode = n;
00361 }
00362 alloc_elist(0, ND_out(prev));
00363
00364
00365
00366
00367
00368
00369 vg = agopen("vg", AGDIGRAPHSTRICT);
00370 for (p = (nitem *) dtflatten(list); p;
00371 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
00372 n = agnode(vg, p->np->name);
00373 p->vnode = n;
00374 ND_alg(n) = p;
00375 }
00376 oldval = -INT_MAX;
00377 for (p = (nitem *) dtflatten(list); p;
00378 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
00379 if (oldval != p->val) {
00380 oldval = p->val;
00381 for (nxt = (nitem *) dtlink(link, (Dtlink_t *) p); nxt;
00382 nxt = (nitem *) dtlink(list, (Dtlink_t *) nxt)) {
00383 if (nxt->val != oldval)
00384 break;
00385 }
00386 if (!nxt)
00387 break;
00388 }
00389 for (nxp = nxt; nxp;
00390 nxp = (nitem *) dtlink(list, (Dtlink_t *) nxp)) {
00391 if (intersect(p, nxp))
00392 agedge(vg, p->vnode, nxp->vnode);
00393 }
00394 }
00395
00396
00397
00398
00399
00400 mapGraphs(vg, cg, dist);
00401 agclose(vg);
00402
00403
00404 #ifdef OLD
00405 for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) {
00406 node_t *vn;
00407 node_t *an;
00408
00409 p = (nitem *) ND_alg(n);
00410 if ((n == root) || (!p))
00411 continue;
00412 vn = newNode(cg);
00413 ND_next(lastn) = vn;
00414 lastn = vn;
00415 alloc_elist(0, ND_out(vn));
00416 alloc_elist(2, ND_in(vn));
00417 an = newNode(cg);
00418 ND_next(lastn) = an;
00419 lastn = an;
00420 alloc_elist(1, ND_in(an));
00421 alloc_elist(1, ND_out(an));
00422
00423 e = agedge(cg, root, an);
00424 ED_minlen(e) = p->val - root_val;
00425 elist_append(e, ND_out(root));
00426 elist_append(e, ND_in(an));
00427
00428 e = agedge(cg, an, vn);
00429 elist_append(e, ND_out(an));
00430 elist_append(e, ND_in(vn));
00431
00432 e = agedge(cg, n, vn);
00433 elist_append(e, ND_out(n));
00434 elist_append(e, ND_in(vn));
00435 }
00436 #endif
00437
00438 return cg;
00439 }
00440
00441 static void closeGraph(graph_t * cg)
00442 {
00443 node_t *n;
00444 for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) {
00445 free_list(ND_in(n));
00446 free_list(ND_out(n));
00447 }
00448 agclose(cg);
00449 }
00450
00451
00452
00453
00454
00455
00456 static void constrainX(graph_t* g, nitem* nlist, int nnodes, intersectfn ifn,
00457 int ortho)
00458 {
00459 Dt_t *list = dtopen(&constr, Dtobag);
00460 nitem *p = nlist;
00461 graph_t *cg;
00462 int i;
00463
00464 for (i = 0; i < nnodes; i++) {
00465 p->val = p->pos.x;
00466 dtinsert(list, p);
00467 p++;
00468 }
00469 if (ortho)
00470 cg = mkConstraintG(g, list, ifn, distX);
00471 else
00472 cg = mkNConstraintG(g, list, ifn, distX);
00473 rank(cg, 2, INT_MAX);
00474
00475 p = nlist;
00476 for (i = 0; i < nnodes; i++) {
00477 int newpos, oldpos, delta;
00478 oldpos = p->pos.x;
00479 newpos = ND_rank(p->cnode);
00480 delta = newpos - oldpos;
00481 p->pos.x = newpos;
00482 p->bb.LL.x += delta;
00483 p->bb.UR.x += delta;
00484 p++;
00485 }
00486
00487 closeGraph(cg);
00488 dtclose(list);
00489 }
00490
00491
00492
00493
00494 static void constrainY(graph_t* g, nitem* nlist, int nnodes, intersectfn ifn,
00495 int ortho)
00496 {
00497 Dt_t *list = dtopen(&constr, Dtobag);
00498 nitem *p = nlist;
00499 graph_t *cg;
00500 int i;
00501
00502 for (i = 0; i < nnodes; i++) {
00503 p->val = p->pos.y;
00504 dtinsert(list, p);
00505 p++;
00506 }
00507 if (ortho)
00508 cg = mkConstraintG(g, list, ifn, distY);
00509 else
00510 cg = mkNConstraintG(g, list, ifn, distY);
00511 rank(cg, 2, INT_MAX);
00512 #ifdef DEBUG
00513 {
00514 Agsym_t *mlsym = agedgeattr(cg, "minlen", "");
00515 Agsym_t *rksym = agnodeattr(cg, "rank", "");
00516 char buf[100];
00517 node_t *n;
00518 edge_t *e;
00519 for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) {
00520 sprintf(buf, "%d", ND_rank(n));
00521 agxset(n, rksym->index, buf);
00522 for (e = agfstedge(cg, n); e; e = agnxtedge(cg, e, n)) {
00523 sprintf(buf, "%d", ED_minlen(e));
00524 agxset(e, mlsym->index, buf);
00525 }
00526 }
00527 }
00528 #endif
00529
00530 p = nlist;
00531 for (i = 0; i < nnodes; i++) {
00532 int newpos, oldpos, delta;
00533 oldpos = p->pos.y;
00534 newpos = ND_rank(p->cnode);
00535 delta = newpos - oldpos;
00536 p->pos.y = newpos;
00537 p->bb.LL.y += delta;
00538 p->bb.UR.y += delta;
00539 p++;
00540 }
00541
00542 closeGraph(cg);
00543 dtclose(list);
00544 }
00545
00546 #define overlap(pb,qb) \
00547 ((pb.LL.x <= qb.UR.x) && (qb.LL.x <= pb.UR.x) && \
00548 (pb.LL.y <= qb.UR.y) && (qb.LL.y <= pb.UR.y))
00549
00550
00551
00552 static int overlaps(nitem * p, int cnt)
00553 {
00554 int i, j;
00555 nitem *pi = p;
00556 nitem *pj;
00557
00558 for (i = 0; i < cnt - 1; i++) {
00559 pj = pi + 1;
00560 for (j = i + 1; j < cnt; j++) {
00561 if (overlap(pi->bb, pj->bb))
00562 return 1;
00563 pj++;
00564 }
00565 pi++;
00566 }
00567 return 0;
00568 }
00569
00570
00571
00572 static void initItem(node_t * n, nitem * p, double margin)
00573 {
00574 int x = POINTS(SCALE * ND_pos(n)[0]);
00575 int y = POINTS(SCALE * ND_pos(n)[1]);
00576 int w2 = POINTS(margin * SCALE2 * ND_width(n));
00577 int h2 = POINTS(margin * SCALE2 * ND_height(n));
00578 box b;
00579
00580 b.LL.x = x - w2;
00581 b.LL.y = y - h2;
00582 b.UR.x = x + w2;
00583 b.UR.y = y + h2;
00584
00585 p->pos.x = x;
00586 p->pos.y = y;
00587 p->np = n;
00588 p->bb = b;
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 int cAdjust(graph_t * g, int mode)
00625 {
00626 double margin;
00627 int ret, i, nnodes = agnnodes(g);
00628 nitem *nlist = N_GNEW(nnodes, nitem);
00629 nitem *p = nlist;
00630 node_t *n;
00631
00632 margin = expFactor (g);
00633
00634 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00635 initItem(n, p, margin);
00636 p++;
00637 }
00638
00639 if (overlaps(nlist, nnodes)) {
00640 point pt;
00641
00642 switch ((adjust_mode)mode) {
00643 case AM_ORTHOXY:
00644 constrainX(g, nlist, nnodes, intersectY, 1);
00645 constrainY(g, nlist, nnodes, intersectX, 1);
00646 break;
00647 case AM_ORTHOYX:
00648 constrainY(g, nlist, nnodes, intersectX, 1);
00649 constrainX(g, nlist, nnodes, intersectY, 1);
00650 break;
00651 case AM_ORTHO :
00652 constrainX(g, nlist, nnodes, intersectY0, 1);
00653 constrainY(g, nlist, nnodes, intersectX, 1);
00654 case AM_ORTHO_YX :
00655 constrainY(g, nlist, nnodes, intersectX0, 1);
00656 constrainX(g, nlist, nnodes, intersectY, 1);
00657 case AM_PORTHOXY:
00658 constrainX(g, nlist, nnodes, intersectY, 0);
00659 constrainY(g, nlist, nnodes, intersectX, 0);
00660 break;
00661 case AM_PORTHOYX:
00662 constrainY(g, nlist, nnodes, intersectX, 0);
00663 constrainX(g, nlist, nnodes, intersectY, 0);
00664 break;
00665 case AM_PORTHO_YX :
00666 constrainY(g, nlist, nnodes, intersectX0, 0);
00667 constrainX(g, nlist, nnodes, intersectY, 0);
00668 break;
00669 case AM_PORTHO :
00670 default :
00671 constrainX(g, nlist, nnodes, intersectY0, 0);
00672 constrainY(g, nlist, nnodes, intersectX, 0);
00673 break;
00674 }
00675 p = nlist;
00676 for (i = 0; i < nnodes; i++) {
00677 n = p->np;
00678 pt = p->pos;
00679 ND_pos(n)[0] = PS2INCH(pt.x) / SCALE;
00680 ND_pos(n)[1] = PS2INCH(pt.y) / SCALE;
00681 p++;
00682 }
00683 ret = 1;
00684 }
00685 else ret = 0;
00686 free(nlist);
00687 return ret;
00688 }
00689
00690 typedef struct {
00691 pointf pos;
00692 boxf bb;
00693 double wd2;
00694 double ht2;
00695 node_t *np;
00696 } info;
00697
00698 typedef int (*sortfn_t) (const void *, const void *);
00699
00700 static int sortf(pointf * p, pointf * q)
00701 {
00702 if (p->x < q->x)
00703 return -1;
00704 else if (p->x > q->x)
00705 return 1;
00706 else if (p->y < q->y)
00707 return -1;
00708 else if (p->y > q->y)
00709 return 1;
00710 else
00711 return 0;
00712 }
00713
00714 static double compress(info * nl, int nn)
00715 {
00716 info *p = nl;
00717 info *q;
00718 int i, j;
00719 double s, sc = 0;
00720 pointf pt;
00721
00722 for (i = 0; i < nn; i++) {
00723 q = p + 1;
00724 for (j = i + 1; j < nn; j++) {
00725 if (overlap(p->bb, q->bb))
00726 return 0;
00727 if (p->pos.x == q->pos.x)
00728 pt.x = HUGE_VAL;
00729 else {
00730 pt.x = (p->wd2 + q->wd2) / fabs(p->pos.x - q->pos.x);
00731 }
00732 if (p->pos.y == q->pos.y)
00733 pt.y = HUGE_VAL;
00734 else {
00735 pt.y = (p->ht2 + q->ht2) / fabs(p->pos.y - q->pos.y);
00736 }
00737 if (pt.y < pt.x)
00738 s = pt.y;
00739 else
00740 s = pt.x;
00741 if (s > sc)
00742 sc = s;
00743 q++;
00744 }
00745 p++;
00746 }
00747 return sc;
00748 }
00749
00750 static pointf *mkOverlapSet(info * nl, int nn, int *cntp)
00751 {
00752 info *p = nl;
00753 info *q;
00754 int sz = nn;
00755 pointf *S = N_GNEW(sz + 1, pointf);
00756 int i, j;
00757 int cnt = 0;
00758
00759 for (i = 0; i < nn; i++) {
00760 q = p + 1;
00761 for (j = i + 1; j < nn; j++) {
00762 if (overlap(p->bb, q->bb)) {
00763 pointf pt;
00764 if (cnt == sz) {
00765 sz += nn;
00766 S = realloc(S, sizeof(pointf) * (sz + 1));
00767 }
00768 if (p->pos.x == q->pos.x)
00769 pt.x = HUGE_VAL;
00770 else {
00771 pt.x = (p->wd2 + q->wd2) / fabs(p->pos.x - q->pos.x);
00772 if (pt.x < 1)
00773 pt.x = 1;
00774 }
00775 if (p->pos.y == q->pos.y)
00776 pt.y = HUGE_VAL;
00777 else {
00778 pt.y = (p->ht2 + q->ht2) / fabs(p->pos.y - q->pos.y);
00779 if (pt.y < 1)
00780 pt.y = 1;
00781 }
00782 S[++cnt] = pt;
00783 }
00784 q++;
00785 }
00786 p++;
00787 }
00788
00789 S = realloc(S, sizeof(pointf) * (cnt + 1));
00790 *cntp = cnt;
00791 return S;
00792 }
00793
00794 static pointf computeScaleXY(pointf * aarr, int m)
00795 {
00796 pointf *barr;
00797 double cost, bestcost;
00798 int k, best = 0;
00799 pointf scale;
00800
00801 aarr[0].x = 1;
00802 aarr[0].y = HUGE_VAL;
00803 qsort(aarr + 1, m, sizeof(pointf), (sortfn_t) sortf);
00804
00805 barr = N_GNEW(m + 1, pointf);
00806 barr[m].x = aarr[m].x;
00807 barr[m].y = 1;
00808 for (k = m - 1; k >= 0; k--) {
00809 barr[k].x = aarr[k].x;
00810 barr[k].y = MAX(aarr[k + 1].y, barr[k + 1].y);
00811 }
00812
00813 bestcost = HUGE_VAL;
00814 for (k = 0; k <= m; k++) {
00815 cost = barr[k].x * barr[k].y;
00816 if (cost < bestcost) {
00817 bestcost = cost;
00818 best = k;
00819 }
00820 }
00821 assert(bestcost < HUGE_VAL);
00822 scale.x = barr[best].x;
00823 scale.y = barr[best].y;
00824
00825 return scale;
00826 }
00827
00828
00829
00830
00831
00832 static double computeScale(pointf * aarr, int m)
00833 {
00834 int i;
00835 double sc = 0;
00836 double v;
00837 pointf p;
00838
00839 aarr++;
00840 for (i = 1; i <= m; i++) {
00841 p = *aarr++;
00842 v = MIN(p.x, p.y);
00843 if (v > sc)
00844 sc = v;
00845 }
00846 return sc;
00847 }
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 int scAdjust(graph_t * g, int equal)
00860 {
00861 int nnodes = agnnodes(g);
00862 info *nlist = N_GNEW(nnodes, info);
00863 info *p = nlist;
00864 node_t *n;
00865 pointf s;
00866 int i;
00867 double margin;
00868 pointf *aarr;
00869 int m;
00870
00871 margin = expFactor (g);
00872
00873 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00874 double w2 = margin * ND_width(n) / 2.0;
00875 double h2 = margin * ND_height(n) / 2.0;
00876 p->pos.x = ND_pos(n)[0];
00877 p->pos.y = ND_pos(n)[1];
00878 p->bb.LL.x = p->pos.x - w2;
00879 p->bb.LL.y = p->pos.y - h2;
00880 p->bb.UR.x = p->pos.x + w2;
00881 p->bb.UR.y = p->pos.y + h2;
00882 p->wd2 = w2;
00883 p->ht2 = h2;
00884 p->np = n;
00885 p++;
00886 }
00887
00888 if (equal < 0) {
00889 s.x = s.y = compress(nlist, nnodes);
00890 if (s.x == 0) {
00891 free(nlist);
00892 return 0;
00893 }
00894 fprintf(stderr, "compress %g \n", s.x);
00895 } else {
00896 aarr = mkOverlapSet(nlist, nnodes, &m);
00897
00898 if (m == 0) {
00899 free(aarr);
00900 free(nlist);
00901 return 0;
00902 }
00903
00904 if (equal) {
00905 s.x = s.y = computeScale(aarr, m);
00906 } else {
00907 s = computeScaleXY(aarr, m);
00908 }
00909 free(aarr);
00910 }
00911
00912 p = nlist;
00913 for (i = 0; i < nnodes; i++) {
00914 ND_pos(p->np)[0] = s.x * p->pos.x;
00915 ND_pos(p->np)[1] = s.y * p->pos.y;
00916 p++;
00917 }
00918
00919 free(nlist);
00920 return 1;
00921 }