Graphviz  2.29.20120523.0446
lib/dotgen/dotinit.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 #include <time.h>
00016 #include "dot.h"
00017 #include "aspect.h"
00018 
00019 #ifdef WITH_CGRAPH
00020 static void
00021 dot_init_subg(graph_t * g)
00022 {
00023     graph_t* subg;
00024 
00025     if ((g != agroot(g)))
00026         agbindrec(g, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
00027     for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
00028         dot_init_subg(subg);
00029     }
00030 }
00031 #endif
00032 
00033 
00034 static void 
00035 dot_init_node(node_t * n)
00036 {
00037 #ifdef WITH_CGRAPH
00038     agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);   //graph custom data
00039 #endif /* WITH_CGRAPH */
00040     common_init_node(n);
00041     gv_nodesize(n, GD_flip(agraphof(n)));
00042     alloc_elist(4, ND_in(n));
00043     alloc_elist(4, ND_out(n));
00044     alloc_elist(2, ND_flat_in(n));
00045     alloc_elist(2, ND_flat_out(n));
00046     alloc_elist(2, ND_other(n));
00047     ND_UF_size(n) = 1;
00048 }
00049 
00050 static void 
00051 dot_init_edge(edge_t * e)
00052 {
00053     char *tailgroup, *headgroup;
00054 #ifdef WITH_CGRAPH
00055     agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);   //graph custom data
00056 #endif /* WITH_CGRAPH */
00057     common_init_edge(e);
00058 
00059     ED_weight(e) = late_int(e, E_weight, 1, 0);
00060     tailgroup = late_string(agtail(e), N_group, "");
00061     headgroup = late_string(aghead(e), N_group, "");
00062     ED_count(e) = ED_xpenalty(e) = 1;
00063     if (tailgroup[0] && (tailgroup == headgroup)) {
00064         ED_xpenalty(e) = CL_CROSS;
00065         ED_weight(e) *= 100;
00066     }
00067     if (nonconstraint_edge(e)) {
00068         ED_xpenalty(e) = 0;
00069         ED_weight(e) = 0;
00070     }
00071 
00072     ED_showboxes(e) = late_int(e, E_showboxes, 0, 0);
00073     ED_minlen(e) = late_int(e, E_minlen, 1, 0);
00074 }
00075 
00076 void 
00077 dot_init_node_edge(graph_t * g)
00078 {
00079     node_t *n;
00080     edge_t *e;
00081 
00082     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00083         dot_init_node(n);
00084     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00085         for (e = agfstout(g, n); e; e = agnxtout(g, e))
00086             dot_init_edge(e);
00087     }
00088 }
00089 
00090 #if 0                           /* not used */
00091 static void free_edge_list(elist L)
00092 {
00093     edge_t *e;
00094     int i;
00095 
00096     for (i = 0; i < L.size; i++) {
00097         e = L.list[i];
00098         free(e);
00099     }
00100 }
00101 #endif
00102 
00103 static void 
00104 dot_cleanup_node(node_t * n)
00105 {
00106     free_list(ND_in(n));
00107     free_list(ND_out(n));
00108     free_list(ND_flat_out(n));
00109     free_list(ND_flat_in(n));
00110     free_list(ND_other(n));
00111     free_label(ND_label(n));
00112     if (ND_shape(n))
00113         ND_shape(n)->fns->freefn(n);
00114 #ifndef WITH_CGRAPH
00115     memset(&(n->u), 0, sizeof(Agnodeinfo_t));
00116 #else /* WITH_CGRAPH */
00117     agdelrec(n, "Agnodeinfo_t");        
00118 #endif /* WITH_CGRAPH */
00119 }
00120 
00121 static void free_virtual_edge_list(node_t * n)
00122 {
00123     edge_t *e;
00124     int i;
00125 
00126     for (i = ND_in(n).size - 1; i >= 0; i--) {
00127         e = ND_in(n).list[i];
00128         delete_fast_edge(e);
00129 #ifdef WITH_CGRAPH
00130         free(e->base.data);
00131 #endif
00132         free(e);
00133     }
00134     for (i = ND_out(n).size - 1; i >= 0; i--) {
00135         e = ND_out(n).list[i];
00136         delete_fast_edge(e);
00137 #ifdef WITH_CGRAPH
00138         free(e->base.data);
00139 #endif
00140         free(e);
00141     }
00142 }
00143 
00144 static void free_virtual_node_list(node_t * vn)
00145 {
00146     node_t *next_vn;
00147 
00148     while (vn) {
00149         next_vn = ND_next(vn);
00150         free_virtual_edge_list(vn);
00151         if (ND_node_type(vn) == VIRTUAL) {
00152             free_list(ND_out(vn));
00153             free_list(ND_in(vn));
00154 #ifdef WITH_CGRAPH
00155             free(vn->base.data);
00156 #endif
00157             free(vn);
00158         }
00159         vn = next_vn;
00160     }
00161 }
00162 
00163 static void 
00164 dot_cleanup_graph(graph_t * g)
00165 {
00166     int i;
00167 #ifndef WITH_CGRAPH
00168     graph_t *clust;
00169     int c;
00170     for (c = 1; c <= GD_n_cluster(g); c++) {
00171         clust = GD_clust(g)[c];
00172         GD_parent(clust) = NULL;
00173         dot_cleanup(clust);
00174     }
00175 #else
00176     graph_t *subg;
00177     for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
00178         dot_cleanup_graph(subg);
00179     }
00180 #endif
00181     if (GD_clust(g)) free (GD_clust(g));
00182     if (GD_rankleader(g)) free (GD_rankleader(g));
00183 
00184     free_list(GD_comp(g));
00185     if (GD_rank(g)) {
00186         for (i = GD_minrank(g); i <= GD_maxrank(g); i++)
00187             free(GD_rank(g)[i].av);
00188         if (GD_minrank(g) == -1)
00189             free(GD_rank(g)-1);
00190         else
00191             free(GD_rank(g));
00192     }
00193     if (g != agroot(g)) 
00194 #ifndef WITH_CGRAPH
00195         memset(&(g->u), 0, sizeof(Agraphinfo_t));
00196 #else /* WITH_CGRAPH */
00197         agdelrec(g,"Agraphinfo_t");
00198 #endif /* WITH_CGRAPH */
00199 }
00200 
00201 /* delete the layout (but retain the underlying graph) */
00202 void dot_cleanup(graph_t * g)
00203 {
00204     node_t *n;
00205     edge_t *e;
00206 
00207     free_virtual_node_list(GD_nlist(g));
00208     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00209         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00210             gv_cleanup_edge(e);
00211         }
00212         dot_cleanup_node(n);
00213     }
00214     dot_cleanup_graph(g);
00215 }
00216 
00217 #ifdef DEBUG
00218 int
00219 fastn (graph_t * g)
00220 {
00221     node_t* u;
00222     int cnt = 0;
00223     for (u = GD_nlist(g); u; u = ND_next(u)) cnt++;
00224     return cnt;
00225 }
00226 
00227 static void
00228 dumpRanks (graph_t * g)
00229 {
00230     int i, j;
00231     node_t* u;
00232     rank_t *rank = GD_rank(g);
00233     int rcnt = 0;
00234     for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
00235         fprintf (stderr, "[%d] :", i);
00236         for (j = 0; j < rank[i].n; j++) {
00237             u = rank[i].v[j];
00238             rcnt++;
00239             if (streq(u->name,"virtual"))
00240                 fprintf (stderr, " %x", u);
00241             else
00242                 fprintf (stderr, " %s", u->name);
00243       
00244         }
00245         fprintf (stderr, "\n");
00246     }
00247     fprintf (stderr, "count %d rank count = %d\n", fastn(g), rcnt);
00248 }
00249 #endif
00250 
00251 #define MIN_AR 1.0
00252 #define MAX_AR 20.0
00253 #define DEF_PASSES 5
00254 
00255 static aspect_t*
00256 setAspect (Agraph_t * g, aspect_t* adata)
00257 {
00258     double rv;
00259     char *p;
00260     int r, passes = DEF_PASSES;
00261 
00262     p = agget (g, "aspect");
00263 
00264     if (!p || ((r = sscanf (p, "%lf,%d", &rv, &passes)) <= 0)) {
00265         adata->nextIter = 0;
00266         adata->badGraph = 0;
00267         return NULL;
00268     }
00269     
00270     if (rv < MIN_AR) rv = MIN_AR;
00271     else if (rv > MAX_AR) rv = MAX_AR;
00272     adata->targetAR = rv;
00273     adata->nextIter = -1;
00274     adata->nPasses = passes;
00275     adata->badGraph = 0;
00276 
00277     if (Verbose) 
00278         fprintf(stderr, "Target AR = %g\n", adata->targetAR);
00279 
00280     return adata;
00281 }
00282 
00283 #ifdef WITH_CGRAPH
00284 static void
00285 remove_from_rank (Agraph_t * g, Agnode_t* n)
00286 {
00287     Agnode_t* v = NULL;
00288     int j, rk = ND_rank(n);
00289 
00290     for (j = 0; j < GD_rank(g)[rk].n; j++) {
00291         v = GD_rank(g)[rk].v[j];
00292         if (v == n) {
00293             for (j++; j < GD_rank(g)[rk].n; j++) {
00294                 GD_rank(g)[rk].v[j-1] = GD_rank(g)[rk].v[j];
00295             }
00296             GD_rank(g)[rk].n--;
00297             break;
00298         }
00299     }
00300     assert (v == n);  /* if found */
00301 }
00302 
00303 /* removeFill:
00304  * This removes all of the fill nodes added in mincross.
00305  * It appears to be sufficient to remove them only from the
00306  * rank array and fast node list of the root graph.
00307  */
00308 static void
00309 removeFill (Agraph_t * g)
00310 {
00311     Agnode_t* n;
00312     Agnode_t* nxt;
00313     Agraph_t* sg = agsubg (g, "_new_rank", 0);
00314 
00315     if (!sg) return;
00316     for (n = agfstnode(sg); n; n = nxt) {
00317         nxt = agnxtnode(sg, n);
00318         delete_fast_node (g, n);
00319         remove_from_rank (g, n);
00320         dot_cleanup_node (n);
00321         agdelnode(g, n);
00322     }
00323     agdelsubg (g, sg);
00324 
00325 }
00326 #endif
00327 
00328 void dot_layout(Agraph_t * g)
00329 {
00330     aspect_t aspect;
00331     aspect_t* asp;
00332 
00333     setEdgeType (g, ET_SPLINE);
00334     asp = setAspect (g, &aspect);
00335 
00336 #ifdef WITH_CGRAPH
00337     dot_init_subg(g);
00338 #endif
00339 
00340     dot_init_node_edge(g);
00341 
00342     do {
00343         dot_rank(g, asp);
00344         if (aspect.badGraph) {
00345             agerr(AGWARN, "dot does not support the aspect attribute for disconnected graphs or graphs with clusters\n");
00346             asp = NULL;
00347             aspect.nextIter = 0;
00348         }
00349         dot_mincross(g, (asp != NULL));
00350         dot_position(g, asp);
00351         aspect.nPasses--;
00352     } while (aspect.nextIter && aspect.nPasses);
00353 #ifdef WITH_CGRAPH
00354     if (GD_flags(g) & NEW_RANK)
00355         removeFill (g);
00356 #endif
00357     dot_sameports(g);
00358     dot_splines(g);
00359     if (mapbool(agget(g, "compound")))
00360         dot_compoundEdges(g);
00361     dotneato_postprocess(g);
00362 
00363 }