Graphviz 2.29.20120208.0545
lib/circogen/blockpath.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 
00015 #include        "blockpath.h"
00016 #include        "edgelist.h"
00017 #include        "nodeset.h"
00018 #include        "deglist.h"
00019 
00020 /* The code below lays out a single block on a circle.
00021  */
00022 
00023 /* We use the unused fields order and to_orig in cloned nodes and edges */
00024 #define ORIGE(e)  (ED_to_orig(e))
00025 
00026 /* clone_graph:
00027  * Create two copies of the argument graph
00028  * One is a subgraph, the other is an actual copy since we will be
00029  * adding edges to it.
00030  */
00031 static Agraph_t *clone_graph(Agraph_t * ing, Agraph_t ** xg)
00032 {
00033     Agraph_t *clone;
00034     Agraph_t *xclone;
00035     Agnode_t *n;
00036     Agnode_t *xn;
00037     Agnode_t *xh;
00038     Agedge_t *e;
00039     Agedge_t *xe;
00040     char gname[SMALLBUF];
00041     static int id = 0;
00042 
00043     sprintf(gname, "_clone_%d", id++);
00044 #ifndef WITH_CGRAPH
00045     clone = agsubg(ing, gname);
00046 #else /* WITH_CGRAPH */
00047     clone = agsubg(ing, gname,1);
00048     agbindrec(clone, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);       //node custom data
00049 #endif /* WITH_CGRAPH */
00050     sprintf(gname, "_clone_%d", id++);
00051 #ifndef WITH_CGRAPH
00052     xclone = agopen(gname, ing->kind);
00053     for (n = agfstnode(ing); n; n = agnxtnode(ing, n)) {
00054         aginsert(clone, n);
00055         xn = agnode(xclone, agnameof(n));
00056 #else /* WITH_CGRAPH */
00057     xclone = agopen(gname, ing->desc,NIL(Agdisc_t *));
00058     for (n = agfstnode(ing); n; n = agnxtnode(ing, n)) {
00059         agsubnode(clone,n,1);
00060         xn = agnode(xclone, agnameof(n),1);
00061         agbindrec(xn, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);      //node custom data
00062 #endif /* WITH_CGRAPH */
00063         CLONE(n) = xn;
00064     }
00065 
00066     for (n = agfstnode(ing); n; n = agnxtnode(ing, n)) {
00067         xn = CLONE(n);
00068 #ifndef WITH_CGRAPH
00069         for (e = agfstout(ing, n); e; e = agnxtout(ing, e)) {
00070             aginsert(clone, e);
00071             xh = CLONE(e->head);
00072             xe = agedge(xclone, xn, xh);
00073 #else /* WITH_CGRAPH */
00074         for (e = agfstout(ing, n); e; e = agnxtout(ing, e)) {
00075             agsubedge(clone,e,1);
00076             xh = CLONE(aghead(e));
00077             xe = agedge(xclone, xn, xh, NULL, 1);
00078             agbindrec(xe, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);  //node custom data
00079 #endif /* WITH_CGRAPH */
00080             ORIGE(xe) = e;
00081             DEGREE(xn) += 1;
00082             DEGREE(xh) += 1;
00083         }
00084     }
00085     *xg = xclone;
00086     return clone;
00087 }
00088 
00089 /* fillList:
00090  * Add nodes to deg_list, which stores them by degree.
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 /* find_pair_edges:
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 = aghead(e);
00128         if (n1 == n)
00129             n1 = agtail(e);
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 = aghead(ep);
00135             if (n2 == n)
00136                 n2 = agtail(ep);
00137             ex = agfindedge(g, n1, n2);
00138             if (ex) {
00139                 has_pair_edge = 1;
00140                 if (n1 < n2) {  /* count edge only once */
00141                     edge_cnt++;
00142                     if (ORIGE(ex)) {
00143                         agdelete(outg, ORIGE(ex));
00144                         ORIGE(ex) = 0;  /* delete only once */
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 #ifndef WITH_CGRAPH
00171                 agedge(g, tp, hp);
00172 #else /* WITH_CGRAPH */
00173                 agbindrec(agedge(g, tp, hp, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);   // edge custom data
00174 
00175 #endif /* WITH_CGRAPH */
00176                 DEGREE(tp)++;
00177                 DEGREE(hp)++;
00178                 diff--;
00179             }
00180 
00181             mark = 2;
00182             while (diff > 0) {
00183                 tp = neighbors_without[0];
00184                 hp = neighbors_without[mark];
00185 #ifndef WITH_CGRAPH
00186                 agedge(g, tp, hp);
00187 #else /* WITH_CGRAPH */
00188 
00189                 agbindrec(agedge(g, tp, hp, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);   // edge custom data
00190 
00191 #endif /* WITH_CGRAPH */
00192                 DEGREE(tp)++;
00193                 DEGREE(hp)++;
00194                 mark++;
00195                 diff--;
00196             }
00197         }
00198 
00199         else if (diff == no_pair_count) {
00200             tp = neighbors_with[0];
00201             for (mark = 0; mark < no_pair_count; mark++) {
00202                 hp = neighbors_without[mark];
00203 #ifndef WITH_CGRAPH
00204                 agedge(g, tp, hp);
00205 #else /* WITH_CGRAPH */
00206                 agbindrec(agedge(g, tp, hp, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);      //node custom data
00207 
00208 #endif /* WITH_CGRAPH */
00209                 DEGREE(tp)++;
00210                 DEGREE(hp)++;
00211             }
00212         }
00213     }
00214 
00215     free(neighbors_without);
00216     free(neighbors_with);
00217 }
00218 
00219 /* remove_pair_edges:
00220  * Create layout skeleton of ing.
00221  * Why is returned graph connected?
00222  */
00223 static Agraph_t *remove_pair_edges(Agraph_t * ing)
00224 {
00225     int counter = 0;
00226     int nodeCount;
00227     Agraph_t *outg;
00228     Agraph_t *g;
00229     deglist_t *dl;
00230     Agnode_t *currnode, *adjNode;
00231     Agedge_t *e;
00232 
00233     outg = clone_graph(ing, &g);
00234     nodeCount = agnnodes(g);
00235     dl = getList(g);
00236 
00237     while (counter < (nodeCount - 3)) {
00238         currnode = firstDeglist(dl);
00239 
00240         /* Remove all adjacent nodes since they have to be reinserted */
00241         for (e = agfstedge(g, currnode); e; e = agnxtedge(g, e, currnode)) {
00242             adjNode = aghead(e);
00243             if (currnode == adjNode)
00244                 adjNode = agtail(e);
00245             removeDeglist(dl, adjNode);
00246         }
00247 
00248         find_pair_edges(g, currnode, outg);
00249 
00250         for (e = agfstedge(g, currnode); e; e = agnxtedge(g, e, currnode)) {
00251             adjNode = aghead(e);
00252             if (currnode == adjNode)
00253                 adjNode = agtail(e);
00254 
00255             DEGREE(adjNode)--;
00256             insertDeglist(dl, adjNode);
00257         }
00258 
00259         agdelete(g, currnode);
00260 
00261         counter++;
00262     }
00263 
00264     agclose(g);
00265     freeDeglist(dl);
00266     return outg;
00267 }
00268 
00269 static void
00270 measure_distance(Agnode_t * n, Agnode_t * ancestor, int dist,
00271                  Agnode_t * change)
00272 {
00273     Agnode_t *parent;
00274 
00275     parent = TPARENT(ancestor);
00276     if (parent == NULL)
00277         return;
00278 
00279     dist++;
00280 
00281     /* check parent to see if it has other leaf paths at greater distance
00282        than the context node.
00283        set the path/distance of the leaf at this ancestor node */
00284 
00285     if (DISTONE(parent) == 0) {
00286         LEAFONE(parent) = n;
00287         DISTONE(parent) = dist;
00288     } else if (dist > DISTONE(parent)) {
00289         if (LEAFONE(parent) != change) {
00290             if (!DISTTWO(parent) || (LEAFTWO(parent) != change))
00291                 change = LEAFONE(parent);
00292             LEAFTWO(parent) = LEAFONE(parent);
00293             DISTTWO(parent) = DISTONE(parent);
00294         }
00295         LEAFONE(parent) = n;
00296         DISTONE(parent) = dist;
00297     } else if (dist > DISTTWO(parent)) {
00298         LEAFTWO(parent) = n;
00299         DISTTWO(parent) = dist;
00300         return;
00301     } else
00302         return;
00303 
00304     measure_distance(n, parent, dist, change);
00305 }
00306 
00307 /* find_longest_path:
00308  * Find and return longest path in tree.
00309  */
00310 static nodelist_t *find_longest_path(Agraph_t * tree)
00311 {
00312     Agnode_t *n;
00313     Agedge_t *e;
00314     Agnode_t *common = 0;
00315     nodelist_t *path;
00316     nodelist_t *endPath;
00317     int maxlength = 0;
00318     int length;
00319 
00320     if (agnnodes(tree) == 1) {
00321         path = mkNodelist();
00322         n = agfstnode(tree);
00323         appendNodelist(path, NULL, n);
00324         SET_ONPATH(n);
00325         return path;
00326     }
00327 
00328     for (n = agfstnode(tree); n; n = agnxtnode(tree, n)) {
00329         int count = 0;
00330         for (e = agfstedge(tree, n); e; e = agnxtedge(tree, e, n)) {
00331             count++;
00332         }
00333         if (count == 1)
00334             measure_distance(n, n, 0, NULL);
00335     }
00336 
00337     /* find the branch node rooted at the longest path */
00338     for (n = agfstnode(tree); n; n = agnxtnode(tree, n)) {
00339         length = DISTONE(n) + DISTTWO(n);
00340         if (length > maxlength) {
00341             common = n;
00342             maxlength = length;
00343         }
00344     }
00345 
00346     path = mkNodelist();
00347     for (n = LEAFONE(common); n != common; n = TPARENT(n)) {
00348         appendNodelist(path, NULL, n);
00349         SET_ONPATH(n);
00350     }
00351     appendNodelist(path, NULL, common);
00352     SET_ONPATH(common);
00353 
00354     if (DISTTWO(common)) {      /* 2nd path might be empty */
00355         endPath = mkNodelist();
00356         for (n = LEAFTWO(common); n != common; n = TPARENT(n)) {
00357             appendNodelist(endPath, NULL, n);
00358             SET_ONPATH(n);
00359         }
00360         reverseAppend(path, endPath);
00361     }
00362 
00363     return path;
00364 }
00365 
00366 /* dfs:
00367  * Simple depth first search, adding traversed edges to tree.
00368  */
00369 static void dfs(Agraph_t * g, Agnode_t * n, Agraph_t * tree)
00370 {
00371     Agedge_t *e;
00372     Agnode_t *neighbor;
00373 
00374     SET_VISITED(n);
00375     for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00376         neighbor = aghead(e);
00377         if (neighbor == n)
00378             neighbor = agtail(e);
00379 
00380         if (!VISITED(neighbor)) {
00381             /* add the edge to the dfs tree */
00382 #ifndef WITH_CGRAPH
00383             aginsert(tree, e);
00384 #else /* WITH_CGRAPH */
00385             agsubedge(tree,e,1);
00386 #endif /* WITH_CGRAPH */
00387             TPARENT(neighbor) = n;
00388             dfs(g, neighbor, tree);
00389         }
00390     }
00391 }
00392 
00393 /* spanning_tree:
00394  * Construct spanning forest of g as subgraph
00395  */
00396 static Agraph_t *spanning_tree(Agraph_t * g)
00397 {
00398     Agnode_t *n;
00399     Agraph_t *tree;
00400     char gname[SMALLBUF];
00401     static int id = 0;
00402 
00403     sprintf(gname, "_span_%d", id++);
00404 #ifndef WITH_CGRAPH
00405     tree = agsubg(g, gname);
00406 #else /* WITH_CGRAPH */
00407     tree = agsubg(g, gname,1);
00408     agbindrec(tree, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);        //node custom data
00409 #endif /* WITH_CGRAPH */
00410 
00411     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00412 #ifndef WITH_CGRAPH
00413         aginsert(tree, n);
00414 #else /* WITH_CGRAPH */
00415         agsubnode(tree,n,1);
00416 #endif /* WITH_CGRAPH */
00417         DISTONE(n) = 0;
00418         DISTTWO(n) = 0;
00419         UNSET_VISITED(n);
00420     }
00421 
00422     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00423         if (!VISITED(n)) {
00424             TPARENT(n) = NULL;
00425             dfs(g, n, tree);
00426         }
00427     }
00428 
00429     return tree;
00430 }
00431 
00432 /* block_graph:
00433  * Add induced edges.
00434  */
00435 static void block_graph(Agraph_t * g, block_t * sn)
00436 {
00437     Agnode_t *n;
00438     Agedge_t *e;
00439     Agraph_t *subg = sn->sub_graph;
00440 
00441     for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00442         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00443             if (BLOCK(aghead(e)) == sn)
00444 #ifndef WITH_CGRAPH
00445                 aginsert(subg, e);
00446 #else /* WITH_CGRAPH */
00447                 agsubedge(subg,e,1);
00448 #endif /* WITH_CGRAPH */
00449         }
00450     }
00451 }
00452 
00453 static int count_all_crossings(nodelist_t * list, Agraph_t * subg)
00454 {
00455     nodelistitem_t *item;
00456     edgelist *openEdgeList = init_edgelist();
00457     Agnode_t *n;
00458     Agedge_t *e;
00459     int crossings = 0;
00460     int order = 1;
00461 
00462     for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00463         for (e = agfstout(subg, n); e; e = agnxtout(subg, e)) {
00464             EDGEORDER(e) = 0;
00465         }
00466     }
00467 
00468     for (item = list->first; item; item = item->next) {
00469         n = item->curr;
00470 
00471         for (e = agfstedge(subg, n); e; e = agnxtedge(subg, e, n)) {
00472             if (EDGEORDER(e) > 0) {
00473                 edgelistitem *eitem;
00474                 Agedge_t *ep;
00475 
00476                 for (eitem = (edgelistitem *) dtfirst(openEdgeList); eitem;
00477                      eitem =
00478                      (edgelistitem *) dtnext(openEdgeList, eitem)) {
00479                     ep = eitem->edge;
00480                     if (EDGEORDER(ep) > EDGEORDER(e)) {
00481                         if ((aghead(ep) != n) && (agtail(ep) != n))
00482                             crossings++;
00483                     }
00484                 }
00485                 remove_edge(openEdgeList, e);
00486             }
00487         }
00488 
00489         for (e = agfstedge(subg, n); e; e = agnxtedge(subg, e, n)) {
00490             if (EDGEORDER(e) == 0) {
00491                 EDGEORDER(e) = order;
00492                 add_edge(openEdgeList, e);
00493             }
00494         }
00495         order++;
00496     }
00497 
00498     free_edgelist(openEdgeList);
00499     return crossings;
00500 }
00501 
00502 #define CROSS_ITER 10
00503 
00504 /* reduce:
00505  * Attempt to reduce edge crossings by moving nodes.
00506  * Original crossing count is in cnt; final count is returned there.
00507  * list is the original list; return the best list found.
00508  */
00509 static nodelist_t *reduce(nodelist_t * list, Agraph_t * subg, int *cnt)
00510 {
00511     Agnode_t *curnode;
00512     Agedge_t *e;
00513     Agnode_t *neighbor;
00514     nodelist_t *listCopy;
00515     int crossings, j, newCrossings;
00516 
00517     crossings = *cnt;
00518     for (curnode = agfstnode(subg); curnode;
00519          curnode = agnxtnode(subg, curnode)) {
00520         /*  move curnode next to its neighbors */
00521         for (e = agfstedge(subg, curnode); e;
00522              e = agnxtedge(subg, e, curnode)) {
00523             neighbor = agtail(e);
00524             if (neighbor == curnode)
00525                 neighbor = aghead(e);
00526 
00527             for (j = 0; j < 2; j++) {
00528                 listCopy = cloneNodelist(list);
00529                 insertNodelist(list, curnode, neighbor, j);
00530                 newCrossings = count_all_crossings(list, subg);
00531                 if (newCrossings < crossings) {
00532                     crossings = newCrossings;
00533                     freeNodelist(listCopy);
00534                     if (crossings == 0) {
00535                         *cnt = 0;
00536                         return list;
00537                     }
00538                 } else {
00539                     freeNodelist(list);
00540                     list = listCopy;
00541                 }
00542             }
00543         }
00544     }
00545     *cnt = crossings;
00546     return list;
00547 }
00548 
00549 static nodelist_t *reduce_edge_crossings(nodelist_t * list,
00550                                          Agraph_t * subg)
00551 {
00552     int i, crossings, origCrossings;
00553 
00554     crossings = count_all_crossings(list, subg);
00555     if (crossings == 0)
00556         return list;
00557 
00558     for (i = 0; i < CROSS_ITER; i++) {
00559         origCrossings = crossings;
00560         list = reduce(list, subg, &crossings);
00561         /* return if no crossings or no improvement */
00562         if ((origCrossings == crossings) || (crossings == 0))
00563             return list;
00564     }
00565     return list;
00566 }
00567 
00568 /* largest_nodesize:
00569  * Return max dimension of nodes on list
00570  */
00571 static double largest_nodesize(nodelist_t * list)
00572 {
00573     Agnode_t *n;
00574     nodelistitem_t *item;
00575     double size = 0;
00576 
00577     for (item = list->first; item; item = item->next) {
00578         n = ORIGN(item->curr);
00579         if (ND_width(n) > size)
00580             size = ND_width(n);
00581         if (ND_height(n) > size)
00582             size = ND_height(n);
00583     }
00584     return size;
00585 }
00586 
00587 /* place_node:
00588  * Add n to list. By construction, n is not in list at start.
00589  */
00590 static void place_node(Agraph_t * g, Agnode_t * n, nodelist_t * list)
00591 {
00592     Agedge_t *e;
00593     int placed = 0;
00594     nodelist_t *neighbors = mkNodelist();
00595     nodelistitem_t *one, *two;
00596 
00597     for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00598         appendNodelist(neighbors, NULL, aghead(e));
00599         SET_NEIGHBOR(aghead(e));
00600     }
00601     for (e = agfstin(g, n); e; e = agnxtin(g, e)) {
00602         appendNodelist(neighbors, NULL, agtail(e));
00603         SET_NEIGHBOR(agtail(e));
00604     }
00605 
00606     /* Look for 2 neighbors consecutive on list */
00607     if (sizeNodelist(neighbors) >= 2) {
00608         for (one = list->first; one; one = one->next) {
00609             if (one == list->last)
00610                 two = list->first;
00611             else
00612                 two = one->next;
00613 
00614             if (NEIGHBOR(one->curr) && NEIGHBOR(two->curr)) {
00615                 appendNodelist(list, one, n);
00616                 placed = 1;
00617                 break;
00618             }
00619         }
00620     }
00621 
00622     /* Find any neighbor on list */
00623     if (!placed && sizeNodelist(neighbors) > 0) {
00624         for (one = list->first; one; one = one->next) {
00625             if (NEIGHBOR(one->curr)) {
00626                 appendNodelist(list, one, n);
00627                 placed = 1;
00628                 break;
00629             }
00630         }
00631     }
00632 
00633     if (!placed)
00634         appendNodelist(list, NULL, n);
00635 
00636     for (one = neighbors->first; one; one = one->next)
00637         UNSET_NEIGHBOR(one->curr);
00638     freeNodelist(neighbors);
00639 }
00640 
00641 /* place_residual_nodes:
00642  * Add nodes not in list to list.
00643  */
00644 static void place_residual_nodes(Agraph_t * g, nodelist_t * list)
00645 {
00646     Agnode_t *n;
00647 
00648     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00649         if (!ONPATH(n))
00650             place_node(g, n, list);
00651     }
00652 }
00653 
00654 nodelist_t *layout_block(Agraph_t * g, block_t * sn, double min_dist)
00655 {
00656     Agnode_t *n;
00657     Agraph_t *copyG, *tree, *subg;
00658     nodelist_t *longest_path;
00659     nodelistitem_t *item;
00660     int N, k;
00661     double theta, radius, largest_node;
00662     largest_node = 0;
00663 
00664     subg = sn->sub_graph;
00665     block_graph(g, sn);         /* add induced edges */
00666 
00667     copyG = remove_pair_edges(subg);
00668 
00669     tree = spanning_tree(copyG);
00670     longest_path = find_longest_path(tree);
00671     place_residual_nodes(subg, longest_path);
00672     /* at this point, longest_path is a list of all nodes in the block */
00673 
00674     /* apply crossing reduction algorithms here */
00675     longest_path = reduce_edge_crossings(longest_path, subg);
00676 
00677     N = sizeNodelist(longest_path);
00678     largest_node = largest_nodesize(longest_path);
00679     /* N*(min_dist+largest_node) is roughly circumference of required circle */
00680     if (N == 1)
00681         radius = 0;
00682     else
00683         radius = (N * (min_dist + largest_node)) / (2 * M_PI);
00684 
00685     for (item = longest_path->first; item; item = item->next) {
00686         n = item->curr;
00687         if (ISPARENT(n)) {
00688             /* QUESTION: Why is only one parent realigned? */
00689             realignNodelist(longest_path, item);
00690             break;
00691         }
00692     }
00693 
00694     k = 0;
00695     for (item = longest_path->first; item; item = item->next) {
00696         n = item->curr;
00697         POSITION(n) = k;
00698         PSI(n) = 0.0;
00699         theta = k * ((2.0 * M_PI) / N);
00700 
00701         ND_pos(n)[0] = radius * cos(theta);
00702         ND_pos(n)[1] = radius * sin(theta);
00703 
00704         k++;
00705     }
00706 
00707     if (N == 1)
00708         sn->radius = largest_node / 2;
00709     else
00710         sn->radius = radius;
00711     sn->rad0 = sn->radius;
00712 
00713     /* initialize parent pos */
00714     sn->parent_pos = -1;
00715 
00716     agclose(copyG);
00717     return longest_path;
00718 }
00719 
00720 #ifdef DEBUG
00721 void prTree(Agraph_t * g)
00722 {
00723     Agnode_t *n;
00724 
00725     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00726         if (TPARENT(n))
00727             fprintf(stderr, "%s -> %s\n", n->name, TPARENT(n)->name);
00728     }
00729 }
00730 #endif