/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/dotgen/class2.c

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

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