|
Graphviz
2.31.20130525.0447
|
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 /* 00016 * Circular layout. Biconnected components are put on circles. 00017 * block-cutnode tree is done recursively, with children placed 00018 * about parent block. 00019 * Based on: 00020 * Six and Tollis, "A Framework for Circular Drawings of 00021 * Networks", GD '99, LNCS 1731, pp. 107-116; 00022 * Six and Tollis, "Circular Drawings of Biconnected Graphs", 00023 * Proc. ALENEX '99, pp 57-73. 00024 * Kaufmann and Wiese, "Maintaining the Mental Map for Circular 00025 * Drawings", GD '02, LNCS 2528, pp. 12-22. 00026 */ 00027 00028 #include "circular.h" 00029 #include "adjust.h" 00030 #include "pack.h" 00031 #include "neatoprocs.h" 00032 #include <string.h> 00033 00034 static void circular_init_edge(edge_t * e) 00035 { 00036 #ifdef WITH_CGRAPH 00037 agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //node custom data 00038 #endif /* WITH_CGRAPH */ 00039 common_init_edge(e); 00040 00041 ED_factor(e) = late_double(e, E_weight, 1.0, 0.0); 00042 } 00043 00044 00045 static void circular_init_node_edge(graph_t * g) 00046 { 00047 node_t *n; 00048 edge_t *e; 00049 int i = 0; 00050 ndata* alg = N_NEW(agnnodes(g), ndata); 00051 00052 GD_neato_nlist(g) = N_NEW(agnnodes(g) + 1, node_t *); 00053 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00054 neato_init_node(n); 00055 ND_alg(n) = alg + i; 00056 GD_neato_nlist(g)[i++] = n; 00057 } 00058 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00059 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00060 circular_init_edge(e); 00061 } 00062 } 00063 } 00064 00065 00066 void circo_init_graph(graph_t * g) 00067 { 00068 setEdgeType (g, ET_LINE); 00069 /* GD_ndim(g) = late_int(g,agfindattr(g,"dim"),2,2); */ 00070 Ndim = GD_ndim(g) = 2; /* The algorithm only makes sense in 2D */ 00071 circular_init_node_edge(g); 00072 } 00073 00074 /* makeDerivedNode: 00075 * Make a node in the derived graph, with the given name. 00076 * orig points to what it represents, either a real node or 00077 * a cluster. Copy size info from original node; needed for 00078 * adjustNodes and packSubgraphs. 00079 */ 00080 static node_t *makeDerivedNode(graph_t * dg, char *name, int isNode, 00081 void *orig) 00082 { 00083 #ifndef WITH_CGRAPH 00084 node_t *n = agnode(dg, name); 00085 #else /* WITH_CGRAPH */ 00086 node_t *n = agnode(dg, name,1); 00087 agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); //node custom data 00088 #endif /* WITH_CGRAPH */ 00089 ND_alg(n) = (void *) NEW(cdata); 00090 if (isNode) { 00091 ND_pos(n) = N_NEW(Ndim, double); 00092 ND_lw(n) = ND_lw((node_t *) orig); 00093 ND_rw(n) = ND_rw((node_t *) orig); 00094 ND_ht(n) = ND_ht((node_t *) orig); 00095 ORIGN(n) = (node_t *) orig; 00096 } else 00097 ORIGG(n) = (graph_t *) orig; 00098 return n; 00099 } 00100 00101 /* circomps: 00102 * Construct a strict, undirected graph with no loops from g. 00103 * Construct the connected components with the provision that all 00104 * nodes in a block subgraph are considered connected. 00105 * Return array of components with number of components in cnt. 00106 * Each component has its blocks as subgraphs. 00107 * FIX: Check that blocks are disjoint. 00108 */ 00109 Agraph_t **circomps(Agraph_t * g, int *cnt) 00110 { 00111 int c_cnt; 00112 Agraph_t **ccs; 00113 Agraph_t *dg; 00114 Agnode_t *n, *v, *dt, *dh; 00115 Agedge_t *e; 00116 Agraph_t *sg; 00117 int i; 00118 Agedge_t *ep; 00119 Agnode_t *p; 00120 00121 #ifndef WITH_CGRAPH 00122 dg = agopen("derived", AGFLAG_STRICT); 00123 #else /* WITH_CGRAPH */ 00124 dg = agopen("derived", Agstrictundirected,NIL(Agdisc_t *)); 00125 #endif /* WITH_CGRAPH */ 00126 GD_alg(g) = dg; /* store derived graph for closing later */ 00127 00128 for (v = agfstnode(g); v; v = agnxtnode(g, v)) { 00129 if (DNODE(v)) 00130 continue; 00131 n = makeDerivedNode(dg, agnameof(v), 1, v); 00132 DNODE(v) = n; 00133 } 00134 00135 for (v = agfstnode(g); v; v = agnxtnode(g, v)) { 00136 for (e = agfstout(g, v); e; e = agnxtout(g, e)) { 00137 dt = DNODE(agtail(e)); 00138 dh = DNODE(aghead(e)); 00139 if (dt != dh) { 00140 #ifndef WITH_CGRAPH 00141 agedge(dg, dt, dh); 00142 #else /* WITH_CGRAPH */ 00143 agbindrec(agedge(dg, dt, dh, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //node custom data 00144 #endif /* WITH_CGRAPH */ 00145 } 00146 } 00147 } 00148 00149 ccs = ccomps(dg, &c_cnt, 0); 00150 00151 /* replace block nodes with block contents */ 00152 for (i = 0; i < c_cnt; i++) { 00153 sg = ccs[i]; 00154 00155 /* add edges: since sg is a union of components, all edges 00156 * of any node should be added, except loops. 00157 */ 00158 for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) { 00159 p = ORIGN(n); 00160 for (e = agfstout(g, p); e; e = agnxtout(g, e)) { 00161 /* n = DNODE(agtail(e)); by construction since agtail(e) == p */ 00162 dh = DNODE(aghead(e)); 00163 if (n != dh) { 00164 #ifndef WITH_CGRAPH 00165 ep = agedge(dg, n, dh); 00166 aginsert(sg, ep); 00167 #else /* WITH_CGRAPH */ 00168 ep = agedge(dg, n, dh, NULL, 1); 00169 agbindrec(ep, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //node custom data 00170 agsubedge(sg,ep,1); 00171 #endif /* WITH_CGRAPH */ 00172 } 00173 } 00174 } 00175 } 00176 00177 /* Finally, add edge data to edges */ 00178 for (n = agfstnode(dg); n; n = agnxtnode(dg, n)) { 00179 for (e = agfstout(dg, n); e; e = agnxtout(dg, e)) { 00180 ED_alg(e) = NEW(edata); 00181 } 00182 } 00183 00184 *cnt = c_cnt; 00185 return ccs; 00186 } 00187 00188 /* closeDerivedGraph: 00189 */ 00190 static void closeDerivedGraph(graph_t * g) 00191 { 00192 node_t *n; 00193 edge_t *e; 00194 00195 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00196 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00197 free(ED_alg(e)); 00198 } 00199 free(ND_alg(n)); 00200 free(ND_pos(n)); 00201 } 00202 agclose(g); 00203 } 00204 00205 /* copyPosns: 00206 * Copy position of nodes in given subgraph of derived graph 00207 * to corresponding node in original graph. 00208 * FIX: consider assigning from n directly to ORIG(n). 00209 */ 00210 static void copyPosns(graph_t * g) 00211 { 00212 node_t *n; 00213 node_t *v; 00214 00215 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00216 v = ORIGN(n); 00217 ND_pos(v)[0] = ND_pos(n)[0]; 00218 ND_pos(v)[1] = ND_pos(n)[1]; 00219 } 00220 } 00221 00222 /* circoLayout: 00223 */ 00224 void circoLayout(Agraph_t * g) 00225 { 00226 Agraph_t **ccs; 00227 Agraph_t *sg; 00228 int ncc; 00229 int i; 00230 00231 if (agnnodes(g)) { 00232 ccs = circomps(g, &ncc); 00233 00234 if (ncc == 1) { 00235 circularLayout(ccs[0], g); 00236 copyPosns(ccs[0]); 00237 adjustNodes(g); 00238 } else { 00239 Agraph_t *dg = ccs[0]->root; 00240 pack_info pinfo; 00241 getPackInfo(g, l_node, CL_OFFSET, &pinfo); 00242 00243 for (i = 0; i < ncc; i++) { 00244 sg = ccs[i]; 00245 circularLayout(sg, g); 00246 adjustNodes(sg); 00247 } 00248 /* FIX: splines have not been calculated for dg 00249 * To use, either do splines in dg and copy to g, or 00250 * construct components of g from ccs and use that in packing. 00251 */ 00252 packSubgraphs(ncc, ccs, dg, &pinfo); 00253 for (i = 0; i < ncc; i++) 00254 copyPosns(ccs[i]); 00255 } 00256 free(ccs); 00257 } 00258 } 00259 00260 /* circo_layout: 00261 */ 00262 void circo_layout(Agraph_t * g) 00263 { 00264 if (agnnodes(g) == 0) return; 00265 circo_init_graph(g); 00266 circoLayout(g); 00267 /* Release ND_alg as we need to reuse it during edge routing */ 00268 free(ND_alg(agfstnode(g))); 00269 spline_edges(g); 00270 dotneato_postprocess(g); 00271 } 00272 00273 /* circo_cleanup: 00274 * ND_alg is freed in circo_layout 00275 */ 00276 void circo_cleanup(graph_t * g) 00277 { 00278 node_t *n; 00279 edge_t *e; 00280 00281 n = agfstnode(g); 00282 if (n == NULL) 00283 return; /* g is empty */ 00284 00285 closeDerivedGraph((graph_t*)GD_alg(g)); /* delete derived graph */ 00286 00287 /* free (ND_alg(n)); */ 00288 for (; n; n = agnxtnode(g, n)) { 00289 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00290 gv_cleanup_edge(e); 00291 } 00292 gv_cleanup_node(n); 00293 } 00294 free(GD_neato_nlist(g)); 00295 if (g != agroot(g)) 00296 #ifndef WITH_CGRAPH 00297 memset(&(g->u), 0, sizeof(Agraphinfo_t)); 00298 #else /* WITH_CGRAPH */ 00299 agclean (g,AGRAPH,"Agraphinfo_t"); 00300 #endif /* WITH_CGRAPH */ 00301 }
1.7.5