Graphviz  2.35.20130930.0449
twopiinit.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 /*
16  * Written by Emden R. Gansner
17  * Derived from Graham Wills' algorithm described in GD'97.
18  */
19 
20 #include "circle.h"
21 #include "adjust.h"
22 #include "pack.h"
23 #include "neatoprocs.h"
24 
25 static void twopi_init_edge(edge_t * e)
26 {
27 #ifdef WITH_CGRAPH
28  agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //edge custom data
29 #endif /* WITH_CGRAPH */
31  ED_factor(e) = late_double(e, E_weight, 1.0, 0.0);
32 }
33 
34 static void twopi_init_node_edge(graph_t * g)
35 {
36  node_t *n;
37  edge_t *e;
38  int i = 0;
39  int n_nodes = agnnodes(g);
40  rdata* alg;
41 
42  alg = N_NEW(n_nodes, rdata);
43  GD_neato_nlist(g) = N_NEW(n_nodes + 1, node_t *);
44  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
45  neato_init_node(n);
46  ND_alg(n) = alg + i;
47  GD_neato_nlist(g)[i++] = n;
48  }
49  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
50  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
51  twopi_init_edge(e);
52  }
53  }
54 }
55 
56 static void scaleGraph (graph_t * g, node_t* root, pointf sc)
57 {
58  pointf ctr;
59  node_t* n;
60 
61  ctr.x = ND_pos(root)[0];
62  ctr.y = ND_pos(root)[1];
63 
64  for (n = agfstnode(g); n; n = agnxtnode (g, n)) {
65  if (n == root) continue;
66  ND_pos(n)[0] = sc.x*(ND_pos(n)[0] - ctr.x) + ctr.x;
67  ND_pos(n)[1] = sc.y*(ND_pos(n)[1] - ctr.y) + ctr.y;
68  }
69 }
70 
72 {
73  setEdgeType (g, ET_LINE);
74  /* GD_ndim(g) = late_int(g,agfindgraphattr(g,"dim"),2,2); */
75  Ndim = GD_ndim(g)=2; /* The algorithm only makes sense in 2D */
76  twopi_init_node_edge(g);
77 }
78 
79 /* twopi_layout:
80  */
82 {
83  Agnode_t *ctr = 0;
84  char *s;
85  int setRoot = 0;
86  pointf sc;
87  int doScale = 0;
88  int r;
89 
90  if (agnnodes(g) == 0) return;
91 
93  s = agget(g, "root");
94  if ((s = agget(g, "root"))) {
95  if (*s) {
96  ctr = agfindnode(g, s);
97  if (!ctr) {
98  agerr(AGWARN, "specified root node \"%s\" was not found.", s);
99  agerr(AGPREV, "Using default calculation for root node\n");
100  setRoot = 1;
101  }
102  }
103  else {
104  setRoot = 1;
105  }
106  }
107 
108  if ((s = agget(g, "scale")) && *s) {
109  if ((r = sscanf (s, "%lf,%lf",&sc.x,&sc.y))) {
110  if (r == 1) sc.y = sc.x;
111  doScale = 1;
112  if (Verbose)
113  fprintf (stderr, "scale = (%f,%f)\n", sc.x, sc.y);
114  }
115  }
116 
117  if (agnnodes(g)) {
118  Agraph_t **ccs;
119  Agraph_t *sg;
120  Agnode_t *c = NULL;
121  Agnode_t *n;
122  int ncc;
123  int i;
124 
125  ccs = ccomps(g, &ncc, 0);
126  if (ncc == 1) {
127  c = circleLayout(g, ctr);
128  if (setRoot && !ctr)
129  ctr = c;
130  n = agfstnode(g);
131  free(ND_alg(n));
132  ND_alg(n) = NULL;
133  if (doScale)
134  scaleGraph (g, c, sc);
135  adjustNodes(g);
136  spline_edges(g);
137  } else {
138  pack_info pinfo;
139  getPackInfo (g, l_node, CL_OFFSET, &pinfo);
140  pinfo.doSplines = 0;
141 
142  for (i = 0; i < ncc; i++) {
143  sg = ccs[i];
144  if (ctr && agcontains(sg, ctr))
145  c = ctr;
146  else
147  c = 0;
148  nodeInduce(sg);
149  c = circleLayout(sg, c);
150  if (setRoot && !ctr)
151  ctr = c;
152  if (doScale)
153  scaleGraph (sg, c, sc);
154  adjustNodes(sg);
155  }
156  n = agfstnode(g);
157  free(ND_alg(n));
158  ND_alg(n) = NULL;
159  packSubgraphs(ncc, ccs, g, &pinfo);
160  spline_edges(g);
161  }
162  for (i = 0; i < ncc; i++) {
163  agdelete(g, ccs[i]);
164  }
165  free(ccs);
166  }
167  if (setRoot)
168  agset (g, "root", agnameof (ctr));
170 
171 }
172 
173 static void twopi_cleanup_graph(graph_t * g)
174 {
175  free(GD_neato_nlist(g));
176  if (g != agroot(g))
177 #ifndef WITH_CGRAPH
178  memset(&(g->u), 0, sizeof(Agraphinfo_t));
179 #else /* WITH_CGRAPH */
180  agclean(g,AGRAPH,"Agraphinfo_t");
181 #endif /* WITH_CGRAPH */
182 }
183 
184 /* twopi_cleanup:
185  * The ND_alg data used by twopi is freed in twopi_layout
186  * before edge routing as edge routing may use this field.
187  */
189 {
190  node_t *n;
191  edge_t *e;
192 
193  n = agfstnode (g);
194  if (!n) return; /* empty graph */
195  /* free (ND_alg(n)); */
196  for (; n; n = agnxtnode(g, n)) {
197  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
198  gv_cleanup_edge(e);
199  }
200  gv_cleanup_node(n);
201  }
202  twopi_cleanup_graph(g);
203 }