~ubuntu-branches/ubuntu/precise/graphviz/precise-security

« back to all changes in this revision

Viewing changes to doc/addingLayout.txt

  • Committer: Bazaar Package Importer
  • Author(s): David Claughton
  • Date: 2010-03-24 22:45:18 UTC
  • mfrom: (1.2.7 upstream) (6.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100324224518-do441tthbqjaqjzd
Tags: 2.26.3-4
Add patch to fix segfault in circo. Backported from upstream snapshot
release.  Thanks to Francis Russell for his work on this.
(Closes: #575255)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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