Graphviz  2.35.20130930.0449
dotinit.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 
15 #include <time.h>
16 #include "dot.h"
17 #include "aspect.h"
18 
19 #ifdef WITH_CGRAPH
20 static void
21 dot_init_subg(graph_t * g)
22 {
23  graph_t* subg;
24 
25  if ((g != agroot(g)))
26  agbindrec(g, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
27  for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
28  dot_init_subg(subg);
29  }
30 }
31 #endif
32 
33 
34 static void
35 dot_init_node(node_t * n)
36 {
37 #ifdef WITH_CGRAPH
38  agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); //graph custom data
39 #endif /* WITH_CGRAPH */
41  gv_nodesize(n, GD_flip(agraphof(n)));
42  alloc_elist(4, ND_in(n));
43  alloc_elist(4, ND_out(n));
44  alloc_elist(2, ND_flat_in(n));
45  alloc_elist(2, ND_flat_out(n));
46  alloc_elist(2, ND_other(n));
47  ND_UF_size(n) = 1;
48 }
49 
50 static void
51 dot_init_edge(edge_t * e)
52 {
53  char *tailgroup, *headgroup;
54 #ifdef WITH_CGRAPH
55  agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //graph custom data
56 #endif /* WITH_CGRAPH */
58 
59  ED_weight(e) = late_int(e, E_weight, 1, 0);
60  tailgroup = late_string(agtail(e), N_group, "");
61  headgroup = late_string(aghead(e), N_group, "");
62  ED_count(e) = ED_xpenalty(e) = 1;
63  if (tailgroup[0] && (tailgroup == headgroup)) {
64  ED_xpenalty(e) = CL_CROSS;
65  ED_weight(e) *= 100;
66  }
67  if (nonconstraint_edge(e)) {
68  ED_xpenalty(e) = 0;
69  ED_weight(e) = 0;
70  }
71 
72  ED_showboxes(e) = late_int(e, E_showboxes, 0, 0);
73  ED_minlen(e) = late_int(e, E_minlen, 1, 0);
74 }
75 
76 void
78 {
79  node_t *n;
80  edge_t *e;
81 
82  for (n = agfstnode(g); n; n = agnxtnode(g, n))
83  dot_init_node(n);
84  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
85  for (e = agfstout(g, n); e; e = agnxtout(g, e))
86  dot_init_edge(e);
87  }
88 }
89 
90 #if 0 /* not used */
91 static void free_edge_list(elist L)
92 {
93  edge_t *e;
94  int i;
95 
96  for (i = 0; i < L.size; i++) {
97  e = L.list[i];
98  free(e);
99  }
100 }
101 #endif
102 
103 static void
104 dot_cleanup_node(node_t * n)
105 {
106  free_list(ND_in(n));
107  free_list(ND_out(n));
109  free_list(ND_flat_in(n));
110  free_list(ND_other(n));
111  free_label(ND_label(n));
112  if (ND_shape(n))
113  ND_shape(n)->fns->freefn(n);
114 #ifndef WITH_CGRAPH
115  memset(&(n->u), 0, sizeof(Agnodeinfo_t));
116 #else /* WITH_CGRAPH */
117  agdelrec(n, "Agnodeinfo_t");
118 #endif /* WITH_CGRAPH */
119 }
120 
121 static void free_virtual_edge_list(node_t * n)
122 {
123  edge_t *e;
124  int i;
125 
126  for (i = ND_in(n).size - 1; i >= 0; i--) {
127  e = ND_in(n).list[i];
128  delete_fast_edge(e);
129 #ifdef WITH_CGRAPH
130  free(e->base.data);
131 #endif
132  free(e);
133  }
134  for (i = ND_out(n).size - 1; i >= 0; i--) {
135  e = ND_out(n).list[i];
136  delete_fast_edge(e);
137 #ifdef WITH_CGRAPH
138  free(e->base.data);
139 #endif
140  free(e);
141  }
142 }
143 
144 static void free_virtual_node_list(node_t * vn)
145 {
146  node_t *next_vn;
147 
148  while (vn) {
149  next_vn = ND_next(vn);
150  free_virtual_edge_list(vn);
151  if (ND_node_type(vn) == VIRTUAL) {
152  free_list(ND_out(vn));
153  free_list(ND_in(vn));
154 #ifdef WITH_CGRAPH
155  free(vn->base.data);
156 #endif
157  free(vn);
158  }
159  vn = next_vn;
160  }
161 }
162 
163 static void
164 dot_cleanup_graph(graph_t * g)
165 {
166  int i;
167 #ifndef WITH_CGRAPH
168  graph_t *clust;
169  int c;
170  for (c = 1; c <= GD_n_cluster(g); c++) {
171  clust = GD_clust(g)[c];
172  GD_parent(clust) = NULL;
173  dot_cleanup(clust);
174  }
175 #else
176  graph_t *subg;
177  for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
178  dot_cleanup_graph(subg);
179  }
180 #endif
181  if (GD_clust(g)) free (GD_clust(g));
182  if (GD_rankleader(g)) free (GD_rankleader(g));
183 
184  free_list(GD_comp(g));
185  if (GD_rank(g)) {
186  for (i = GD_minrank(g); i <= GD_maxrank(g); i++)
187  free(GD_rank(g)[i].av);
188  if (GD_minrank(g) == -1)
189  free(GD_rank(g)-1);
190  else
191  free(GD_rank(g));
192  }
193 #ifndef WITH_CGRAPH
194  if (g != agroot(g))
195  memset(&(g->u), 0, sizeof(Agraphinfo_t));
196 #else /* WITH_CGRAPH */
197  if (g != agroot(g))
198  agdelrec(g,"Agraphinfo_t");
199 #endif /* WITH_CGRAPH */
200 }
201 
202 /* delete the layout (but retain the underlying graph) */
204 {
205  node_t *n;
206  edge_t *e;
207 
208  free_virtual_node_list(GD_nlist(g));
209  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
210  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
211  gv_cleanup_edge(e);
212  }
213  dot_cleanup_node(n);
214  }
215  dot_cleanup_graph(g);
216 }
217 
218 #ifdef DEBUG
219 int
220 fastn (graph_t * g)
221 {
222  node_t* u;
223  int cnt = 0;
224  for (u = GD_nlist(g); u; u = ND_next(u)) cnt++;
225  return cnt;
226 }
227 
228 static void
229 dumpRanks (graph_t * g)
230 {
231  int i, j;
232  node_t* u;
233  rank_t *rank = GD_rank(g);
234  int rcnt = 0;
235  for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
236  fprintf (stderr, "[%d] :", i);
237  for (j = 0; j < rank[i].n; j++) {
238  u = rank[i].v[j];
239  rcnt++;
240  if (streq(agnameof(u),"virtual"))
241  fprintf (stderr, " %x", u);
242  else
243  fprintf (stderr, " %s", agnameof(u));
244 
245  }
246  fprintf (stderr, "\n");
247  }
248  fprintf (stderr, "count %d rank count = %d\n", fastn(g), rcnt);
249 }
250 #endif
251 
252 
253 #ifdef WITH_CGRAPH
254 static void
255 remove_from_rank (Agraph_t * g, Agnode_t* n)
256 {
257  Agnode_t* v = NULL;
258  int j, rk = ND_rank(n);
259 
260  for (j = 0; j < GD_rank(g)[rk].n; j++) {
261  v = GD_rank(g)[rk].v[j];
262  if (v == n) {
263  for (j++; j < GD_rank(g)[rk].n; j++) {
264  GD_rank(g)[rk].v[j-1] = GD_rank(g)[rk].v[j];
265  }
266  GD_rank(g)[rk].n--;
267  break;
268  }
269  }
270  assert (v == n); /* if found */
271 }
272 
273 /* removeFill:
274  * This removes all of the fill nodes added in mincross.
275  * It appears to be sufficient to remove them only from the
276  * rank array and fast node list of the root graph.
277  */
278 static void
279 removeFill (Agraph_t * g)
280 {
281  Agnode_t* n;
282  Agnode_t* nxt;
283  Agraph_t* sg = agsubg (g, "_new_rank", 0);
284 
285  if (!sg) return;
286  for (n = agfstnode(sg); n; n = nxt) {
287  nxt = agnxtnode(sg, n);
288  delete_fast_node (g, n);
289  remove_from_rank (g, n);
290  dot_cleanup_node (n);
291  agdelnode(g, n);
292  }
293  agdelsubg (g, sg);
294 
295 }
296 #endif
297 
298 #ifndef WITH_CGRAPH
299 #define ag_xset(x,a,v) agxset(x,a->index,v)
300 #else /* WITH_CGRAPH */
301 #define ag_xset(x,a,v) agxset(x,a,v)
302 #define agnodeattr(g,n,v) agattr(g,AGNODE,n,v)
303 #endif /* WITH_CGRAPH */
304 
305 static void
306 attach_phase_attrs (Agraph_t * g, int maxphase)
307 {
308  Agsym_t* rk = agnodeattr(g,"rank","");
309  Agsym_t* order = agnodeattr(g,"order","");
310  Agnode_t* n;
311  char buf[BUFSIZ];
312 
313  for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
314  if (maxphase >= 1) {
315  sprintf(buf, "%d", ND_rank(n));
316  ag_xset(n,rk,buf);
317  }
318  if (maxphase >= 2) {
319  sprintf(buf, "%d", ND_order(n));
320  ag_xset(n,order,buf);
321  }
322  }
323 }
324 
326 {
327  aspect_t aspect;
328  aspect_t* asp;
329  int maxphase = late_int(g, agfindgraphattr(g,"phase"), -1, 1);
330 
331  setEdgeType (g, ET_SPLINE);
332  asp = setAspect (g, &aspect);
333 
334 #ifdef WITH_CGRAPH
335  dot_init_subg(g);
336 #endif
337 
339 
340  do {
341  dot_rank(g, asp);
342  if (maxphase == 1) {
343  attach_phase_attrs (g, 1);
344  return;
345  }
346  if (aspect.badGraph) {
347  agerr(AGWARN, "dot does not support the aspect attribute for disconnected graphs or graphs with clusters\n");
348  asp = NULL;
349  aspect.nextIter = 0;
350  }
351  dot_mincross(g, (asp != NULL));
352  if (maxphase == 2) {
353  attach_phase_attrs (g, 2);
354  return;
355  }
356  dot_position(g, asp);
357  if (maxphase == 3) {
358  attach_phase_attrs (g, 2); /* positions will be attached on output */
359  return;
360  }
361  aspect.nPasses--;
362  } while (aspect.nextIter && aspect.nPasses);
363 #ifdef WITH_CGRAPH
364  if (GD_flags(g) & NEW_RANK)
365  removeFill (g);
366 #endif
367  dot_sameports(g);
368  dot_splines(g);
369  if (mapbool(agget(g, "compound")))
372 
373 }