comparison toolboxes/graph_visualisation/share/graphviz/doc/addingLayout.txt @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e9a9cd732c1e
1 To create a new layout plugin called xxx, you first need
2 to provide two functions: xxx_layout and xxx_cleanup. The
3 semantics of these are described below.
4
5 ========================
6
7 void xxx_layout(Agraph_t * g)
8
9 Initialize the graph.
10 - If the algorithm will use the common edge routing code, it should
11 call setEdgeType (g, ...);
12
13 - For each node, call common_init_node and gv_nodesize.
14
15 If the algorithm will use spline_edges() to route the edges, the
16 node coordinates need to be stored in ND_pos, so this should be
17 allocated here. This, and the two calls mentioned above, are all
18 handled by a call to neato_init_node().
19
20 - For each edge, call common_init_edge
21
22 - The algorithm should allocate whatever other data structures it
23 needs. This can involve fields in the A*info_t fields. In addition,
24 each of these fields contains a void* alg; subfield that the algorithm
25 can use the store additional data.
26 Once we move to cgraph, this will all be replace with
27 algorithm specific records.
28
29 Layout the graph. When finished, each node should have its coordinates
30 stored in points in ND_coord_i(n), each edge should have its layout
31 described in ED_spl(e).
32 (N.B. As of version 2.21, ND_coord_i has been replaced by ND_coord,
33 which are now floating point coordinates.)
34
35 To add edges, there are 3 functions available:
36
37 - spline_edges1 (Agraph_t*, int edgeType)
38 Assumes the node coordinates are stored in ND_coord_i, and that
39 GD_bb is set. For each edge, this function constructs the appropriate
40 data and stores it in ED_spl.
41 - spline_edges0 (Agraph_t*)
42 Assumes the node coordinates are stored in ND_pos, and that
43 GD_bb is set. This function uses the ratio attribute if set,
44 copies the values in ND_pos to ND_coord_i (converting from
45 inches to points); and calls spline_edges1 using the edge type
46 specified by setEdgeType().
47 - spline_edges (Agraph_t*)
48 Assumes the node coordinates are stored in ND_pos. This
49 function calculates the bounding box of g and stores it in GD_bb,
50 then calls spline_edges0().
51
52 If the algorithm only works with connected components, the code can
53 use the pack library to get components, lay them out individually, and
54 pack them together based on user specifications. A typical schema is
55 given below. One can look at the code for twopi, circo, neato or fdp
56 for more detailed examples.
57
58 Agraph_t **ccs;
59 Agraph_t *sg;
60 Agnode_t *c = NULL;
61 int ncc;
62 int i;
63
64 ccs = ccomps(g, &ncc, 0);
65 if (ncc == 1) {
66 /* layout nodes of g */
67 adjustNodes(g); /* if you need to remove overlaps */
68 spline_edges(g); /* generic edge routing code */
69
70 } else {
71 pack_info pinfo;
72 pack_mode pmode = getPackMode(g, l_node);
73
74 for (i = 0; i < ncc; i++) {
75 sg = ccs[i];
76 /* layout sg */
77 adjustNodes(sg); /* if you need to remove overlaps */
78 }
79 spline_edges(g); /* generic edge routing */
80
81 /* initialize packing info, e.g. */
82 pinfo.margin = getPack(g, CL_OFFSET, CL_OFFSET);
83 pinfo.doSplines = 1;
84 pinfo.mode = pmode;
85 pinfo.fixed = 0;
86 packSubgraphs(ncc, ccs, g, &pinfo);
87 }
88 for (i = 0; i < ncc; i++) {
89 agdelete(g, ccs[i]);
90 }
91
92 free(ccs);
93
94 Be careful in laying of subgraphs if you rely on attributes that have
95 only been set in the root graph. With connected components, edges can
96 be added with each component, before packing (as above) or after the
97 components have been packed (see circo).
98
99 It good to check for trivial cases where the graph has 0 or 1 nodes,
100 or no edges.
101
102 At the end of xxx_layout, call
103
104 dotneato_postprocess(g);
105
106 The following template will work in most cases, ignoring the problems of
107 handling disconnected graphs and removing node overlaps:
108
109 static void
110 xxx_init_node(node_t * n)
111 {
112 neato_init_node(n);
113 /* add algorithm-specific data, if desired */
114 }
115
116 static void
117 xxx_init_edge(edge_t * e)
118 {
119 common_init_edge(e);
120 /* add algorithm-specific data, if desired */
121 }
122
123 static void
124 xxx_init_node_edge(graph_t * g)
125 {
126 node_t *n;
127 edge_t *e;
128
129 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
130 xxx_init_node(n);
131 }
132 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
133 for (e = agfstout(g, n); e; e = agnxtout(g, e)){
134 xxx_init_edge(e);
135 }
136 }
137 }
138
139 void
140 xxx_layout (Agraph_t* g)
141 {
142 xxx_init_node_edge(g);
143 /* Set ND_pos(n) for each node n */
144 spline_edges(g);
145 dotneato_postprocess(g);
146 }
147
148 ======================
149
150 void xxx_cleanup(Agraph_t * g)
151
152 Free up any resources allocated in the layout.
153
154 Finish with calls to gv_cleanup_node and gv_cleanup_edge for
155 each node and edge. This cleans up splines labels, ND_pos, shapes
156 and 0's out the A*info_t, so these have to occur last, but could be
157 part of explicit xxx_cleanup_node and xxx_cleanup_edge, if desired.
158 At the end, you should do
159
160 if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
161
162 This is necessary for the graph to be laid out again, as the layout
163 code assumes this structure is clean.
164
165 libgvc does a final cleanup to the root graph, freeing any drawing,
166 freeing its label, and zeroing out Agraphinfo_t of the root graph.
167
168 The following template will work in most cases:
169
170 static void xxx_cleanup_graph(Agraph_t * g)
171 {
172 /* Free any algorithm-specific data attached to the graph */
173 if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
174 }
175
176 static void xxx_cleanup_edge (Agedge_t* e)
177 {
178 /* Free any algorithm-specific data attached to the edge */
179 gv_cleanup_edge(e);
180 }
181
182 static void xxx_cleanup_node (Agnode_t* n)
183 {
184 /* Free any algorithm-specific data attached to the node */
185 gv_cleanup_node(e);
186 }
187
188 void xxx_cleanup(Agraph_t * g)
189 {
190 Agnode_t *n;
191 Agedge_t *e;
192
193 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
194 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
195 xxx_cleanup_edge(e);
196 }
197 xxx_cleanup_node(n);
198 }
199 xxx_cleanup_graph(g);
200 }
201
202 ==================
203
204 Most layouts use auxiliary routines similar to neato, so
205 the entry points can be added in plugin/neato_layout
206
207 Add to gvlayout_neato_layout.c:
208
209 gvlayout_engine_t xxxgen_engine = {
210 xxx_layout,
211 xxx_cleanup,
212 };
213
214 and the line
215
216 {LAYOUT_XXX, "xxx", 0, &xxxgen_engine, &neatogen_features},
217
218 to gvlayout_neato_types and a new emum
219
220 LAYOUT_XXX
221
222 to layout_type in that file.
223
224 The above allows the new layout to piggyback on top of the neato
225 plugin, but requires rebuilding the plugin. In general, a user
226 can (and probably should) build a layout plugin totally separately.
227
228 To do this, after writing xxx_layout and xxx_cleanup, it is necessary to:
229
230 - add the types and data structures
231
232 typedef enum { LAYOUT_XXX } layout_type;
233
234 static gvlayout_features_t xxxgen_features = {
235 0
236 };
237 gvlayout_engine_t xxxgen_engine = {
238 xxx_layout,
239 xxx_cleanup,
240 };
241 static gvplugin_installed_t gvlayout_xxx_types[] = {
242 {LAYOUT_XXX, "xxx", 0, &xxxgen_engine, &xxxgen_features},
243 {0, NULL, 0, NULL, NULL}
244 };
245 static gvplugin_api_t apis[] = {
246 {API_layout, &gvlayout_xxx_types},
247 {(api_t)0, 0},
248 };
249 gvplugin_library_t gvplugin_xxx_layout_LTX_library = { "xxx_layout", apis };
250
251 - combine all of this into a dynamic library whose name contains the
252 string "gvplugin_" and install the library in the same directory as the
253 other Graphviz plugins. For example, on Linux systems, the dot layout
254 plugin is in the library libgvplugin_dot_layout.so.
255
256 - run
257 dot -c
258 to regenerate the config file.
259
260 NOTES:
261 - Additional layouts can be added as extra lines in gvlayout_xxx_types.
262 - Obviously, most of the names and strings can be arbitrary. One
263 constraint is that external identifier for the gvplugin_library_t
264 type must end in "_LTX_library". In addition, the string "xxx" in
265 each entry of gvlayout_xxx_types is the name used to identify the
266 layout algorithm, so needs to be distinct from any other layout name.
267 - The features of a layout algorithm are currently limited to a
268 flag of bits, and the only flag supported is LAYOUT_USES_RANKDIR,
269 which enables the layout to the rankdir attribute.
270
271 Changes need to be made to any applications, such as gvedit, that
272 statically know about layout algorithms.
273
274 ==================
275
276 Software configuration - automake
277
278 If you want to integrate your code into the Graphviz software
279 and use its build system, follow the instructions below.
280 You can certainly build and install your plugin using your own
281 build software.
282
283 0. Put your software in lib/xxxgen, and added the hooks describe above
284 into gvlayout_neato_layout.c
285 1. In lib/xxxgen, provide a Makefile.am (based on a simple example
286 like lib/fdpgen/Makefile.am)
287 3. In lib/Makefile.am, add xxxgen to SUBDIRS
288 2. In configure.ac, add lib/xxxgen/Makefile to AC_CONFIG_FILES.
289 4. In lib/plugin/neato_layout/Makefile.am, insert
290 $(top_builddir)/lib/xxxgen/libxxxgen_C.la
291 in libgvplugin_neato_layout_C_la_LIBADD
292 5. Remember to run autogen.sh because on its own configure can guess wrong.
293
294 This also assumes you have a good version of the various automake tools
295 on your system.
296
297