Graphviz  2.31.20130525.0447
lib/circogen/circularinit.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 
00015 /*
00016  * Circular layout. Biconnected components are put on circles.
00017  * block-cutnode tree is done recursively, with children placed
00018  * about parent block.
00019  * Based on:
00020  *   Six and Tollis, "A Framework for Circular Drawings of
00021  * Networks", GD '99, LNCS 1731, pp. 107-116;
00022  *   Six and Tollis, "Circular Drawings of Biconnected Graphs",
00023  * Proc. ALENEX '99, pp 57-73.
00024  *   Kaufmann and Wiese, "Maintaining the Mental Map for Circular
00025  * Drawings", GD '02, LNCS 2528, pp. 12-22.
00026  */
00027 
00028 #include    "circular.h"
00029 #include    "adjust.h"
00030 #include    "pack.h"
00031 #include    "neatoprocs.h"
00032 #include    <string.h>
00033 
00034 static void circular_init_edge(edge_t * e)
00035 {
00036 #ifdef WITH_CGRAPH
00037     agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);   //node custom data
00038 #endif /* WITH_CGRAPH */
00039     common_init_edge(e);
00040 
00041     ED_factor(e) = late_double(e, E_weight, 1.0, 0.0);
00042 }
00043 
00044 
00045 static void circular_init_node_edge(graph_t * g)
00046 {
00047     node_t *n;
00048     edge_t *e;
00049     int i = 0;
00050     ndata* alg = N_NEW(agnnodes(g), ndata);
00051 
00052     GD_neato_nlist(g) = N_NEW(agnnodes(g) + 1, node_t *);
00053     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00054         neato_init_node(n);
00055         ND_alg(n) = alg + i;
00056         GD_neato_nlist(g)[i++] = n;
00057     }
00058     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00059         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00060             circular_init_edge(e);
00061         }
00062     }
00063 }
00064 
00065 
00066 void circo_init_graph(graph_t * g)
00067 {
00068     setEdgeType (g, ET_LINE);
00069     /* GD_ndim(g) = late_int(g,agfindattr(g,"dim"),2,2); */
00070     Ndim = GD_ndim(g) = 2;      /* The algorithm only makes sense in 2D */
00071     circular_init_node_edge(g);
00072 }
00073 
00074 /* makeDerivedNode:
00075  * Make a node in the derived graph, with the given name.
00076  * orig points to what it represents, either a real node or
00077  * a cluster. Copy size info from original node; needed for
00078  * adjustNodes and packSubgraphs.
00079  */
00080 static node_t *makeDerivedNode(graph_t * dg, char *name, int isNode,
00081                                void *orig)
00082 {
00083 #ifndef WITH_CGRAPH
00084     node_t *n = agnode(dg, name);
00085 #else /* WITH_CGRAPH */
00086     node_t *n = agnode(dg, name,1);
00087     agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);   //node custom data
00088 #endif /* WITH_CGRAPH */
00089     ND_alg(n) = (void *) NEW(cdata);
00090     if (isNode) {
00091         ND_pos(n) = N_NEW(Ndim, double);
00092         ND_lw(n) = ND_lw((node_t *) orig);
00093         ND_rw(n) = ND_rw((node_t *) orig);
00094         ND_ht(n) = ND_ht((node_t *) orig);
00095         ORIGN(n) = (node_t *) orig;
00096     } else
00097         ORIGG(n) = (graph_t *) orig;
00098     return n;
00099 }
00100 
00101 /* circomps:
00102  * Construct a strict, undirected graph with no loops from g.
00103  * Construct the connected components with the provision that all
00104  * nodes in a block subgraph are considered connected.
00105  * Return array of components with number of components in cnt.
00106  * Each component has its blocks as subgraphs.
00107  * FIX: Check that blocks are disjoint.
00108  */
00109 Agraph_t **circomps(Agraph_t * g, int *cnt)
00110 {
00111     int c_cnt;
00112     Agraph_t **ccs;
00113     Agraph_t *dg;
00114     Agnode_t *n, *v, *dt, *dh;
00115     Agedge_t *e;
00116     Agraph_t *sg;
00117     int i;
00118     Agedge_t *ep;
00119     Agnode_t *p;
00120 
00121 #ifndef WITH_CGRAPH
00122     dg = agopen("derived", AGFLAG_STRICT);
00123 #else /* WITH_CGRAPH */
00124     dg = agopen("derived", Agstrictundirected,NIL(Agdisc_t *));
00125 #endif /* WITH_CGRAPH */
00126     GD_alg(g) = dg;  /* store derived graph for closing later */
00127 
00128     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00129         if (DNODE(v))
00130             continue;
00131         n = makeDerivedNode(dg, agnameof(v), 1, v);
00132         DNODE(v) = n;
00133     }
00134 
00135     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00136         for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
00137             dt = DNODE(agtail(e));
00138             dh = DNODE(aghead(e));
00139             if (dt != dh) {
00140 #ifndef WITH_CGRAPH
00141                 agedge(dg, dt, dh);
00142 #else /* WITH_CGRAPH */
00143                 agbindrec(agedge(dg, dt, dh, NULL, 1), "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);     //node custom data
00144 #endif /* WITH_CGRAPH */
00145             }
00146         }
00147     }
00148 
00149     ccs = ccomps(dg, &c_cnt, 0);
00150 
00151     /* replace block nodes with block contents */
00152     for (i = 0; i < c_cnt; i++) {
00153         sg = ccs[i];
00154 
00155         /* add edges: since sg is a union of components, all edges
00156          * of any node should be added, except loops.
00157          */
00158         for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
00159             p = ORIGN(n);
00160             for (e = agfstout(g, p); e; e = agnxtout(g, e)) {
00161                 /* n = DNODE(agtail(e)); by construction since agtail(e) == p */
00162                 dh = DNODE(aghead(e));
00163                 if (n != dh) {
00164 #ifndef WITH_CGRAPH
00165                     ep = agedge(dg, n, dh);
00166                     aginsert(sg, ep);
00167 #else /* WITH_CGRAPH */
00168                     ep = agedge(dg, n, dh, NULL, 1);
00169                     agbindrec(ep, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);  //node custom data
00170                     agsubedge(sg,ep,1);
00171 #endif /* WITH_CGRAPH */
00172                 }
00173             }
00174         }
00175     }
00176 
00177     /* Finally, add edge data to edges */
00178     for (n = agfstnode(dg); n; n = agnxtnode(dg, n)) {
00179         for (e = agfstout(dg, n); e; e = agnxtout(dg, e)) {
00180             ED_alg(e) = NEW(edata);
00181         }
00182     }
00183 
00184     *cnt = c_cnt;
00185     return ccs;
00186 }
00187 
00188 /* closeDerivedGraph:
00189  */
00190 static void closeDerivedGraph(graph_t * g)
00191 {
00192     node_t *n;
00193     edge_t *e;
00194 
00195     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00196         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00197             free(ED_alg(e));
00198         }
00199         free(ND_alg(n));
00200         free(ND_pos(n));
00201     }
00202     agclose(g);
00203 }
00204 
00205 /* copyPosns:
00206  * Copy position of nodes in given subgraph of derived graph
00207  * to corresponding node in original graph.
00208  * FIX: consider assigning from n directly to ORIG(n).
00209  */
00210 static void copyPosns(graph_t * g)
00211 {
00212     node_t *n;
00213     node_t *v;
00214 
00215     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00216         v = ORIGN(n);
00217         ND_pos(v)[0] = ND_pos(n)[0];
00218         ND_pos(v)[1] = ND_pos(n)[1];
00219     }
00220 }
00221 
00222 /* circoLayout:
00223  */
00224 void circoLayout(Agraph_t * g)
00225 {
00226     Agraph_t **ccs;
00227     Agraph_t *sg;
00228     int ncc;
00229     int i;
00230 
00231     if (agnnodes(g)) {
00232         ccs = circomps(g, &ncc);
00233 
00234         if (ncc == 1) {
00235             circularLayout(ccs[0], g);
00236             copyPosns(ccs[0]);
00237             adjustNodes(g);
00238         } else {
00239             Agraph_t *dg = ccs[0]->root;
00240             pack_info pinfo;
00241             getPackInfo(g, l_node, CL_OFFSET, &pinfo);
00242 
00243             for (i = 0; i < ncc; i++) {
00244                 sg = ccs[i];
00245                 circularLayout(sg, g);
00246                 adjustNodes(sg);
00247             }
00248             /* FIX: splines have not been calculated for dg
00249              * To use, either do splines in dg and copy to g, or
00250              * construct components of g from ccs and use that in packing.
00251              */
00252             packSubgraphs(ncc, ccs, dg, &pinfo);
00253             for (i = 0; i < ncc; i++)
00254                 copyPosns(ccs[i]);
00255         }
00256         free(ccs);
00257     }
00258 }
00259 
00260 /* circo_layout:
00261  */
00262 void circo_layout(Agraph_t * g)
00263 {
00264     if (agnnodes(g) == 0) return;
00265     circo_init_graph(g);
00266     circoLayout(g);
00267         /* Release ND_alg as we need to reuse it during edge routing */
00268     free(ND_alg(agfstnode(g)));
00269     spline_edges(g);
00270     dotneato_postprocess(g);
00271 }
00272 
00273 /* circo_cleanup:
00274  * ND_alg is freed in circo_layout
00275  */
00276 void circo_cleanup(graph_t * g)
00277 {
00278     node_t *n;
00279     edge_t *e;
00280 
00281     n = agfstnode(g);
00282     if (n == NULL)
00283         return;                 /* g is empty */
00284 
00285     closeDerivedGraph((graph_t*)GD_alg(g));     /* delete derived graph */
00286 
00287     /* free (ND_alg(n)); */
00288     for (; n; n = agnxtnode(g, n)) {
00289         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00290             gv_cleanup_edge(e);
00291         }
00292         gv_cleanup_node(n);
00293     }
00294     free(GD_neato_nlist(g));
00295     if (g != agroot(g)) 
00296 #ifndef WITH_CGRAPH
00297         memset(&(g->u), 0, sizeof(Agraphinfo_t));
00298 #else /* WITH_CGRAPH */
00299         agclean (g,AGRAPH,"Agraphinfo_t");
00300 #endif /* WITH_CGRAPH */
00301 }