|
Graphviz
2.31.20130618.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 #ifndef WITH_CGRAPH 00194 if (g != agroot(g)) 00195 memset(&(g->u), 0, sizeof(Agraphinfo_t)); 00196 #else /* WITH_CGRAPH */ 00197 if (g != agroot(g)) 00198 agdelrec(g,"Agraphinfo_t"); 00199 #endif /* WITH_CGRAPH */ 00200 } 00201 00202 /* delete the layout (but retain the underlying graph) */ 00203 void dot_cleanup(graph_t * g) 00204 { 00205 node_t *n; 00206 edge_t *e; 00207 00208 free_virtual_node_list(GD_nlist(g)); 00209 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00210 for (e = agfstout(g, n); e; e = agnxtout(g, e)) { 00211 gv_cleanup_edge(e); 00212 } 00213 dot_cleanup_node(n); 00214 } 00215 dot_cleanup_graph(g); 00216 } 00217 00218 #ifdef DEBUG 00219 int 00220 fastn (graph_t * g) 00221 { 00222 node_t* u; 00223 int cnt = 0; 00224 for (u = GD_nlist(g); u; u = ND_next(u)) cnt++; 00225 return cnt; 00226 } 00227 00228 static void 00229 dumpRanks (graph_t * g) 00230 { 00231 int i, j; 00232 node_t* u; 00233 rank_t *rank = GD_rank(g); 00234 int rcnt = 0; 00235 for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { 00236 fprintf (stderr, "[%d] :", i); 00237 for (j = 0; j < rank[i].n; j++) { 00238 u = rank[i].v[j]; 00239 rcnt++; 00240 if (streq(agnameof(u),"virtual")) 00241 fprintf (stderr, " %x", u); 00242 else 00243 fprintf (stderr, " %s", agnameof(u)); 00244 00245 } 00246 fprintf (stderr, "\n"); 00247 } 00248 fprintf (stderr, "count %d rank count = %d\n", fastn(g), rcnt); 00249 } 00250 #endif 00251 00252 #define MIN_AR 1.0 00253 #define MAX_AR 20.0 00254 #define DEF_PASSES 5 00255 00256 static aspect_t* 00257 setAspect (Agraph_t * g, aspect_t* adata) 00258 { 00259 double rv; 00260 char *p; 00261 int r, passes = DEF_PASSES; 00262 00263 p = agget (g, "aspect"); 00264 00265 if (!p || ((r = sscanf (p, "%lf,%d", &rv, &passes)) <= 0)) { 00266 adata->nextIter = 0; 00267 adata->badGraph = 0; 00268 return NULL; 00269 } 00270 00271 if (rv < MIN_AR) rv = MIN_AR; 00272 else if (rv > MAX_AR) rv = MAX_AR; 00273 adata->targetAR = rv; 00274 adata->nextIter = -1; 00275 adata->nPasses = passes; 00276 adata->badGraph = 0; 00277 00278 if (Verbose) 00279 fprintf(stderr, "Target AR = %g\n", adata->targetAR); 00280 00281 return adata; 00282 } 00283 00284 #ifdef WITH_CGRAPH 00285 static void 00286 remove_from_rank (Agraph_t * g, Agnode_t* n) 00287 { 00288 Agnode_t* v = NULL; 00289 int j, rk = ND_rank(n); 00290 00291 for (j = 0; j < GD_rank(g)[rk].n; j++) { 00292 v = GD_rank(g)[rk].v[j]; 00293 if (v == n) { 00294 for (j++; j < GD_rank(g)[rk].n; j++) { 00295 GD_rank(g)[rk].v[j-1] = GD_rank(g)[rk].v[j]; 00296 } 00297 GD_rank(g)[rk].n--; 00298 break; 00299 } 00300 } 00301 assert (v == n); /* if found */ 00302 } 00303 00304 /* removeFill: 00305 * This removes all of the fill nodes added in mincross. 00306 * It appears to be sufficient to remove them only from the 00307 * rank array and fast node list of the root graph. 00308 */ 00309 static void 00310 removeFill (Agraph_t * g) 00311 { 00312 Agnode_t* n; 00313 Agnode_t* nxt; 00314 Agraph_t* sg = agsubg (g, "_new_rank", 0); 00315 00316 if (!sg) return; 00317 for (n = agfstnode(sg); n; n = nxt) { 00318 nxt = agnxtnode(sg, n); 00319 delete_fast_node (g, n); 00320 remove_from_rank (g, n); 00321 dot_cleanup_node (n); 00322 agdelnode(g, n); 00323 } 00324 agdelsubg (g, sg); 00325 00326 } 00327 #endif 00328 00329 #ifndef WITH_CGRAPH 00330 #define ag_xset(x,a,v) agxset(x,a->index,v) 00331 #else /* WITH_CGRAPH */ 00332 #define ag_xset(x,a,v) agxset(x,a,v) 00333 #define agnodeattr(g,n,v) agattr(g,AGNODE,n,v) 00334 #endif /* WITH_CGRAPH */ 00335 00336 static void 00337 attach_phase_attrs (Agraph_t * g, int maxphase) 00338 { 00339 Agsym_t* rk = agnodeattr(g,"rank",""); 00340 Agsym_t* order = agnodeattr(g,"order",""); 00341 Agnode_t* n; 00342 char buf[BUFSIZ]; 00343 00344 for (n = agfstnode(g); n; n = agnxtnode(g,n)) { 00345 if (maxphase >= 1) { 00346 sprintf(buf, "%d", ND_rank(n)); 00347 ag_xset(n,rk,buf); 00348 } 00349 if (maxphase >= 2) { 00350 sprintf(buf, "%d", ND_order(n)); 00351 ag_xset(n,order,buf); 00352 } 00353 } 00354 } 00355 00356 void dot_layout(Agraph_t * g) 00357 { 00358 aspect_t aspect; 00359 aspect_t* asp; 00360 int maxphase = late_int(g, agfindgraphattr(g,"phase"), -1, 1); 00361 00362 setEdgeType (g, ET_SPLINE); 00363 asp = setAspect (g, &aspect); 00364 00365 #ifdef WITH_CGRAPH 00366 dot_init_subg(g); 00367 #endif 00368 00369 dot_init_node_edge(g); 00370 00371 do { 00372 dot_rank(g, asp); 00373 if (maxphase == 1) { 00374 attach_phase_attrs (g, 1); 00375 return; 00376 } 00377 if (aspect.badGraph) { 00378 agerr(AGWARN, "dot does not support the aspect attribute for disconnected graphs or graphs with clusters\n"); 00379 asp = NULL; 00380 aspect.nextIter = 0; 00381 } 00382 dot_mincross(g, (asp != NULL)); 00383 if (maxphase == 2) { 00384 attach_phase_attrs (g, 2); 00385 return; 00386 } 00387 dot_position(g, asp); 00388 if (maxphase == 3) { 00389 attach_phase_attrs (g, 2); /* positions will be attached on output */ 00390 return; 00391 } 00392 aspect.nPasses--; 00393 } while (aspect.nextIter && aspect.nPasses); 00394 #ifdef WITH_CGRAPH 00395 if (GD_flags(g) & NEW_RANK) 00396 removeFill (g); 00397 #endif 00398 dot_sameports(g); 00399 dot_splines(g); 00400 if (mapbool(agget(g, "compound"))) 00401 dot_compoundEdges(g); 00402 dotneato_postprocess(g); 00403 00404 }
1.7.5