00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "blockpath.h"
00019 #include "edgelist.h"
00020 #include "nodeset.h"
00021 #include "deglist.h"
00022
00023
00024
00025
00026
00027 #define ORIGE(e) (ED_to_orig(e))
00028
00029
00030
00031
00032
00033
00034 static Agraph_t *clone_graph(Agraph_t * ing, Agraph_t ** xg)
00035 {
00036 Agraph_t *clone;
00037 Agraph_t *xclone;
00038 Agnode_t *n;
00039 Agnode_t *xn;
00040 Agnode_t *xh;
00041 Agedge_t *e;
00042 Agedge_t *xe;
00043 char gname[SMALLBUF];
00044 static int id = 0;
00045
00046 sprintf(gname, "_clone_%d", id++);
00047 clone = agsubg(ing, gname);
00048 sprintf(gname, "_clone_%d", id++);
00049 xclone = agopen(gname, ing->kind);
00050
00051 for (n = agfstnode(ing); n; n = agnxtnode(ing, n)) {
00052 aginsert(clone, n);
00053 xn = agnode(xclone, n->name);
00054 CLONE(n) = xn;
00055 }
00056
00057 for (n = agfstnode(ing); n; n = agnxtnode(ing, n)) {
00058 xn = CLONE(n);
00059 for (e = agfstout(ing, n); e; e = agnxtout(ing, e)) {
00060 aginsert(clone, e);
00061 xh = CLONE(e->head);
00062 xe = agedge(xclone, xn, xh);
00063 ORIGE(xe) = e;
00064 DEGREE(xn) += 1;
00065 DEGREE(xh) += 1;
00066 }
00067 }
00068 *xg = xclone;
00069 #ifdef OLD
00070 clone = agopen("clone", root->kind);
00071
00072 for (n = agfstnode(root); n; n = agnxtnode(root, n)) {
00073 cn = agnode(clone, n->name);
00074 ND_alg(cn) = DATA(n);
00075 BCDONE(cn) = 0;
00076 }
00077
00078 for (n = agfstnode(root); n; n = agnxtnode(root, n)) {
00079 Agnode_t *t = agnode(clone, n);
00080 for (e = agfstout(root, n); e; e = agnxtout(root, e)) {
00081 Agnode_t *h = agnode(clone, e->head->name);
00082 agedge(clone, t, h);
00083 }
00084 }
00085 #endif
00086 return clone;
00087 }
00088
00089
00090
00091
00092 static deglist_t *getList(Agraph_t * g)
00093 {
00094 deglist_t *dl = mkDeglist();
00095 Agnode_t *n;
00096
00097 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00098 insertDeglist(dl, n);
00099 }
00100 return dl;
00101 }
00102
00103
00104
00105 static void find_pair_edges(Agraph_t * g, Agnode_t * n, Agraph_t * outg)
00106 {
00107 Agnode_t **neighbors_with;
00108 Agnode_t **neighbors_without;
00109
00110 Agedge_t *e;
00111 Agedge_t *ep;
00112 Agedge_t *ex;
00113 Agnode_t *n1;
00114 Agnode_t *n2;
00115 int has_pair_edge;
00116 int diff;
00117 int has_pair_count = 0;
00118 int no_pair_count = 0;
00119 int node_degree;
00120 int edge_cnt = 0;
00121
00122 node_degree = DEGREE(n);
00123 neighbors_with = N_GNEW(node_degree, Agnode_t *);
00124 neighbors_without = N_GNEW(node_degree, Agnode_t *);
00125
00126 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00127 n1 = e->head;
00128 if (n1 == n)
00129 n1 = e->tail;
00130 has_pair_edge = 0;
00131 for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
00132 if (ep == e)
00133 continue;
00134 n2 = ep->head;
00135 if (n2 == n)
00136 n2 = ep->tail;
00137 ex = agfindedge(g, n1, n2);
00138 if (ex) {
00139 has_pair_edge = 1;
00140 if (n1 < n2) {
00141 edge_cnt++;
00142 if (ORIGE(ex)) {
00143 agdelete(outg, ORIGE(ex));
00144 ORIGE(ex) = 0;
00145 }
00146 }
00147 }
00148 }
00149 if (has_pair_edge) {
00150 neighbors_with[has_pair_count] = n1;
00151 has_pair_count++;
00152 } else {
00153 neighbors_without[no_pair_count] = n1;
00154 no_pair_count++;
00155 }
00156 }
00157
00158 diff = node_degree - 1 - edge_cnt;
00159 if (diff > 0) {
00160 int mark;
00161 Agnode_t *hp;
00162 Agnode_t *tp;
00163
00164 if (diff < no_pair_count) {
00165 for (mark = 0; mark < no_pair_count; mark += 2) {
00166 if ((mark + 1) >= no_pair_count)
00167 break;
00168 tp = neighbors_without[mark];
00169 hp = neighbors_without[mark + 1];
00170 agedge(g, tp, hp);
00171 DEGREE(tp)++;
00172 DEGREE(hp)++;
00173 diff--;
00174 }
00175
00176 mark = 2;
00177 while (diff > 0) {
00178 tp = neighbors_without[0];
00179 hp = neighbors_without[mark];
00180 agedge(g, tp, hp);
00181 DEGREE(tp)++;
00182 DEGREE(hp)++;
00183 mark++;
00184 diff--;
00185 }
00186 }
00187
00188 else if (diff == no_pair_count) {
00189 tp = neighbors_with[0];
00190 for (mark = 0; mark < no_pair_count; mark++) {
00191 hp = neighbors_without[mark];
00192 agedge(g, tp, hp);
00193 DEGREE(tp)++;
00194 DEGREE(hp)++;
00195 }
00196 }
00197 }
00198
00199 free(neighbors_without);
00200 free(neighbors_with);
00201 }
00202
00203
00204
00205
00206
00207 static Agraph_t *remove_pair_edges(Agraph_t * ing)
00208 {
00209 int counter = 0;
00210 int nodeCount;
00211 Agraph_t *outg;
00212 Agraph_t *g;
00213 deglist_t *dl;
00214 Agnode_t *currnode, *adjNode;
00215 Agedge_t *e;
00216
00217 outg = clone_graph(ing, &g);
00218 nodeCount = agnnodes(g);
00219 dl = getList(g);
00220
00221 while (counter < (nodeCount - 3)) {
00222 currnode = firstDeglist(dl);
00223
00224
00225 for (e = agfstedge(g, currnode); e; e = agnxtedge(g, e, currnode)) {
00226 adjNode = e->head;
00227 if (currnode == adjNode)
00228 adjNode = e->tail;
00229 removeDeglist(dl, adjNode);
00230 }
00231
00232 find_pair_edges(g, currnode, outg);
00233
00234 for (e = agfstedge(g, currnode); e; e = agnxtedge(g, e, currnode)) {
00235 adjNode = e->head;
00236 if (currnode == adjNode)
00237 adjNode = e->tail;
00238
00239 DEGREE(adjNode)--;
00240 insertDeglist(dl, adjNode);
00241 }
00242
00243 agdelete(g, currnode);
00244
00245 counter++;
00246 }
00247
00248 agclose(g);
00249 freeDeglist(dl);
00250 return outg;
00251 }
00252
00253 static void
00254 measure_distance(Agnode_t * n, Agnode_t * ancestor, int dist,
00255 Agnode_t * change)
00256 {
00257 Agnode_t *parent;
00258
00259 parent = TPARENT(ancestor);
00260 if (parent == NULL)
00261 return;
00262
00263 dist++;
00264
00265
00266
00267
00268
00269 if (DISTONE(parent) == 0) {
00270 LEAFONE(parent) = n;
00271 DISTONE(parent) = dist;
00272 } else if (dist > DISTONE(parent)) {
00273 if (LEAFONE(parent) != change) {
00274 if (!DISTTWO(parent) || (LEAFTWO(parent) != change))
00275 change = LEAFONE(parent);
00276 LEAFTWO(parent) = LEAFONE(parent);
00277 DISTTWO(parent) = DISTONE(parent);
00278 }
00279 LEAFONE(parent) = n;
00280 DISTONE(parent) = dist;
00281 } else if (dist > DISTTWO(parent)) {
00282 LEAFTWO(parent) = n;
00283 DISTTWO(parent) = dist;
00284 return;
00285 } else
00286 return;
00287
00288 measure_distance(n, parent, dist, change);
00289 }
00290
00291
00292
00293
00294 static nodelist_t *find_longest_path(Agraph_t * tree)
00295 {
00296 Agnode_t *n;
00297 Agedge_t *e;
00298 Agnode_t *common = 0;
00299 nodelist_t *path;
00300 nodelist_t *endPath;
00301 int maxlength = 0;
00302 int length;
00303
00304 if (agnnodes(tree) == 1) {
00305 path = mkNodelist();
00306 n = agfstnode(tree);
00307 appendNodelist(path, NULL, n);
00308 SET_ONPATH(n);
00309 return path;
00310 }
00311
00312 for (n = agfstnode(tree); n; n = agnxtnode(tree, n)) {
00313 int count = 0;
00314 for (e = agfstedge(tree, n); e; e = agnxtedge(tree, e, n)) {
00315 count++;
00316 }
00317 if (count == 1)
00318 measure_distance(n, n, 0, NULL);
00319 }
00320
00321
00322 for (n = agfstnode(tree); n; n = agnxtnode(tree, n)) {
00323 length = DISTONE(n) + DISTTWO(n);
00324 if (length > maxlength) {
00325 common = n;
00326 maxlength = length;
00327 }
00328 }
00329
00330 path = mkNodelist();
00331 for (n = LEAFONE(common); n != common; n = TPARENT(n)) {
00332 appendNodelist(path, NULL, n);
00333 SET_ONPATH(n);
00334 }
00335 appendNodelist(path, NULL, common);
00336 SET_ONPATH(common);
00337
00338 if (DISTTWO(common)) {
00339 endPath = mkNodelist();
00340 for (n = LEAFTWO(common); n != common; n = TPARENT(n)) {
00341 appendNodelist(endPath, NULL, n);
00342 SET_ONPATH(n);
00343 }
00344 reverseAppend(path, endPath);
00345 }
00346
00347 return path;
00348 }
00349
00350
00351
00352
00353 static void dfs(Agraph_t * g, Agnode_t * n, Agraph_t * tree)
00354 {
00355 Agedge_t *e;
00356 Agnode_t *neighbor;
00357
00358 SET_VISITED(n);
00359 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00360 neighbor = e->head;
00361 if (neighbor == n)
00362 neighbor = e->tail;
00363
00364 if (!VISITED(neighbor)) {
00365
00366 aginsert(tree, e);
00367 TPARENT(neighbor) = n;
00368 dfs(g, neighbor, tree);
00369 }
00370 }
00371 }
00372
00373
00374
00375
00376 static Agraph_t *spanning_tree(Agraph_t * g)
00377 {
00378 Agnode_t *n;
00379 Agraph_t *tree;
00380 char gname[SMALLBUF];
00381 static int id = 0;
00382
00383 sprintf(gname, "_span_%d", id++);
00384 tree = agsubg(g, gname);
00385 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00386 aginsert(tree, n);
00387 DISTONE(n) = 0;
00388 DISTTWO(n) = 0;
00389 UNSET_VISITED(n);
00390 }
00391
00392 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00393 if (!VISITED(n)) {
00394 TPARENT(n) = NULL;
00395 dfs(g, n, tree);
00396 }
00397 }
00398
00399 return tree;
00400 }
00401
00402
00403
00404
00405 static void block_graph(Agraph_t * g, block_t * sn)
00406 {
00407 Agnode_t *n;
00408 Agedge_t *e;
00409 Agraph_t *subg = sn->sub_graph;
00410
00411 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00412 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00413 if (BLOCK(e->head) == sn)
00414 aginsert(subg, e);
00415 }
00416 }
00417 }
00418
00419 static int count_all_crossings(nodelist_t * list, Agraph_t * subg)
00420 {
00421 nodelistitem_t *item;
00422 edgelist *openEdgeList = init_edgelist();
00423 Agnode_t *n;
00424 Agedge_t *e;
00425 int crossings = 0;
00426 int order = 1;
00427
00428 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00429 for (e = agfstout(subg, n); e; e = agnxtout(subg, e)) {
00430 EDGEORDER(e) = 0;
00431 }
00432 }
00433
00434 for (item = list->first; item; item = item->next) {
00435 n = item->curr;
00436
00437 for (e = agfstedge(subg, n); e; e = agnxtedge(subg, e, n)) {
00438 if (EDGEORDER(e) > 0) {
00439 edgelistitem *eitem;
00440 Agedge_t *ep;
00441
00442 for (eitem = (edgelistitem *) dtfirst(openEdgeList); eitem;
00443 eitem =
00444 (edgelistitem *) dtnext(openEdgeList, eitem)) {
00445 ep = eitem->edge;
00446 if (EDGEORDER(ep) > EDGEORDER(e)) {
00447 if ((ep->head != n) && (ep->tail != n))
00448 crossings++;
00449 }
00450 }
00451 remove_edge(openEdgeList, e);
00452 }
00453 }
00454
00455 for (e = agfstedge(subg, n); e; e = agnxtedge(subg, e, n)) {
00456 if (EDGEORDER(e) == 0) {
00457 EDGEORDER(e) = order;
00458 add_edge(openEdgeList, e);
00459 }
00460 }
00461 order++;
00462 }
00463
00464 free_edgelist(openEdgeList);
00465 return crossings;
00466 }
00467
00468 #define CROSS_ITER 10
00469
00470
00471
00472
00473
00474
00475 static nodelist_t *reduce(nodelist_t * list, Agraph_t * subg, int *cnt)
00476 {
00477 Agnode_t *curnode;
00478 Agedge_t *e;
00479 Agnode_t *neighbor;
00480 nodelist_t *listCopy;
00481 int crossings, j, newCrossings;
00482
00483 crossings = *cnt;
00484 for (curnode = agfstnode(subg); curnode;
00485 curnode = agnxtnode(subg, curnode)) {
00486
00487 for (e = agfstedge(subg, curnode); e;
00488 e = agnxtedge(subg, e, curnode)) {
00489 neighbor = e->tail;
00490 if (neighbor == curnode)
00491 neighbor = e->head;
00492
00493 for (j = 0; j < 2; j++) {
00494 listCopy = cloneNodelist(list);
00495 insertNodelist(list, curnode, neighbor, j);
00496 newCrossings = count_all_crossings(list, subg);
00497 if (newCrossings < crossings) {
00498 crossings = newCrossings;
00499 freeNodelist(listCopy);
00500 if (crossings == 0) {
00501 *cnt = 0;
00502 return list;
00503 }
00504 } else {
00505 freeNodelist(list);
00506 list = listCopy;
00507 }
00508 }
00509 }
00510 }
00511 *cnt = crossings;
00512 return list;
00513 }
00514
00515 static nodelist_t *reduce_edge_crossings(nodelist_t * list,
00516 Agraph_t * subg)
00517 {
00518 int i, crossings, origCrossings;
00519
00520 crossings = count_all_crossings(list, subg);
00521 if (crossings == 0)
00522 return list;
00523
00524 for (i = 0; i < CROSS_ITER; i++) {
00525 origCrossings = crossings;
00526 list = reduce(list, subg, &crossings);
00527
00528 if ((origCrossings == crossings) || (crossings == 0))
00529 return list;
00530 }
00531 return list;
00532 }
00533
00534
00535
00536
00537 static double largest_nodesize(nodelist_t * list)
00538 {
00539 Agnode_t *n;
00540 nodelistitem_t *item;
00541 double size = 0;
00542
00543 for (item = list->first; item; item = item->next) {
00544 n = ORIGN(item->curr);
00545 if (ND_width(n) > size)
00546 size = ND_width(n);
00547 if (ND_height(n) > size)
00548 size = ND_height(n);
00549 }
00550 return size;
00551 }
00552
00553
00554
00555
00556 static void place_node(Agraph_t * g, Agnode_t * n, nodelist_t * list)
00557 {
00558 Agedge_t *e;
00559 int placed = 0;
00560 nodelist_t *neighbors = mkNodelist();
00561 nodelistitem_t *one, *two;
00562
00563 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00564 appendNodelist(neighbors, NULL, e->head);
00565 SET_NEIGHBOR(e->head);
00566 }
00567 for (e = agfstin(g, n); e; e = agnxtin(g, e)) {
00568 appendNodelist(neighbors, NULL, e->tail);
00569 SET_NEIGHBOR(e->tail);
00570 }
00571
00572
00573 if (sizeNodelist(neighbors) >= 2) {
00574 for (one = list->first; one; one = one->next) {
00575 if (one == list->last)
00576 two = list->first;
00577 else
00578 two = one->next;
00579
00580 if (NEIGHBOR(one->curr) && NEIGHBOR(two->curr)) {
00581 appendNodelist(list, one, n);
00582 placed = 1;
00583 break;
00584 }
00585 }
00586 }
00587
00588
00589 if (!placed && sizeNodelist(neighbors) > 0) {
00590 for (one = list->first; one; one = one->next) {
00591 if (NEIGHBOR(one->curr)) {
00592 appendNodelist(list, one, n);
00593 placed = 1;
00594 break;
00595 }
00596 }
00597 }
00598
00599 if (!placed)
00600 appendNodelist(list, NULL, n);
00601
00602 for (one = neighbors->first; one; one = one->next)
00603 UNSET_NEIGHBOR(one->curr);
00604 freeNodelist(neighbors);
00605 }
00606
00607
00608
00609
00610 static void place_residual_nodes(Agraph_t * g, nodelist_t * list)
00611 {
00612 Agnode_t *n;
00613
00614 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00615 if (!ONPATH(n))
00616 place_node(g, n, list);
00617 }
00618 }
00619
00620 nodelist_t *layout_block(Agraph_t * g, block_t * sn, double min_dist)
00621 {
00622 Agnode_t *n;
00623 Agraph_t *copyG, *tree, *subg;
00624 nodelist_t *longest_path;
00625 nodelistitem_t *item;
00626 int N, k;
00627 double theta, radius, largest_node;
00628 largest_node = 0;
00629
00630 subg = sn->sub_graph;
00631 block_graph(g, sn);
00632
00633 copyG = remove_pair_edges(subg);
00634
00635 tree = spanning_tree(copyG);
00636 longest_path = find_longest_path(tree);
00637 place_residual_nodes(subg, longest_path);
00638
00639
00640
00641 longest_path = reduce_edge_crossings(longest_path, subg);
00642
00643 N = sizeNodelist(longest_path);
00644 largest_node = largest_nodesize(longest_path);
00645
00646 if (N == 1)
00647 radius = 0;
00648 else
00649 radius = (N * (min_dist + largest_node)) / (2 * M_PI);
00650
00651 for (item = longest_path->first; item; item = item->next) {
00652 n = item->curr;
00653 if (ISPARENT(n)) {
00654
00655 realignNodelist(longest_path, item);
00656 break;
00657 }
00658 }
00659
00660 k = 0;
00661 for (item = longest_path->first; item; item = item->next) {
00662 n = item->curr;
00663 POSITION(n) = k;
00664 PSI(n) = 0.0;
00665 theta = k * ((2.0 * M_PI) / N);
00666
00667 ND_pos(n)[0] = radius * cos(theta);
00668 ND_pos(n)[1] = radius * sin(theta);
00669
00670 k++;
00671 }
00672
00673 if (N == 1)
00674 sn->radius = largest_node / 2;
00675 else
00676 sn->radius = radius;
00677 sn->rad0 = sn->radius;
00678
00679
00680 sn->parent_pos = -1;
00681
00682 agclose(copyG);
00683 return longest_path;
00684 }
00685
00686 #ifdef DEBUG
00687 void prTree(Agraph_t * g)
00688 {
00689 Agnode_t *n;
00690
00691 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00692 if (TPARENT(n))
00693 fprintf(stderr, "%s -> %s\n", n->name, TPARENT(n)->name);
00694 }
00695 }
00696 #endif