diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolboxes/graph_visualisation/share/graphviz/doc/addingLayout.txt	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,297 @@
+To create a new layout plugin called xxx, you first need
+to provide two functions: xxx_layout and xxx_cleanup. The
+semantics of these are described below.
+
+========================
+
+  void xxx_layout(Agraph_t * g)
+
+    Initialize the graph.
+       - If the algorithm will use the common edge routing code, it should
+    call setEdgeType (g, ...);
+
+       - For each node, call common_init_node and gv_nodesize.
+
+         If the algorithm will use spline_edges() to route the edges, the
+    node coordinates need to be stored in ND_pos, so this should be
+    allocated here. This, and the two calls mentioned above, are all
+    handled by a call to neato_init_node().
+
+       - For each edge, call common_init_edge
+
+       - The algorithm should allocate whatever other data structures it
+    needs. This can involve fields in the A*info_t fields. In addition,
+    each of these fields contains a void* alg; subfield that the algorithm
+    can use the store additional data. 
+         Once we move to cgraph, this will all be replace with 
+    algorithm specific records.
+
+    Layout the graph. When finished, each node should have its coordinates
+  stored in points in ND_coord_i(n), each edge should have its layout
+  described in ED_spl(e). 
+  (N.B. As of version 2.21, ND_coord_i has been replaced by ND_coord,
+  which are now floating point coordinates.)
+
+    To add edges, there are 3 functions available:
+
+      - spline_edges1 (Agraph_t*, int edgeType)
+          Assumes the node coordinates are stored in ND_coord_i, and that
+        GD_bb is set. For each edge, this function constructs the appropriate 
+        data and stores it in ED_spl.
+      - spline_edges0 (Agraph_t*)
+          Assumes the node coordinates are stored in ND_pos, and that
+        GD_bb is set. This function uses the ratio attribute if set, 
+        copies the values in ND_pos to ND_coord_i (converting from 
+        inches to points); and calls spline_edges1 using the edge type
+        specified by setEdgeType().
+      - spline_edges (Agraph_t*)
+          Assumes the node coordinates are stored in ND_pos. This
+        function calculates the bounding box of g and stores it in GD_bb,
+        then calls spline_edges0().
+
+    If the algorithm only works with connected components, the code can
+  use the pack library to get components, lay them out individually, and
+  pack them together based on user specifications. A typical schema is
+  given below. One can look at the code for twopi, circo, neato or fdp
+  for more detailed examples.
+
+        Agraph_t **ccs;
+        Agraph_t *sg;
+        Agnode_t *c = NULL;
+        int ncc;
+        int i;
+
+        ccs = ccomps(g, &ncc, 0);
+        if (ncc == 1) {
+            /* layout nodes of g */
+            adjustNodes(g);  /* if you need to remove overlaps */
+            spline_edges(g); /* generic edge routing code */
+
+        } else {
+            pack_info pinfo;
+            pack_mode pmode = getPackMode(g, l_node);
+
+            for (i = 0; i < ncc; i++) {
+                sg = ccs[i];
+                /* layout sg */
+                adjustNodes(sg);  /* if you need to remove overlaps */
+            }
+            spline_edges(g);  /* generic edge routing */
+
+            /* initialize packing info, e.g. */
+            pinfo.margin = getPack(g, CL_OFFSET, CL_OFFSET);
+            pinfo.doSplines = 1;
+            pinfo.mode = pmode;
+            pinfo.fixed = 0;
+            packSubgraphs(ncc, ccs, g, &pinfo);
+        }
+        for (i = 0; i < ncc; i++) {
+            agdelete(g, ccs[i]);
+        }
+
+        free(ccs);
+
+    Be careful in laying of subgraphs if you rely on attributes that have
+  only been set in the root graph. With connected components, edges can
+  be added with each component, before packing (as above) or after the
+  components have been packed (see circo).
+
+    It good to check for trivial cases where the graph has 0 or 1 nodes,
+  or no edges.
+
+    At the end of xxx_layout, call
+
+       dotneato_postprocess(g);
+
+  The following template will work in most cases, ignoring the problems of
+  handling disconnected graphs and removing node overlaps:
+
+  static void
+  xxx_init_node(node_t * n)
+  {
+    neato_init_node(n);
+    /* add algorithm-specific data, if desired */
+  }
+
+  static void
+  xxx_init_edge(edge_t * e)
+  {
+    common_init_edge(e);
+    /* add algorithm-specific data, if desired */
+  }
+
+  static void
+  xxx_init_node_edge(graph_t * g)
+  {
+    node_t *n;
+    edge_t *e;
+
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+        xxx_init_node(n);
+    }
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+        for (e = agfstout(g, n); e; e = agnxtout(g, e)){          
+            xxx_init_edge(e);
+        }
+    }
+  }
+
+  void
+  xxx_layout (Agraph_t* g)
+  {
+    xxx_init_node_edge(g);
+    /* Set ND_pos(n) for each node n */
+    spline_edges(g);
+    dotneato_postprocess(g);
+  }  
+
+======================
+
+  void xxx_cleanup(Agraph_t * g)
+
+    Free up any resources allocated in the layout.
+
+    Finish with calls to gv_cleanup_node and gv_cleanup_edge for
+  each node and edge. This cleans up splines labels, ND_pos, shapes
+  and 0's out the A*info_t, so these have to occur last, but could be
+  part of explicit xxx_cleanup_node and xxx_cleanup_edge, if desired.
+    At the end, you should do
+
+  if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
+
+  This is necessary for the graph to be laid out again, as the layout
+  code assumes this structure is clean.
+
+  libgvc does a final cleanup to the root graph, freeing any drawing,
+  freeing its label, and zeroing out Agraphinfo_t of the root graph.
+
+  The following template will work in most cases:
+
+  static void xxx_cleanup_graph(Agraph_t * g)
+  {
+    /* Free any algorithm-specific data attached to the graph */
+    if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
+  }
+
+  static void xxx_cleanup_edge (Agedge_t* e)
+  {
+    /* Free any algorithm-specific data attached to the edge */
+    gv_cleanup_edge(e);
+  }
+
+  static void xxx_cleanup_node (Agnode_t* n)
+  {
+    /* Free any algorithm-specific data attached to the node */
+    gv_cleanup_node(e);
+  }
+
+  void xxx_cleanup(Agraph_t * g)
+  {
+    Agnode_t *n;
+    Agedge_t *e;
+
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+        for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+            xxx_cleanup_edge(e);
+        }
+        xxx_cleanup_node(n);
+    }
+    xxx_cleanup_graph(g);
+  }   
+
+==================
+
+Most layouts use auxiliary routines similar to neato, so
+the entry points can be added in plugin/neato_layout
+
+Add to gvlayout_neato_layout.c:
+
+gvlayout_engine_t xxxgen_engine = {
+    xxx_layout,
+    xxx_cleanup,
+};
+
+and the line
+
+    {LAYOUT_XXX, "xxx", 0, &xxxgen_engine, &neatogen_features},
+
+to gvlayout_neato_types and a new emum
+
+    LAYOUT_XXX
+
+to layout_type in that file.
+
+The above allows the new layout to piggyback on top of the neato
+plugin, but requires rebuilding the plugin. In general, a user
+can (and probably should) build a layout plugin totally separately. 
+
+To do this, after writing xxx_layout and xxx_cleanup, it is necessary to:
+
+  - add the types and data structures
+
+typedef enum { LAYOUT_XXX } layout_type;
+
+static gvlayout_features_t xxxgen_features = {
+    0
+};
+gvlayout_engine_t xxxgen_engine = {
+    xxx_layout,
+    xxx_cleanup,
+};
+static gvplugin_installed_t gvlayout_xxx_types[] = {
+    {LAYOUT_XXX, "xxx", 0, &xxxgen_engine, &xxxgen_features},
+    {0, NULL, 0, NULL, NULL}
+};
+static gvplugin_api_t apis[] = {
+    {API_layout, &gvlayout_xxx_types},
+    {(api_t)0, 0},
+};
+gvplugin_library_t gvplugin_xxx_layout_LTX_library = { "xxx_layout", apis };
+
+  - combine all of this into a dynamic library whose name contains the 
+  string "gvplugin_" and install the library in the same directory as the 
+  other Graphviz plugins. For example, on Linux systems, the dot layout 
+  plugin is in the library libgvplugin_dot_layout.so.
+
+  - run
+      dot -c
+  to regenerate the config file.
+
+NOTES:
+  - Additional layouts can be added as extra lines in gvlayout_xxx_types.
+  - Obviously, most of the names and strings can be arbitrary. One
+  constraint is that external identifier for the gvplugin_library_t
+  type must end in "_LTX_library". In addition, the string "xxx" in
+  each entry of gvlayout_xxx_types is the name used to identify the
+  layout algorithm, so needs to be distinct from any other layout name.
+  - The features of a layout algorithm are currently limited to a 
+  flag of bits, and the only flag supported is LAYOUT_USES_RANKDIR,
+  which enables the layout to the rankdir attribute.
+
+Changes need to be made to any applications, such as gvedit, that
+statically know about layout algorithms.
+
+==================
+
+Software configuration - automake
+
+If you want to integrate your code into the Graphviz software
+and use its build system, follow the instructions below. 
+You can certainly build and install your plugin using your own
+build software.
+
+0. Put your software in lib/xxxgen, and added the hooks describe above
+into gvlayout_neato_layout.c
+1. In lib/xxxgen, provide a Makefile.am (based on a simple example
+like lib/fdpgen/Makefile.am)
+3. In lib/Makefile.am, add xxxgen to SUBDIRS
+2. In configure.ac, add lib/xxxgen/Makefile to AC_CONFIG_FILES.
+4. In lib/plugin/neato_layout/Makefile.am, insert
+	$(top_builddir)/lib/xxxgen/libxxxgen_C.la 
+	in libgvplugin_neato_layout_C_la_LIBADD
+5. Remember to run autogen.sh because on its own configure can guess wrong.
+
+This also assumes you have a good version of the various automake tools
+on your system.
+
+