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.
5
========================
7
void xxx_layout(Agraph_t * g)
10
- If the algorithm will use the common edge routing code, it should
11
call setEdgeType (g, ...);
13
- For each node, call common_init_node and gv_nodesize.
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().
20
- For each edge, call common_init_edge
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.
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.)
35
To add edges, there are 3 functions available:
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().
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.
64
ccs = ccomps(g, &ncc, 0);
66
/* layout nodes of g */
67
adjustNodes(g); /* if you need to remove overlaps */
68
spline_edges(g); /* generic edge routing code */
72
pack_mode pmode = getPackMode(g, l_node);
74
for (i = 0; i < ncc; i++) {
77
adjustNodes(sg); /* if you need to remove overlaps */
79
spline_edges(g); /* generic edge routing */
81
/* initialize packing info, e.g. */
82
pinfo.margin = getPack(g, CL_OFFSET, CL_OFFSET);
86
packSubgraphs(ncc, ccs, g, &pinfo);
88
for (i = 0; i < ncc; i++) {
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).
99
It good to check for trivial cases where the graph has 0 or 1 nodes,
102
At the end of xxx_layout, call
104
dotneato_postprocess(g);
106
The following template will work in most cases, ignoring the problems of
107
handling disconnected graphs and removing node overlaps:
110
xxx_init_node(node_t * n)
113
/* add algorithm-specific data, if desired */
117
xxx_init_edge(edge_t * e)
120
/* add algorithm-specific data, if desired */
124
xxx_init_node_edge(graph_t * g)
129
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
132
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
133
for (e = agfstout(g, n); e; e = agnxtout(g, e)){
140
xxx_layout (Agraph_t* g)
142
xxx_init_node_edge(g);
143
/* Set ND_pos(n) for each node n */
145
dotneato_postprocess(g);
148
======================
150
void xxx_cleanup(Agraph_t * g)
152
Free up any resources allocated in the layout.
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
160
if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
162
This is necessary for the graph to be laid out again, as the layout
163
code assumes this structure is clean.
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.
168
The following template will work in most cases:
170
static void xxx_cleanup_graph(Agraph_t * g)
172
/* Free any algorithm-specific data attached to the graph */
173
if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
176
static void xxx_cleanup_edge (Agedge_t* e)
178
/* Free any algorithm-specific data attached to the edge */
182
static void xxx_cleanup_node (Agnode_t* n)
184
/* Free any algorithm-specific data attached to the node */
188
void xxx_cleanup(Agraph_t * g)
193
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
194
for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
199
xxx_cleanup_graph(g);
204
Most layouts use auxiliary routines similar to neato, so
205
the entry points can be added in plugin/neato_layout
207
Add to gvlayout_neato_layout.c:
209
gvlayout_engine_t xxxgen_engine = {
216
{LAYOUT_XXX, "xxx", 0, &xxxgen_engine, &neatogen_features},
218
to gvlayout_neato_types and a new emum
222
to layout_type in that file.
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.
228
To do this, after writing xxx_layout and xxx_cleanup, it is necessary to:
230
- add the types and data structures
232
typedef enum { LAYOUT_XXX } layout_type;
234
static gvlayout_features_t xxxgen_features = {
237
gvlayout_engine_t xxxgen_engine = {
241
static gvplugin_installed_t gvlayout_xxx_types[] = {
242
{LAYOUT_XXX, "xxx", 0, &xxxgen_engine, &xxxgen_features},
243
{0, NULL, 0, NULL, NULL}
245
static gvplugin_api_t apis[] = {
246
{API_layout, &gvlayout_xxx_types},
249
gvplugin_library_t gvplugin_xxx_layout_LTX_library = { "xxx_layout", apis };
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.
258
to regenerate the config file.
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.
271
Changes need to be made to any applications, such as gvedit, that
272
statically know about layout algorithms.
276
Software configuration - automake
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
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.
294
This also assumes you have a good version of the various automake tools