Graphviz  2.31.20130618.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 #ifndef WITH_CGRAPH
00194     if (g != agroot(g)) 
00195         memset(&(g->u), 0, sizeof(Agraphinfo_t));
00196 #else /* WITH_CGRAPH */
00197     if (g != agroot(g)) 
00198         agdelrec(g,"Agraphinfo_t");
00199 #endif /* WITH_CGRAPH */
00200 }
00201 
00202 /* delete the layout (but retain the underlying graph) */
00203 void dot_cleanup(graph_t * g)
00204 {
00205     node_t *n;
00206     edge_t *e;
00207 
00208     free_virtual_node_list(GD_nlist(g));
00209     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00210         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00211             gv_cleanup_edge(e);
00212         }
00213         dot_cleanup_node(n);
00214     }
00215     dot_cleanup_graph(g);
00216 }
00217 
00218 #ifdef DEBUG
00219 int
00220 fastn (graph_t * g)
00221 {
00222     node_t* u;
00223     int cnt = 0;
00224     for (u = GD_nlist(g); u; u = ND_next(u)) cnt++;
00225     return cnt;
00226 }
00227 
00228 static void
00229 dumpRanks (graph_t * g)
00230 {
00231     int i, j;
00232     node_t* u;
00233     rank_t *rank = GD_rank(g);
00234     int rcnt = 0;
00235     for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
00236         fprintf (stderr, "[%d] :", i);
00237         for (j = 0; j < rank[i].n; j++) {
00238             u = rank[i].v[j];
00239             rcnt++;
00240             if (streq(agnameof(u),"virtual"))
00241                 fprintf (stderr, " %x", u);
00242             else
00243                 fprintf (stderr, " %s", agnameof(u));
00244       
00245         }
00246         fprintf (stderr, "\n");
00247     }
00248     fprintf (stderr, "count %d rank count = %d\n", fastn(g), rcnt);
00249 }
00250 #endif
00251 
00252 #define MIN_AR 1.0
00253 #define MAX_AR 20.0
00254 #define DEF_PASSES 5
00255 
00256 static aspect_t*
00257 setAspect (Agraph_t * g, aspect_t* adata)
00258 {
00259     double rv;
00260     char *p;
00261     int r, passes = DEF_PASSES;
00262 
00263     p = agget (g, "aspect");
00264 
00265     if (!p || ((r = sscanf (p, "%lf,%d", &rv, &passes)) <= 0)) {
00266         adata->nextIter = 0;
00267         adata->badGraph = 0;
00268         return NULL;
00269     }
00270     
00271     if (rv < MIN_AR) rv = MIN_AR;
00272     else if (rv > MAX_AR) rv = MAX_AR;
00273     adata->targetAR = rv;
00274     adata->nextIter = -1;
00275     adata->nPasses = passes;
00276     adata->badGraph = 0;
00277 
00278     if (Verbose) 
00279         fprintf(stderr, "Target AR = %g\n", adata->targetAR);
00280 
00281     return adata;
00282 }
00283 
00284 #ifdef WITH_CGRAPH
00285 static void
00286 remove_from_rank (Agraph_t * g, Agnode_t* n)
00287 {
00288     Agnode_t* v = NULL;
00289     int j, rk = ND_rank(n);
00290 
00291     for (j = 0; j < GD_rank(g)[rk].n; j++) {
00292         v = GD_rank(g)[rk].v[j];
00293         if (v == n) {
00294             for (j++; j < GD_rank(g)[rk].n; j++) {
00295                 GD_rank(g)[rk].v[j-1] = GD_rank(g)[rk].v[j];
00296             }
00297             GD_rank(g)[rk].n--;
00298             break;
00299         }
00300     }
00301     assert (v == n);  /* if found */
00302 }
00303 
00304 /* removeFill:
00305  * This removes all of the fill nodes added in mincross.
00306  * It appears to be sufficient to remove them only from the
00307  * rank array and fast node list of the root graph.
00308  */
00309 static void
00310 removeFill (Agraph_t * g)
00311 {
00312     Agnode_t* n;
00313     Agnode_t* nxt;
00314     Agraph_t* sg = agsubg (g, "_new_rank", 0);
00315 
00316     if (!sg) return;
00317     for (n = agfstnode(sg); n; n = nxt) {
00318         nxt = agnxtnode(sg, n);
00319         delete_fast_node (g, n);
00320         remove_from_rank (g, n);
00321         dot_cleanup_node (n);
00322         agdelnode(g, n);
00323     }
00324     agdelsubg (g, sg);
00325 
00326 }
00327 #endif
00328 
00329 #ifndef WITH_CGRAPH
00330 #define ag_xset(x,a,v) agxset(x,a->index,v)
00331 #else /* WITH_CGRAPH */
00332 #define ag_xset(x,a,v) agxset(x,a,v)
00333 #define agnodeattr(g,n,v) agattr(g,AGNODE,n,v)
00334 #endif /* WITH_CGRAPH */
00335 
00336 static void
00337 attach_phase_attrs (Agraph_t * g, int maxphase)
00338 {
00339     Agsym_t* rk = agnodeattr(g,"rank","");
00340     Agsym_t* order = agnodeattr(g,"order","");
00341     Agnode_t* n;
00342     char buf[BUFSIZ];
00343 
00344     for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
00345         if (maxphase >= 1) {
00346             sprintf(buf, "%d", ND_rank(n));
00347             ag_xset(n,rk,buf);
00348         }
00349         if (maxphase >= 2) {
00350             sprintf(buf, "%d", ND_order(n));
00351             ag_xset(n,order,buf);
00352         }
00353     }
00354 }
00355 
00356 void dot_layout(Agraph_t * g)
00357 {
00358     aspect_t aspect;
00359     aspect_t* asp;
00360     int maxphase = late_int(g, agfindgraphattr(g,"phase"), -1, 1);
00361 
00362     setEdgeType (g, ET_SPLINE);
00363     asp = setAspect (g, &aspect);
00364 
00365 #ifdef WITH_CGRAPH
00366     dot_init_subg(g);
00367 #endif
00368 
00369     dot_init_node_edge(g);
00370 
00371     do {
00372         dot_rank(g, asp);
00373         if (maxphase == 1) {
00374             attach_phase_attrs (g, 1);
00375             return;
00376         }
00377         if (aspect.badGraph) {
00378             agerr(AGWARN, "dot does not support the aspect attribute for disconnected graphs or graphs with clusters\n");
00379             asp = NULL;
00380             aspect.nextIter = 0;
00381         }
00382         dot_mincross(g, (asp != NULL));
00383         if (maxphase == 2) {
00384             attach_phase_attrs (g, 2);
00385             return;
00386         }
00387         dot_position(g, asp);
00388         if (maxphase == 3) {
00389             attach_phase_attrs (g, 2);  /* positions will be attached on output */
00390             return;
00391         }
00392         aspect.nPasses--;
00393     } while (aspect.nextIter && aspect.nPasses);
00394 #ifdef WITH_CGRAPH
00395     if (GD_flags(g) & NEW_RANK)
00396         removeFill (g);
00397 #endif
00398     dot_sameports(g);
00399     dot_splines(g);
00400     if (mapbool(agget(g, "compound")))
00401         dot_compoundEdges(g);
00402     dotneato_postprocess(g);
00403 
00404 }