Graphviz  2.31.20130523.0446
lib/dotgen/class2.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 /* classify edges for mincross/nodepos/splines, using given ranks */
00016 
00017 #include "dot.h"
00018 
00019 static node_t*
00020 label_vnode(graph_t * g, edge_t * orig)
00021 {
00022     node_t *v;
00023     pointf dimen;
00024 
00025     dimen = ED_label(orig)->dimen;
00026     v = virtual_node(g);
00027     ND_label(v) = ED_label(orig);
00028     ND_lw(v) = GD_nodesep(agroot(agraphof(v)));
00029     if (!ED_label_ontop(orig)) {
00030         if (GD_flip(agroot(g))) {
00031             ND_ht(v) = dimen.x;
00032             ND_rw(v) = dimen.y;
00033         } else {
00034             ND_ht(v) = dimen.y;
00035             ND_rw(v) = dimen.x;
00036         }
00037     }
00038     return v;
00039 }
00040 
00041 static void 
00042 incr_width(graph_t * g, node_t * v)
00043 {
00044     int width = GD_nodesep(g) / 2;
00045     ND_lw(v) += width;
00046     ND_rw(v) += width;
00047 }
00048 
00049 static node_t*
00050 plain_vnode(graph_t * g, edge_t * orig)
00051 {
00052     node_t *v;
00053     orig = orig;
00054     v = virtual_node(g);
00055     incr_width(g, v);
00056     return v;
00057 }
00058 
00059 static node_t*
00060 leader_of(graph_t * g, node_t * v)
00061 {
00062     graph_t *clust;
00063     node_t *rv;
00064 
00065     if (ND_ranktype(v) != CLUSTER) {
00066         /*assert(v == UF_find(v));  could be leaf, so comment out */
00067         rv = UF_find(v);
00068     } else {
00069         clust = ND_clust(v);
00070         rv = GD_rankleader(clust)[ND_rank(v)];
00071     }
00072     return rv;
00073 }
00074 
00075 /* make_chain:
00076  * Create chain of dummy nodes for edge orig.
00077  */
00078 static void 
00079 make_chain(graph_t * g, node_t * from, node_t * to, edge_t * orig)
00080 {
00081     int r, label_rank;
00082     node_t *u, *v;
00083     edge_t *e;
00084 
00085     u = from;
00086     if (ED_label(orig))
00087         label_rank = (ND_rank(from) + ND_rank(to)) / 2;
00088     else
00089         label_rank = -1;
00090     assert(ED_to_virt(orig) == NULL);
00091     for (r = ND_rank(from) + 1; r <= ND_rank(to); r++) {
00092         if (r < ND_rank(to)) {
00093             if (r == label_rank)
00094                 v = label_vnode(g, orig);
00095             else
00096                 v = plain_vnode(g, orig);
00097             ND_rank(v) = r;
00098         } else
00099             v = to;
00100         e = virtual_edge(u, v, orig);
00101         virtual_weight(e);
00102         u = v;
00103     }
00104     assert(ED_to_virt(orig) != NULL);
00105 }
00106 
00107 static void 
00108 interclrep(graph_t * g, edge_t * e)
00109 {
00110     node_t *t, *h;
00111     edge_t *ve;
00112 
00113     t = leader_of(g, agtail(e));
00114     h = leader_of(g, aghead(e));
00115     if (ND_rank(t) > ND_rank(h)) {
00116         node_t *t0 = t;
00117         t = h;
00118         h = t0;
00119     }
00120     if (ND_clust(t) != ND_clust(h)) {
00121         if ((ve = find_fast_edge(t, h))) {
00122             merge_chain(g, e, ve, TRUE);
00123             return;
00124         }
00125         if (ND_rank(t) == ND_rank(h))
00126             return;
00127         make_chain(g, t, h, e);
00128 
00129         /* mark as cluster edge */
00130         for (ve = ED_to_virt(e); ve && (ND_rank(aghead(ve)) <= ND_rank(h));
00131              ve = ND_out(aghead(ve)).list[0])
00132             ED_edge_type(ve) = CLUSTER_EDGE;
00133     }
00134     /* else ignore intra-cluster edges at this point */
00135 }
00136 
00137 static int 
00138 is_cluster_edge(edge_t * e)
00139 {
00140     return ((ND_ranktype(agtail(e)) == CLUSTER)
00141             || (ND_ranktype(aghead(e)) == CLUSTER));
00142 }
00143 
00144 void merge_chain(graph_t * g, edge_t * e, edge_t * f, int flag)
00145 {
00146     edge_t *rep;
00147     int lastrank = MAX(ND_rank(agtail(e)), ND_rank(aghead(e)));
00148 
00149     assert(ED_to_virt(e) == NULL);
00150     ED_to_virt(e) = f;
00151     rep = f;
00152     do {
00153         /* interclust multi-edges are not counted now */
00154         if (flag)
00155             ED_count(rep) += ED_count(e);
00156         ED_xpenalty(rep) += ED_xpenalty(e);
00157         ED_weight(rep) += ED_weight(e);
00158         if (ND_rank(aghead(rep)) == lastrank)
00159             break;
00160         incr_width(g, aghead(rep));
00161         rep = ND_out(aghead(rep)).list[0];
00162     } while (rep);
00163 }
00164 
00165 int mergeable(edge_t * e, edge_t * f)
00166 {
00167     if (e && f && (agtail(e) == agtail(f)) && (aghead(e) == aghead(f)) &&
00168         (ED_label(e) == ED_label(f)) && ports_eq(e, f))
00169         return TRUE;
00170     return FALSE;
00171 }
00172 
00173 void class2(graph_t * g)
00174 {
00175     int c;
00176     node_t *n, *t, *h;
00177     edge_t *e, *prev, *opp;
00178 
00179     GD_nlist(g) = NULL;
00180 
00181     GD_n_nodes(g) = 0;          /* new */
00182 
00183     mark_clusters(g);
00184     for (c = 1; c <= GD_n_cluster(g); c++)
00185         build_skeleton(g, GD_clust(g)[c]);
00186     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00187         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00188             if (ND_weight_class(aghead(e)) <= 2)
00189                 ND_weight_class(aghead(e))++;
00190             if (ND_weight_class(agtail(e)) <= 2)
00191                 ND_weight_class(agtail(e))++;
00192         }
00193 
00194     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00195         if ((ND_clust(n) == NULL) && (n == UF_find(n))) {
00196             fast_node(g, n);
00197             GD_n_nodes(g)++;
00198         }
00199         prev = NULL;
00200         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00201 
00202             /* already processed */
00203             if (ED_to_virt(e)) {
00204                 prev = e;
00205                 continue;
00206             }
00207 
00208             /* edges involving sub-clusters of g */
00209             if (is_cluster_edge(e)) {
00210                 /* following is new cluster multi-edge code */
00211                 if (mergeable(prev, e)) {
00212                     if (ED_to_virt(prev)) {
00213                         merge_chain(g, e, ED_to_virt(prev), FALSE);
00214                         other_edge(e);
00215                     } else if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
00216                         merge_oneway(e, prev);
00217                         other_edge(e);
00218                     }
00219                     /* else is an intra-cluster edge */
00220                     continue;
00221                 }
00222                 interclrep(g, e);
00223                 prev = e;
00224                 continue;
00225             }
00226             /* merge multi-edges */
00227             if (prev && (agtail(e) == agtail(prev)) && (aghead(e) == aghead(prev))) {
00228                 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
00229                     merge_oneway(e, prev);
00230                     other_edge(e);
00231                     continue;
00232                 }
00233                 if ((ED_label(e) == NULL) && (ED_label(prev) == NULL)
00234                     && ports_eq(e, prev)) {
00235                     if (Concentrate)
00236                         ED_edge_type(e) = IGNORED;
00237                     else {
00238                         merge_chain(g, e, ED_to_virt(prev), TRUE);
00239                         other_edge(e);
00240                     }
00241                     continue;
00242                 }
00243                 /* parallel edges with different labels fall through here */
00244             }
00245 
00246             /* self edges */
00247             if (agtail(e) == aghead(e)) {
00248                 other_edge(e);
00249                 prev = e;
00250                 continue;
00251             }
00252 
00253             t = UF_find(agtail(e));
00254             h = UF_find(aghead(e));
00255 
00256             /* non-leader leaf nodes */
00257             if ((agtail(e) != t) || (aghead(e) != h)) {
00258                 /* FIX need to merge stuff */
00259                 continue;
00260             }
00261 
00262 
00263             /* flat edges */
00264             if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
00265                 flat_edge(g, e);
00266                 prev = e;
00267                 continue;
00268             }
00269 
00270             /* forward edges */
00271             if (ND_rank(aghead(e)) > ND_rank(agtail(e))) {
00272                 make_chain(g, agtail(e), aghead(e), e);
00273                 prev = e;
00274                 continue;
00275             }
00276 
00277             /* backward edges */
00278             else {
00279                 /*other_edge(e); */
00280                 /* avoid when opp==e in undirected graph */
00281 #ifndef WITH_CGRAPH
00282                 if ((opp = agfindedge(g, aghead(e), agtail(e))) && (opp != e)) {
00283 #else
00284                 if ((opp = agfindedge(g, aghead(e), agtail(e))) && (aghead(opp) != aghead(e))) {
00285 #endif /* WITH_CGRAPH */
00286                     /* shadows a forward edge */
00287                     if (ED_to_virt(opp) == NULL)
00288                         make_chain(g, agtail(opp), aghead(opp), opp);
00289                     if ((ED_label(e) == NULL) && (ED_label(opp) == NULL)
00290                         && ports_eq(e, opp)) {
00291                         if (Concentrate) {
00292                             ED_edge_type(e) = IGNORED;
00293                             ED_conc_opp_flag(opp) = TRUE;
00294                         } else {        /* see above.  this is getting out of hand */
00295                             other_edge(e);
00296                             merge_chain(g, e, ED_to_virt(opp), TRUE);
00297                         }
00298                         continue;
00299                     }
00300                 }
00301                 make_chain(g, aghead(e), agtail(e), e);
00302                 prev = e;
00303             }
00304         }
00305     }
00306     /* since decompose() is not called on subgraphs */
00307     if (g != agroot(g)) {
00308         GD_comp(g).list = ALLOC(1, GD_comp(g).list, node_t *);
00309         GD_comp(g).list[0] = GD_nlist(g);
00310     }
00311 }
00312