Graphviz  2.29.20120524.0446
lib/twopigen/twopiinit.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  * Written by Emden R. Gansner
00017  * Derived from Graham Wills' algorithm described in GD'97.
00018  */
00019 
00020 #include    "circle.h"
00021 #include    "adjust.h"
00022 #include    "pack.h"
00023 #include    "neatoprocs.h"
00024 
00025 static void twopi_init_edge(edge_t * e)
00026 {
00027 #ifdef WITH_CGRAPH
00028     agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);   //edge custom data
00029 #endif /* WITH_CGRAPH */
00030     common_init_edge(e);
00031     ED_factor(e) = late_double(e, E_weight, 1.0, 0.0);
00032 }
00033 
00034 static void twopi_init_node_edge(graph_t * g)
00035 {
00036     node_t *n;
00037     edge_t *e;
00038     int i = 0;
00039     int n_nodes = agnnodes(g);
00040     rdata* alg;
00041 
00042     alg = N_NEW(n_nodes, rdata);
00043     GD_neato_nlist(g) = N_NEW(n_nodes + 1, node_t *);
00044     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00045         neato_init_node(n);
00046         ND_alg(n) = alg + i;
00047         GD_neato_nlist(g)[i++] = n;
00048     }
00049     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00050         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00051             twopi_init_edge(e);
00052         }
00053     }
00054 }
00055 
00056 static void scaleGraph (graph_t * g, node_t* root, pointf sc)
00057 {
00058     pointf ctr;
00059     node_t* n;
00060 
00061     ctr.x = ND_pos(root)[0];
00062     ctr.y = ND_pos(root)[1];
00063 
00064     for (n = agfstnode(g); n; n = agnxtnode (g, n)) {
00065         if (n == root) continue;
00066         ND_pos(n)[0] = sc.x*(ND_pos(n)[0] - ctr.x) + ctr.x;
00067         ND_pos(n)[1] = sc.y*(ND_pos(n)[1] - ctr.y) + ctr.y;
00068     }
00069 }
00070 
00071 void twopi_init_graph(graph_t * g)
00072 {
00073     setEdgeType (g, ET_LINE);
00074     /* GD_ndim(g) = late_int(g,agfindgraphattr(g,"dim"),2,2); */
00075         Ndim = GD_ndim(g)=2;    /* The algorithm only makes sense in 2D */
00076     twopi_init_node_edge(g);
00077 }
00078 
00079 /* twopi_layout:
00080  */
00081 void twopi_layout(Agraph_t * g)
00082 {
00083     Agnode_t *ctr = 0;
00084     char *s;
00085     int setRoot = 0;
00086     pointf sc;
00087     int doScale = 0;
00088     int r;
00089 
00090     if (agnnodes(g) == 0) return;
00091 
00092     twopi_init_graph(g);
00093     s = agget(g, "root");
00094     if ((s = agget(g, "root"))) {
00095         if (*s) {
00096             ctr = agfindnode(g, s);
00097             if (!ctr) {
00098                 agerr(AGWARN, "specified root node \"%s\" was not found.", s);
00099                 agerr(AGPREV, "Using default calculation for root node\n");
00100                 setRoot = 1;
00101             }
00102         }
00103         else {
00104             setRoot = 1;
00105         }
00106     }
00107 
00108     if ((s = agget(g, "scale")) && *s) {
00109         if ((r = sscanf (s, "%lf,%lf",&sc.x,&sc.y))) {
00110             if (r == 1) sc.y = sc.x;
00111             doScale = 1;
00112             if (Verbose)
00113                 fprintf (stderr, "scale = (%f,%f)\n", sc.x, sc.y);
00114         }
00115     }
00116 
00117     if (agnnodes(g)) {
00118         Agraph_t **ccs;
00119         Agraph_t *sg;
00120         Agnode_t *c = NULL;
00121         Agnode_t *n;
00122         int ncc;
00123         int i;
00124 
00125         ccs = ccomps(g, &ncc, 0);
00126         if (ncc == 1) {
00127             c = circleLayout(g, ctr);
00128             if (setRoot && !ctr)
00129                 ctr = c;
00130             n = agfstnode(g);
00131             free(ND_alg(n));
00132             ND_alg(n) = NULL;
00133             if (doScale)
00134                 scaleGraph (g, c, sc);
00135             adjustNodes(g);
00136             spline_edges(g);
00137         } else {
00138             pack_info pinfo;
00139             getPackInfo (g, l_node, CL_OFFSET, &pinfo);
00140             pinfo.doSplines = 0;
00141 
00142             for (i = 0; i < ncc; i++) {
00143                 sg = ccs[i];
00144                 if (ctr && agcontains(sg, ctr))
00145                     c = ctr;
00146                 else
00147                     c = 0;
00148                 nodeInduce(sg);
00149                 c = circleLayout(sg, c);
00150                 if (setRoot && !ctr)
00151                     ctr = c;
00152                 if (doScale)
00153                     scaleGraph (sg, c, sc);
00154                 adjustNodes(sg);
00155             }
00156             n = agfstnode(g);
00157             free(ND_alg(n));
00158             ND_alg(n) = NULL;
00159             packSubgraphs(ncc, ccs, g, &pinfo);
00160             spline_edges(g);
00161         }
00162         for (i = 0; i < ncc; i++) {
00163             agdelete(g, ccs[i]);
00164         }
00165         free(ccs);
00166     }
00167     if (setRoot)
00168         agset (g, "root", agnameof (ctr)); 
00169     dotneato_postprocess(g);
00170 
00171 }
00172 
00173 static void twopi_cleanup_graph(graph_t * g)
00174 {
00175     free(GD_neato_nlist(g));
00176     if (g != agroot(g))
00177 #ifndef WITH_CGRAPH
00178         memset(&(g->u), 0, sizeof(Agraphinfo_t));
00179 #else /* WITH_CGRAPH */
00180         agclean(g,AGRAPH,"Agraphinfo_t");
00181 #endif /* WITH_CGRAPH */
00182 }
00183 
00184 /* twopi_cleanup:
00185  * The ND_alg data used by twopi is freed in twopi_layout
00186  * before edge routing as edge routing may use this field.
00187  */
00188 void twopi_cleanup(graph_t * g)
00189 {
00190     node_t *n;
00191     edge_t *e;
00192 
00193     n = agfstnode (g);
00194     if (!n) return; /* empty graph */
00195     /* free (ND_alg(n)); */
00196     for (; n; n = agnxtnode(g, n)) {
00197         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00198             gv_cleanup_edge(e);
00199         }
00200         gv_cleanup_node(n);
00201     }
00202     twopi_cleanup_graph(g);
00203 }