|
Graphviz 2.29.20120208.0545
|
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
1.7.4