/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/circogen/circularinit.c

Go to the documentation of this file.
00001 /* $Id: circularinit.c,v 1.14 2007/08/14 15:54:24 erg Exp $ $Revision: 1.14 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 /*
00019  * Circular layout. Biconnected components are put on circles.
00020  * block-cutnode tree is done recursively, with children placed
00021  * about parent block.
00022  * Based on:
00023  *   Six and Tollis, "A Framework for Circular Drawings of
00024  * Networks", GD '99, LNCS 1731, pp. 107-116;
00025  *   Six and Tollis, "Circular Drawings of Biconnected Graphs",
00026  * Proc. ALENEX '99, pp 57-73.
00027  *   Kaufmann and Wiese, "Maintaining the Mental Map for Circular
00028  * Drawings", GD '02, LNCS 2528, pp. 12-22.
00029  */
00030 
00031 #include    "circular.h"
00032 #include    "adjust.h"
00033 #include    "pack.h"
00034 #include    "neatoprocs.h"
00035 #include    <string.h>
00036 
00037 static void circular_init_node(node_t * n)
00038 {
00039     common_init_node(n);
00040 
00041     neato_nodesize(n, GD_flip(n->graph));
00042     ND_pos(n) = N_NEW(GD_ndim(n->graph), double);
00043 }
00044 
00045 static void circular_init_edge(edge_t * e)
00046 {
00047     common_init_edge(e);
00048 
00049     ED_factor(e) = late_double(e, E_weight, 1.0, 0.0);
00050 }
00051 
00052 
00053 static void circular_init_node_edge(graph_t * g)
00054 {
00055     node_t *n;
00056     edge_t *e;
00057     int i = 0;
00058     ndata* alg = N_NEW(agnnodes(g), ndata);
00059 
00060     GD_neato_nlist(g) = N_NEW(agnnodes(g) + 1, node_t *);
00061     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00062         ND_alg(n) = alg + i;
00063         GD_neato_nlist(g)[i++] = n;
00064         circular_init_node(n);
00065     }
00066     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00067         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00068             circular_init_edge(e);
00069         }
00070     }
00071 }
00072 
00073 
00074 void circo_init_graph(graph_t * g)
00075 {
00076     setEdgeType (g, ET_LINE);
00077     /* GD_ndim(g) = late_int(g,agfindattr(g,"dim"),2,2); */
00078     Ndim = GD_ndim(g) = 2;      /* The algorithm only makes sense in 2D */
00079     circular_init_node_edge(g);
00080 }
00081 
00082 /* makeDerivedNode:
00083  * Make a node in the derived graph, with the given name.
00084  * orig points to what it represents, either a real node or
00085  * a cluster. Copy size info from original node; needed for
00086  * adjustNodes and packSubgraphs.
00087  */
00088 static node_t *makeDerivedNode(graph_t * dg, char *name, int isNode,
00089                                void *orig)
00090 {
00091     node_t *n = agnode(dg, name);
00092     ND_alg(n) = (void *) NEW(cdata);
00093     if (isNode) {
00094         ND_pos(n) = N_NEW(Ndim, double);
00095         ND_xsize(n) = ND_xsize((node_t *) orig);
00096         ND_ysize(n) = ND_ysize((node_t *) orig);
00097         ORIGN(n) = (node_t *) orig;
00098     } else
00099         ORIGG(n) = (graph_t *) orig;
00100     return n;
00101 }
00102 
00103 /* circomps:
00104  * Construct a strict, undirected graph with no loops from g.
00105  * Construct the connected components with the provision that all
00106  * nodes in a block subgraph are considered connected.
00107  * Return array of components with number of components in cnt.
00108  * Each component has its blocks as subgraphs.
00109  * FIX: Check that blocks are disjoint.
00110  */
00111 Agraph_t **circomps(Agraph_t * g, int *cnt)
00112 {
00113     int c_cnt;
00114     Agraph_t **ccs;
00115     Agraph_t *dg;
00116     Agnode_t *n, *v, *dt, *dh;
00117     Agedge_t *e;
00118     Agraph_t *sg;
00119     int i;
00120     Agedge_t *ep;
00121     Agnode_t *p;
00122 #ifdef USER_BLOCKS
00123     Agraph_t *ssg, *ssgl, *subg;
00124     Agnode_t *t;
00125     Agedge_t *me;
00126 #endif
00127 
00128     dg = agopen("derived", AGFLAG_STRICT);
00129     GD_alg(g) = dg;  /* store derived graph for closing later */
00130 #ifdef USER_BLOCKS
00131     sg = g->meta_node->graph;
00132     for (me = agfstout(sg, g->meta_node); me; me = agnxtout(sg, me)) {
00133         subg = agusergraph(me->head);
00134 
00135         if (strncmp(subg->name, "block", 5) != 0)
00136             continue;
00137 
00138         if (agnnodes(subg) == 0)
00139             continue;
00140 
00141         n = makeDerivedNode(dg, subg->name, 0, subg);
00142         for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) {
00143             DNODE(v) = n;
00144         }
00145     }
00146 #endif
00147 
00148     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00149         if (DNODE(v))
00150             continue;
00151         n = makeDerivedNode(dg, v->name, 1, v);
00152         DNODE(v) = n;
00153     }
00154 
00155     for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
00156         for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
00157             dt = DNODE(e->tail);
00158             dh = DNODE(e->head);
00159             if (dt != dh)
00160                 agedge(dg, dt, dh);
00161         }
00162     }
00163 
00164     ccs = ccomps(dg, &c_cnt, 0);
00165 
00166     /* replace block nodes with block contents */
00167     for (i = 0; i < c_cnt; i++) {
00168         sg = ccs[i];
00169 
00170 #ifdef USER_BLOCKS
00171         for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
00172             /* Expand block nodes, and create block subgraph in sg */
00173             if (agobjkind(ORIGN(n)) != AGNODE) {
00174                 ssg = ORIGG(n);
00175                 free(ND_alg(n));
00176                 agdelete(n->graph, n);
00177                 ssgl = agsubg(sg, ssg->name);
00178                 for (t = agfstnode(ssg); t; t = agnxtnode(ssg, t)) {
00179                     p = makeDerivedNode(dg, t->name, 1, t);
00180                     DNODE(t) = p;
00181                     aginsert(ssgl, p);
00182                 }
00183             }
00184         }
00185 #endif
00186 
00187         /* add edges: since sg is a union of components, all edges
00188          * of any node should be added, except loops.
00189          */
00190         for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
00191             p = ORIGN(n);
00192             for (e = agfstout(g, p); e; e = agnxtout(g, e)) {
00193                 /* n = DNODE(e->tail); by construction since e->tail == p */
00194                 dh = DNODE(e->head);
00195                 if (n != dh) {
00196                     ep = agedge(dg, n, dh);
00197                     aginsert(sg, ep);
00198                 }
00199             }
00200         }
00201     }
00202 
00203     /* Finally, add edge data to edges */
00204     for (n = agfstnode(dg); n; n = agnxtnode(dg, n)) {
00205         for (e = agfstout(dg, n); e; e = agnxtout(dg, e)) {
00206             ED_alg(e) = NEW(edata);
00207         }
00208     }
00209 
00210     *cnt = c_cnt;
00211     return ccs;
00212 }
00213 
00214 /* closeDerivedGraph:
00215  */
00216 static void closeDerivedGraph(graph_t * g)
00217 {
00218     node_t *n;
00219     edge_t *e;
00220 
00221     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00222         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00223             free(ED_alg(e));
00224         }
00225         free(ND_alg(n));
00226         free(ND_pos(n));
00227     }
00228     agclose(g);
00229 }
00230 
00231 /* copyPosns:
00232  * Copy position of nodes in given subgraph of derived graph
00233  * to corresponding node in original graph.
00234  * FIX: consider assigning from n directly to ORIG(n).
00235  */
00236 static void copyPosns(graph_t * g)
00237 {
00238     node_t *n;
00239     node_t *v;
00240 
00241     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00242         v = ORIGN(n);
00243         ND_pos(v)[0] = ND_pos(n)[0];
00244         ND_pos(v)[1] = ND_pos(n)[1];
00245     }
00246 }
00247 
00248 /* circoLayout:
00249  */
00250 void circoLayout(Agraph_t * g)
00251 {
00252     Agraph_t **ccs;
00253     Agraph_t *sg;
00254     int ncc;
00255     int i;
00256 
00257     if (agnnodes(g)) {
00258         ccs = circomps(g, &ncc);
00259 
00260         if (ncc == 1) {
00261             circularLayout(ccs[0]);
00262             copyPosns(ccs[0]);
00263             adjustNodes(g);
00264         } else {
00265             Agraph_t *dg = ccs[0]->root;
00266             pack_info pinfo;
00267             pack_mode pmode = getPackMode(g, l_node);
00268 
00269             for (i = 0; i < ncc; i++) {
00270                 sg = ccs[i];
00271                 circularLayout(sg);
00272                 adjustNodes(sg);
00273             }
00274             pinfo.margin = getPack(g, CL_OFFSET, CL_OFFSET);
00275             /* FIX: splines have not been calculated for dg
00276              * To use, either do splines in dg and copy to g, or
00277              * construct components of g from ccs and use that in packing.
00278              */
00279             pinfo.doSplines = 1;
00280             pinfo.mode = pmode;
00281             pinfo.fixed = 0;
00282             packSubgraphs(ncc, ccs, dg, &pinfo);
00283             for (i = 0; i < ncc; i++)
00284                 copyPosns(ccs[i]);
00285         }
00286         for (i = 0; i < ncc; i++) {
00287             agdelete(g, ccs[i]);
00288         }
00289         free(ccs);
00290     }
00291 }
00292 
00293 /* circo_layout:
00294  */
00295 void circo_layout(Agraph_t * g)
00296 {
00297     if (agnnodes(g) == 0) return;
00298     circo_init_graph(g);
00299     circoLayout(g);
00300         /* Release ND_alg as we need to reuse it during edge routing */
00301     free(ND_alg(agfstnode(g)));
00302     spline_edges(g);
00303     dotneato_postprocess(g);
00304 }
00305 
00306 static void circular_cleanup_node(node_t * n)
00307 {
00308     free(ND_pos(n));
00309     if (ND_shape(n))
00310         ND_shape(n)->fns->freefn(n);
00311     free_label(ND_label(n));
00312     memset(&(n->u), 0, sizeof(Agnodeinfo_t));
00313 }
00314 
00315 static void circular_free_splines(edge_t * e)
00316 {
00317     int i;
00318     if (ED_spl(e)) {
00319         for (i = 0; i < ED_spl(e)->size; i++)
00320             free(ED_spl(e)->list[i].list);
00321         free(ED_spl(e)->list);
00322         free(ED_spl(e));
00323     }
00324     ED_spl(e) = NULL;
00325 }
00326 
00327 static void circular_cleanup_edge(edge_t * e)
00328 {
00329     circular_free_splines(e);
00330     free_label(ED_label(e));
00331     memset(&(e->u), 0, sizeof(Agedgeinfo_t));
00332 }
00333 
00334 void circo_cleanup(graph_t * g)
00335 {
00336     node_t *n;
00337     edge_t *e;
00338 
00339     n = agfstnode(g);
00340     if (n == NULL)
00341         return;                 /* g is empty */
00342 
00343     closeDerivedGraph((graph_t*)GD_alg(g));     /* delete derived graph */
00344 
00345     for (; n; n = agnxtnode(g, n)) {
00346         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00347             circular_cleanup_edge(e);
00348         }
00349         circular_cleanup_node(n);
00350     }
00351     free(GD_neato_nlist(g));
00352     if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
00353 }

Generated on Mon Mar 31 19:03:23 2008 for Graphviz by  doxygen 1.5.1