]> granicus.if.org Git - graphviz/commitdiff
Update libguide to reflect plug-in architecture
authorerg <devnull@localhost>
Thu, 24 Aug 2006 21:27:52 +0000 (21:27 +0000)
committererg <devnull@localhost>
Thu, 24 Aug 2006 21:27:52 +0000 (21:27 +0000)
doc/libguide/samples.tex
doc/libguide/types.tex
doc/libguide/unconnect.tex

index a50c1e32cecf59b63a74fa53d5382e1bb3212f75..da4e7fcc27243d053c96e9dfb2dcf438bc199326 100644 (file)
@@ -1,43 +1,39 @@
 \section{A sample program: {\tt simple.c}}
 \label{sec:simple}
-This following code illustrates an application which only uses \gviz\ to
-position a graph. The application will either provide its own
-rendering, perhaps in an interactive setting, or, as in this
-case, it does not render the graph at all.
+This following code illustrates an application which uses \gviz\ to
+position a graph using the \dot\ layout and then write the output
+using the {\tt plain} format.
+An application can replace the call to {\tt gvRender} with its own
+function for rendering the graph, using the layout information
+encoded in the graph structure (cf. Section~\ref{sec:layout_info}).
 \pagebreak[4]
 \begin{verbatim}
-#include <dotneato.h>
+#include <gvc.h>
 
-int main(int argc, char** argv)
+int main(int argc, char **argv)
 {
-    Agraph_t* g;
-    Agnode_t* n;
-    FILE*     fp;
-    char      buf[BUFSIZ];
-    point     p;
+    GVC_t *gvc; 
+    graph_t *g;
+    FILE *fp;
 
-    aginit ();
+    gvc = gvContext();
 
     if (argc > 1)
-        fp = fopen (argv[1],"r");
-    else
+        fp = fopen(argv[1], "r");
+    else    
         fp = stdin;
-    g = agread (fp);
+    g = agread(fp);
 
-    dot_layout(g);
-    
-    agnodeattr(g, "pos", "");
-    for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-        p = ND_coord_i(n);
-        sprintf(buf,"%d,%d", p.x, p.y);
-        agset(n,"pos",buf);
-        printf ("node %s at position (%s)\n", n->name, buf);
-    }
-    agwrite(g, stdout);
+    gvLayout(gvc, g, "dot");
 
-    dot_cleanup(g);
-    return 0;
-}      
+    gvRender(gvc, g, "plain", stdout);
+
+    gvFreeLayout(gvc, g);
+
+    agclose(g);
+
+    return (gvFreeContext(gvc));
+}
 \end{verbatim}
 
 \section{A sample program: {\tt dot.c}}
@@ -49,37 +45,29 @@ is precisely how the \dot\ program is written, ignoring some signal
 handling, its specific declaration of 
 the {\tt Info} data (cf. Section~\ref{sec:info}), and a few other
 minor details.
-If someone desired to write a new layout algorithm, this
-code could be copied directly, merely changing the algorithm-specific 
-layout and cleanup functions \verb+dot_layout+ and \verb+dot_cleanup+.
-A more detailed and realistic example is provided in Appendix~\ref{sec:demo}.
-
 \begin{verbatim}
-#include <dotneato.h>
-
-int main(int argc, char** argv)
-{
-    Agraph_t *g, *prev=NULL;
+#include <gvc.h>
+    
+int main(int argc, char **argv)
+{   
+    graph_t *g, *prev = NULL;
     GVC_t *gvc;
 
     gvc = gvContext();
-
-    dotneato_initialize(gvc,argc,argv);
-    while ((g = next_input_graph())) {
+    gvParseArgs(gvc, argc, argv);
+    
+    while ((g = gvNextInputGraph(gvc))) {
         if (prev) {
-            dot_cleanup(prev);
+            gvFreeLayout(gvc, prev);
             agclose(prev);
         }
+        gvLayoutJobs(gvc, g); 
+        gvRenderJobs(gvc, g);
         prev = g;
-
-        gvBindContext(gvc, g);
-
-        dot_layout(g);
-        dotneato_write(gvc);
     }
-    dotneato_terminate(gvc);
-    return 0;
+    return (gvFreeContext(gvc));
 }
+
 \end{verbatim}
 
 \section{A sample program: {\tt demo.c}}
@@ -88,52 +76,44 @@ This example provides a modification of the previous example. Again it
 relies on the \gviz\ renderers, but now it creates the graph dynamically
 rather than reading the graph from a file.   
 \begin{verbatim}
-#include <dotneato.h>
+#include <gvc.h>
 
-int main(int argc, char** argv)
+int main(int argc, char **argv)
 {
     Agraph_t *g;
-    Agnode_t *n,*m;
+    Agnode_t *n, *m;
     Agedge_t *e;
-    Agsym_t  *a;
-    GVC_t    *gvc;
+    Agsym_t *a;
+    GVC_t *gvc;
 
-    /* set up renderer context */
+    /* set up a graphviz context */
     gvc = gvContext();
 
-    /* Accept -T and -o options like dot.
-     * Input files are ignored in this demo. */
-    dotneato_initialize(gvc, argc, argv);
+    /* parse command line args - minimally argv[0] sets layout engine */
+    gvParseArgs(gvc, argc, argv);
 
     /* Create a simple digraph */
-    g = agopen("g",AGDIGRAPH);
-    n = agnode(g,"n");
-    m = agnode(g,"m");
-    e = agedge(g,n,m);
+    g = agopen("g", AGDIGRAPH);
+    n = agnode(g, "n");
+    m = agnode(g, "m");
+    e = agedge(g, n, m);
 
     /* Set an attribute - in this case one that affects the visible rendering */
-    if (!(a = agfindattr(g->proto->n, "color")))
-        a = agnodeattr(g, "color", "");
-    agxset(n, a->index, "red");
-
-    /* bind graph to GV context - currently must be done before layout */
-    gvBindContext(gvc,g);
+    agsafeset(n, "color", "red", "");
 
-    /* Compute a layout */
-    neato_layout(g);
+    /* Compute a layout using layout engine from command line args */
+    gvLayoutJobs(gvc, g);
 
     /* Write the graph according to -T and -o options */
-    dotneato_write(gvc);
+    gvRenderJobs(gvc, g);
 
-    /* Clean out layout data */
-    neato_cleanup(g);
+    /* Free layout data */
+    gvFreeLayout(gvc, g);
 
     /* Free graph structures */
     agclose(g);
 
-    /* Clean up output file and errors */
-    dotneato_terminate(gvc);
-
-    return 0;
-}    
+    /* close output file, free context, and return number of errors */
+    return (gvFreeContext(gvc));
+}
 \end{verbatim}
index 21e7ac30b70f80e4dbc753b4a619eb04854a1339..b30f8fe3a6e093dd783f9f40eabe64d46b04a274 100644 (file)
@@ -1,5 +1,24 @@
-\section{String representations of types}
+\section{Some basic types and their string representations}
 \label{sec:types}
+A {\tt point} type is the structure
+\begin{verbatim}
+struct {
+  int x, y;
+}
+\end{verbatim}
+The fields can either give an absolute position or represent a
+vector displacement.
+A {\tt pointf} type is the same, with {\tt int} replaced with {\tt double}.
+A {\tt box} type is the structure
+\begin{verbatim}
+struct {
+  point LL, UR;
+}
+\end{verbatim}
+representing a rectangle. The {\tt LL} gives the coordinates of the
+lower-left corner, while the {\tt UR} is the upper-right corner.
+A {\tt boxf} type is the same, with {\tt point} replaced with {\tt pointf}.
+
 The following gives the accepted string representations 
 corresponding to values of the given types. 
 Whitespace is ignored when converting these values from strings
index bbe13758cbd818ea1897ffb73fc831732a4d3c6c..f475499b92a4824cc7dc672a747577808f2c5ce6 100644 (file)
@@ -5,7 +5,7 @@ Each is then extended to handle the not uncommon case of having
 multiple components. Most of the time, the obvious approach is used:
 draw each component separately and then assemble the drawings into a single
 layout. The only place this is not done is in \neato\ when the mode is
-{\tt MODE\_KK} and {\tt pack} is false (cf. Section~\ref{sec:neato}).
+{\tt "KK"} and {\tt pack="false"} (cf. Section~\ref{sec:neato}).
 
 For the \dot\ algorithm, its layered drawings make the merging simple:
 the nodes on the highest rank of each component are all put
@@ -17,47 +17,34 @@ with unconnected graphs, especially by supplying a technique for
 packing arbitrary graph drawings together quickly, aesthetically and
 with efficient use of space. The following code indicates how the
 library can be integrated with the 
-basic algorithm (cf. Section~\ref{sec:twopi}).
+basic layout algorithms given an input graph {\tt g} and a \gvc\ value
+{\tt gvc}.
 
 \begin{verbatim}
-    Agnode_t*  c = NULL;
-    Agraph_t** ccs;       /* array of connected components */
-    Agraph_t*  sg;
-    Agnode_t*  c = NULL;
-    int        ncc;       /* number of connected components */
-    int        i;
+    graph_t *sg;
+    FILE *fp;
+    graph_t** cc;
+    int       i, ncc;
 
-    ccs = ccomps (g, &ncc, (char*)0);
-    if (ncc == 1) {
-      circleLayout (g,ctr);
-      adjustNodes (g);
-      spline_edges(g);
-    }
-    else {
-      pack_info pinfo;
-      pack_mode pmode = getPackMode (g,l_node);
+    cc = ccomps(g, &ncc, (char*)0);
 
-      for (i = 0; i < ncc; i++) {
-        sg = ccs[i];
-        if (ctr && agcontains (sg, ctr)) c = ctr;
-        else c = 0;
+    for (i = 0; i < ncc; i++) {
+           sg = cc[i];
         nodeInduce (sg);
-        circleLayout (sg,c);
-        adjustNodes (sg);
-      }
-      spline_edges(g);
-      pinfo.margin = getPack (g, CL_OFFSET, CL_OFFSET);
-      pinfo.doSplines = 1;
-      pinfo.mode = pmode;
-      pinfo.fixed = 0;
-      packSubgraphs (ncc, ccs, g, &pinfo);
+        gvLayout(gvc, sg, "neato");
     }
+    pack_graph (ncc, cc, g, 0);
+
+    gvRender(gvc, g, "ps", stdout);
+
     for (i = 0; i < ncc; i++) {
-      agdelete (g, ccs[i]);
+        sg = cc[i];
+        gvFreeLayout(gvc, sg);
+        agdelete(g, sg);
     }
 \end{verbatim}
 
-The call to {\tt ccomps} splits the graph into its connected
+The call to {\tt ccomps} splits the graph {\tt g} into its connected
 components. {\tt ncc} is set to the number of components. 
 The components are represented by subgraphs of the input graph, and are
 stored in the returned array. The function gives names to the components
@@ -78,48 +65,30 @@ to to true if the graph has nodes with fixed positions. In this case,
 the component containing these nodes is the first one in the returned array.
 
 Continuing with the example,
-if there is only one component, we can revert to the base implementation
-for simplicity. If there are multiple components, 
-we take one at a time, using {\tt nodeInduce} to create the 
-corresponding node-induced subgraph, laying out the component with
-{\tt circleLayout}, and removing node overlaps, if necessary, by
-calling {\tt adjustNodes}. As a technical point, if a center node
-is provided, it is only used with the component containing it. A
-better implementation would allow a center node to be specified on
-a per component basis.
-
-After the nodes of each component are positioned, with coordinates
-stored in the attributes {\tt pos[0]} and {\tt pos[1]}, the code
-calls {\tt spline\_edges} to generate the edge representations. 
-
-Next, it uses the \pack\ function {\tt packSubgraphs} to reassemble
+we take one component at a time, use {\tt nodeInduce} to create the 
+corresponding node-induced subgraph, and then lay out the component
+with {\tt gvLayout}. Here, we use \neato\ for each layout, but it
+is possible to use a different layout for each component.\footnote{
+At present, the \dot\ layout has a limitation that it only works on
+a root graph. Thus, to use \dot\ for a component, one needs to create
+a new copy of the subgraph, apply \dot\, and then copy the position
+attributes back to the component.}
+
+Next, we use the \pack\ function {\tt pack\_graph} to reassemble
 the graph into a single drawing. To position the components, \pack\
 uses the polyomino-based approach described by
 Freivalds et al\cite{pack}. The first three arguments to the
-function are clear. The fourth argument sets various parameters
-used in the packing. The {\tt pinfo.margin} field specifies the
-margin, in points, maintained between components. The value
-{\tt CL\_OFFSET} is defined by \gviz; it is the same amount of
-space used by \dot\ around clusters. Here, we employ the auxiliary
-function {\tt getPack}. This uses the graph attribute {\tt "pack"} to
-determine this value, which can take boolean and integer values.
-If the attribute evaluates to a non-negative integer, this value is
-returned. If the attribute evaluates to true, the third argument is
-returned. Otherwise, the function returns the second value.
-
-The {\tt pinfo.doSplines} field, if non-zero,
-tells the function that edge representations have already been
-computed for the graph and should be used in determining the packing.
-Otherwise, the packing will treat edges as line segments connecting
-the centers of the two endpoints.
+function are clear. The fourth argument indicates whether or not
+there are fixed components.
 
-The {\tt pinfo.mode} field specifies how the packing should be done. At
+The {\tt pack\_graph} function uses the graph's {\tt packmode}
+attribute to determine how the packing should be done. At
 present, packing uses the single algorithm mentioned above, but allows
-three varying granularities, represented by the values {\tt l\_node},
-{\tt l\_clust} and {\tt l\_graph}. In the first case, packing is done at
+three varying granularities, represented by the values {\tt "node"},
+{\tt "clust"} and {\tt "graph"}. In the first case, packing is done at
 the node and edge level. This provides the tightest packing, using the
 least area, but also allows a node of one component to lie between
-two nodes of another component. The second value, {\tt l\_clust}, 
+two nodes of another component. The second value, {\tt "clust"}, 
 requires that the packing treat top-level clusters with a set
 bounding box {\tt GD\_bb} value like a large node. Nodes and edges not
 entirely contained within a cluster are handled as in the previous
@@ -129,26 +98,9 @@ last case does the packing at the graph granularity. Each component
 is treated as one large node, whose size is determined by its
 bounding box.
 
-In our example, we use another library function, {\tt getPackMode},
-to set the mode value. This function uses the graph's {\tt "packmode"}
-attribute to determine the value. If this is {\tt "node"},
-{\tt "cluster"} or {\tt "graph"}, the function returns
-{\tt l\_node}, {\tt l\_clust} and {\tt l\_graph}, respectively. 
-Otherwise, the function returns its second argument.
-
-The last field, {\tt pinfo.fixed}, is used to constrain the placement
-of certain components. If non-NULL, this field should point to an
-array of {\tt ncc} booleans, where {\tt pinfo.fixed[i]} is true if
-component {\tt i} should be left at its current position. If the
-application specifies fixed components, these are placed first. Then
-the remaining components are packed into the unoccupied space, respecting
-the {\tt pinfo.mode} field. It is the application's responsibility to
-make sure that the fixed components do not overlap each other, if that
-is desired.
-
 Note that the library automatically computes the bounding box of
 each of the components. Also,
-as a side-effect, {\tt packSubgraphs} finishes by recomputing and
+as a side-effect, {\tt pack\_graph} finishes by recomputing and
 setting the bounding box attribute {\tt GD\_bb} of the graph.
 
 The final step is to free the component subgraphs.