|
Graphviz
2.29.20120523.0446
|
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 <time.h> 00016 #include "dot.h" 00017 #include "aspect.h" 00018 00019 #ifdef WITH_CGRAPH 00020 static void 00021 dot_init_subg(graph_t * g) 00022 { 00023 graph_t* subg; 00024 00025 if ((g != agroot(g))) 00026 agbindrec(g, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); 00027 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { 00028 dot_init_subg(subg); 00029 } 00030 } 00031 #endif 00032 00033 00034 static void 00035 dot_init_node(node_t * n) 00036 { 00037 #ifdef WITH_CGRAPH 00038 agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); //graph custom data 00039 #endif /* WITH_CGRAPH */ 00040 common_init_node(n); 00041 gv_nodesize(n, GD_flip(agraphof(n))); 00042 alloc_elist(4, ND_in(n)); 00043 alloc_elist(4, ND_out(n)); 00044 alloc_elist(2, ND_flat_in(n)); 00045 alloc_elist(2, ND_flat_out(n)); 00046 alloc_elist(2, ND_other(n)); 00047 ND_UF_size(n) = 1; 00048 } 00049 00050 static void 00051 dot_init_edge(edge_t * e) 00052 { 00053 char *tailgroup, *headgroup; 00054 #ifdef WITH_CGRAPH 00055 agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //graph custom data 00056 #endif /* WITH_CGRAPH */ 00057 common_init_edge(e); 00058 00059 ED_weight(e) = late_int(e, E_weight, 1, 0); 00060 tailgroup = late_string(agtail(e), N_group, ""); 00061 headgroup = late_string(aghead(e), N_group, ""); 00062 ED_count(e) = ED_xpenalty(e) = 1; 00063 if (tailgroup[0] && (tailgroup == headgroup)) { 00064 ED_xpenalty(e) = CL_CROSS; 00065 ED_weight(e) *= 100; 00066 } 00067 if (nonconstraint_edge(e)) { 00068 ED_xpenalty(e) = 0; 00069 ED_weight(e) = 0; 00070 } 00071 00072 ED_showboxes(e) = late_int(e, E_showboxes, 0, 0); 00073 ED_minlen(e) = late_int(e, E_minlen, 1, 0); 00074 } 00075 00076 void 00077 dot_init_node_edge(graph_t * g) 00078 { 00079 node_t *n; 00080 edge_t *e; 00081 00082 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 00083 dot_init_node(n); 00084 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00085 for (e = agfstout(g, n); e; e = agnxtout(g, e)) 00086 dot_init_edge(e); 00087 } 00088 } 00089 00090 #if 0 /* not used */ 00091 static void free_edge_list(elist L) 00092 { 00093 edge_t *e; 00094 int i; 00095 00096 for (i = 0; i < L.size; i++) { 00097 e = L.list[i]; 00098 free(e); 00099 } 00100 } 00101 #endif 00102 00103 static void 00104 dot_cleanup_node(node_t * n) 00105 { 00106 free_list(ND_in(n)); 00107 free_list(ND_out(n)); 00108 free_list(ND_flat_out(n)); 00109 free_list(ND_flat_in(n)); 00110 free_list(ND_other(n)); 00111 free_label(ND_label(n)); 00112 if (ND_shape(n)) 00113 ND_shape(n)->fns->freefn(n); 00114 #ifndef WITH_CGRAPH 00115 memset(&(n->u), 0, sizeof(Agnodeinfo_t)); 00116 #else /* WITH_CGRAPH */ 00117 agdelrec(n, "Agnodeinfo_t"); 00118 #endif /* WITH_CGRAPH */ 00119 } 00120 00121 static void free_virtual_edge_list(node_t * n) 00122 { 00123 edge_t *e; 00124 int i; 00125 00126 for (i = ND_in(n).size - 1; i >= 0; i--) { 00127 e = ND_in(n).list[i]; 00128 delete_fast_edge(e); 00129 #ifdef WITH_CGRAPH 00130 free(e->base.data); 00131 #endif 00132 free(e); 00133 } 00134 for (i = ND_out(n).size - 1; i >= 0; i--) { 00135 e = ND_out(n).list[i]; 00136 delete_fast_edge(e); 00137 #ifdef WITH_CGRAPH 00138 free(e->base.data); 00139 #endif 00140 free(e); 00141 } 00142 } 00143 00144 static void free_virtual_node_list(node_t * vn) 00145 { 00146 node_t *next_vn; 00147 00148 while (vn) { 00149 next_vn = ND_next(vn); 00150 free_virtual_edge_list(vn); 00151 if (ND_node_type(vn) == VIRTUAL) { 00152 free_list(ND_out(vn)); 00153 free_list(ND_in(vn)); 00154 #ifdef WITH_CGRAPH 00155 free(vn->base.data); 00156 #endif 00157 free(vn); 00158 } 00159 vn = next_vn; 00160 } 00161 } 00162 00163 static void 00164 dot_cleanup_graph(graph_t * g) 00165 { 00166 int i; 00167 #ifndef WITH_CGRAPH 00168 graph_t *clust; 00169 int c; 00170 for (c = 1; c <= GD_n_cluster(g); c++) { 00171 clust = GD_clust(g)[c]; 00172 GD_parent(clust) = NULL; 00173 dot_cleanup(clust); 00174 } 00175 #else 00176 graph_t *subg; 00177 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { 00178 dot_cleanup_graph(subg); 00179 } 00180 #endif 00181 if (GD_clust(g)) free (GD_clust(g)); 00182 if (GD_rankleader(g)) free (GD_rankleader(g)); 00183 00184 free_list(GD_comp(g)); 00185 if (GD_rank(g)) { 00186 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) 00187 free(GD_rank(g)[i].av); 00188 if (GD_minrank(g) == -1) 00189 free(GD_rank(g)-1); 00190 else 00191 free(GD_rank(g)); 00192 } 00193 if (g != agroot(g)) 00194 #ifndef WITH_CGRAPH 00195 memset(&(g->u), 0, sizeof(Agraphinfo_t)); 00196 #else /* WITH_CGRAPH */ 00197 agdelrec(g,"Agraphinfo_t"); 00198 #endif /* WITH_CGRAPH */ 00199 } 00200 00201 /* delete the layout (but retain the underlying graph) */ 00202 void dot_cleanup(graph_t * g) 00203 { 00204 node_t *n; 00205 edge_t *e; 00206 00207 free_virtual_node_list(GD_nlist(g)); 00208 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00209 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00210 gv_cleanup_edge(e); 00211 } 00212 dot_cleanup_node(n); 00213 } 00214 dot_cleanup_graph(g); 00215 } 00216 00217 #ifdef DEBUG 00218 int 00219 fastn (graph_t * g) 00220 { 00221 node_t* u; 00222 int cnt = 0; 00223 for (u = GD_nlist(g); u; u = ND_next(u)) cnt++; 00224 return cnt; 00225 } 00226 00227 static void 00228 dumpRanks (graph_t * g) 00229 { 00230 int i, j; 00231 node_t* u; 00232 rank_t *rank = GD_rank(g); 00233 int rcnt = 0; 00234 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { 00235 fprintf (stderr, "[%d] :", i); 00236 for (j = 0; j < rank[i].n; j++) { 00237 u = rank[i].v[j]; 00238 rcnt++; 00239 if (streq(u->name,"virtual")) 00240 fprintf (stderr, " %x", u); 00241 else 00242 fprintf (stderr, " %s", u->name); 00243 00244 } 00245 fprintf (stderr, "\n"); 00246 } 00247 fprintf (stderr, "count %d rank count = %d\n", fastn(g), rcnt); 00248 } 00249 #endif 00250 00251 #define MIN_AR 1.0 00252 #define MAX_AR 20.0 00253 #define DEF_PASSES 5 00254 00255 static aspect_t* 00256 setAspect (Agraph_t * g, aspect_t* adata) 00257 { 00258 double rv; 00259 char *p; 00260 int r, passes = DEF_PASSES; 00261 00262 p = agget (g, "aspect"); 00263 00264 if (!p || ((r = sscanf (p, "%lf,%d", &rv, &passes)) <= 0)) { 00265 adata->nextIter = 0; 00266 adata->badGraph = 0; 00267 return NULL; 00268 } 00269 00270 if (rv < MIN_AR) rv = MIN_AR; 00271 else if (rv > MAX_AR) rv = MAX_AR; 00272 adata->targetAR = rv; 00273 adata->nextIter = -1; 00274 adata->nPasses = passes; 00275 adata->badGraph = 0; 00276 00277 if (Verbose) 00278 fprintf(stderr, "Target AR = %g\n", adata->targetAR); 00279 00280 return adata; 00281 } 00282 00283 #ifdef WITH_CGRAPH 00284 static void 00285 remove_from_rank (Agraph_t * g, Agnode_t* n) 00286 { 00287 Agnode_t* v = NULL; 00288 int j, rk = ND_rank(n); 00289 00290 for (j = 0; j < GD_rank(g)[rk].n; j++) { 00291 v = GD_rank(g)[rk].v[j]; 00292 if (v == n) { 00293 for (j++; j < GD_rank(g)[rk].n; j++) { 00294 GD_rank(g)[rk].v[j-1] = GD_rank(g)[rk].v[j]; 00295 } 00296 GD_rank(g)[rk].n--; 00297 break; 00298 } 00299 } 00300 assert (v == n); /* if found */ 00301 } 00302 00303 /* removeFill: 00304 * This removes all of the fill nodes added in mincross. 00305 * It appears to be sufficient to remove them only from the 00306 * rank array and fast node list of the root graph. 00307 */ 00308 static void 00309 removeFill (Agraph_t * g) 00310 { 00311 Agnode_t* n; 00312 Agnode_t* nxt; 00313 Agraph_t* sg = agsubg (g, "_new_rank", 0); 00314 00315 if (!sg) return; 00316 for (n = agfstnode(sg); n; n = nxt) { 00317 nxt = agnxtnode(sg, n); 00318 delete_fast_node (g, n); 00319 remove_from_rank (g, n); 00320 dot_cleanup_node (n); 00321 agdelnode(g, n); 00322 } 00323 agdelsubg (g, sg); 00324 00325 } 00326 #endif 00327 00328 void dot_layout(Agraph_t * g) 00329 { 00330 aspect_t aspect; 00331 aspect_t* asp; 00332 00333 setEdgeType (g, ET_SPLINE); 00334 asp = setAspect (g, &aspect); 00335 00336 #ifdef WITH_CGRAPH 00337 dot_init_subg(g); 00338 #endif 00339 00340 dot_init_node_edge(g); 00341 00342 do { 00343 dot_rank(g, asp); 00344 if (aspect.badGraph) { 00345 agerr(AGWARN, "dot does not support the aspect attribute for disconnected graphs or graphs with clusters\n"); 00346 asp = NULL; 00347 aspect.nextIter = 0; 00348 } 00349 dot_mincross(g, (asp != NULL)); 00350 dot_position(g, asp); 00351 aspect.nPasses--; 00352 } while (aspect.nextIter && aspect.nPasses); 00353 #ifdef WITH_CGRAPH 00354 if (GD_flags(g) & NEW_RANK) 00355 removeFill (g); 00356 #endif 00357 dot_sameports(g); 00358 dot_splines(g); 00359 if (mapbool(agget(g, "compound"))) 00360 dot_compoundEdges(g); 00361 dotneato_postprocess(g); 00362 00363 }
1.7.5