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

Go to the documentation of this file.
00001 /* $Id: flat.c,v 1.6 2006/12/07 22:49:36 erg Exp $ $Revision: 1.6 $ */
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 #include        "dot.h"
00019 
00020 
00021 static node_t *make_vn_slot(graph_t * g, int r, int pos)
00022 {
00023     int i;
00024     node_t **v, *n;
00025 
00026     v = GD_rank(g)[r].v =
00027         ALLOC(GD_rank(g)[r].n + 2, GD_rank(g)[r].v, node_t *);
00028     for (i = GD_rank(g)[r].n; i > pos; i--) {
00029         v[i] = v[i - 1];
00030         v[i]->u.order++;
00031     }
00032     n = v[pos] = virtual_node(g);
00033     ND_order(n) = pos;
00034     ND_rank(n) = r;
00035     v[++(GD_rank(g)[r].n)] = NULL;
00036     return v[pos];
00037 }
00038 
00039 #define         HLB     0       /* hard left bound */
00040 #define         HRB             1       /* hard right bound */
00041 #define         SLB             2       /* soft left bound */
00042 #define         SRB             3       /* soft right bound */
00043 
00044 static void findlr(node_t * u, node_t * v, int *lp, int *rp)
00045 {
00046     int l, r;
00047     l = ND_order(u);
00048     r = ND_order(v);
00049     if (l > r) {
00050         int t = l;
00051         l = r;
00052         r = t;
00053     }
00054     *lp = l;
00055     *rp = r;
00056 }
00057 
00058 static void setbounds(node_t * v, int *bounds, int lpos, int rpos)
00059 {
00060     int i, l, r, ord;
00061     edge_t *f;
00062 
00063     if (ND_node_type(v) == VIRTUAL) {
00064         ord = ND_order(v);
00065         if (ND_in(v).size == 0) {       /* flat */
00066             assert(ND_out(v).size == 2);
00067             findlr(ND_out(v).list[0]->head, ND_out(v).list[1]->head, &l,
00068                    &r);
00069             /* the other flat edge could be to the left or right */
00070             if (r <= lpos)
00071                 bounds[SLB] = bounds[HLB] = ord;
00072             else if (l >= rpos)
00073                 bounds[SRB] = bounds[HRB] = ord;
00074             /* could be spanning this one */
00075             else if ((l < lpos) && (r > rpos)); /* ignore */
00076             /* must have intersecting ranges */
00077             else {
00078                 if ((l < lpos) || ((l == lpos) && (r < rpos)))
00079                     bounds[SLB] = ord;
00080                 if ((r > rpos) || ((r == rpos) && (l > lpos)))
00081                     bounds[SRB] = ord;
00082             }
00083         } else {                /* forward */
00084             boolean onleft, onright;
00085             onleft = onright = FALSE;
00086             for (i = 0; (f = ND_out(v).list[i]); i++) {
00087                 if (ND_order(f->head) <= lpos) {
00088                     onleft = TRUE;
00089                     continue;
00090                 }
00091                 if (ND_order(f->head) >= rpos) {
00092                     onright = TRUE;
00093                     continue;
00094                 }
00095             }
00096             if (onleft && (onright == FALSE))
00097                 bounds[HLB] = ord + 1;
00098             if (onright && (onleft == FALSE))
00099                 bounds[HRB] = ord - 1;
00100         }
00101     }
00102 }
00103 
00104 static int flat_limits(graph_t * g, edge_t * e)
00105 {
00106     int lnode, rnode, r, bounds[4], lpos, rpos, pos;
00107     node_t **rank;
00108 
00109     r = ND_rank(e->tail) - 1;
00110     rank = GD_rank(g)[r].v;
00111     lnode = 0;
00112     rnode = GD_rank(g)[r].n - 1;
00113     bounds[HLB] = bounds[SLB] = lnode - 1;
00114     bounds[HRB] = bounds[SRB] = rnode + 1;
00115     findlr(e->tail, e->head, &lpos, &rpos);
00116     while (lnode <= rnode) {
00117         setbounds(rank[lnode], bounds, lpos, rpos);
00118         if (lnode != rnode)
00119             setbounds(rank[rnode], bounds, lpos, rpos);
00120         lnode++;
00121         rnode--;
00122         if (bounds[HRB] - bounds[HLB] <= 1)
00123             break;
00124     }
00125     if (bounds[HLB] <= bounds[HRB])
00126         pos = (bounds[HLB] + bounds[HRB] + 1) / 2;
00127     else
00128         pos = (bounds[SLB] + bounds[SRB] + 1) / 2;
00129     return pos;
00130 }
00131 
00132 /* flat_node:
00133  * Create virtual node representing edge label between
00134  * actual ends of edge e. 
00135  * This node is characterized by being virtual and having a non-NULL
00136  * ND_alg pointing to e.
00137  */
00138 static void 
00139 flat_node(edge_t * e)
00140 {
00141     int r, place, ypos, h2;
00142     graph_t *g;
00143     node_t *n, *vn;
00144     edge_t *ve;
00145     pointf dimen;
00146 
00147     if (ED_label(e) == NULL)
00148         return;
00149     g = e->tail->graph;
00150     r = ND_rank(e->tail);
00151 
00152     place = flat_limits(g, e);
00153     /* grab ypos = LL.y of label box before make_vn_slot() */
00154     if ((n = GD_rank(g)[r - 1].v[0]))
00155         ypos = ND_coord_i(n).y - GD_rank(g)[r - 1].ht1;
00156     else {
00157         n = GD_rank(g)[r].v[0];
00158         ypos = ND_coord_i(n).y + GD_rank(g)[r].ht2 + GD_ranksep(g);
00159     }
00160     vn = make_vn_slot(g, r - 1, place);
00161     dimen = ED_label(e)->dimen;
00162     if (GD_flip(g)) {
00163         double f = dimen.x;
00164         dimen.x = dimen.y;
00165         dimen.y = f;
00166     }
00167     ND_ht_i(vn) = dimen.y;
00168     h2 = ND_ht_i(vn) / 2;
00169     ND_lw_i(vn) = ND_rw_i(vn) = dimen.x / 2;
00170     ND_label(vn) = ED_label(e);
00171     ND_coord_i(vn).y = ypos + h2;
00172     ve = virtual_edge(vn, e->tail, e);  /* was NULL? */
00173     ED_tail_port(ve).p.x = -ND_lw_i(vn);
00174     ED_head_port(ve).p.x = ND_rw_i(e->tail);
00175     ED_edge_type(ve) = FLATORDER;
00176     ve = virtual_edge(vn, e->head, e);
00177     ED_tail_port(ve).p.x = ND_rw_i(vn);
00178     ED_head_port(ve).p.x = ND_lw_i(e->head);
00179     ED_edge_type(ve) = FLATORDER;
00180     /* another assumed symmetry of ht1/ht2 of a label node */
00181     if (GD_rank(g)[r - 1].ht1 < h2)
00182         GD_rank(g)[r - 1].ht1 = h2;
00183     if (GD_rank(g)[r - 1].ht2 < h2)
00184         GD_rank(g)[r - 1].ht2 = h2;
00185     ND_alg(vn) = e;
00186 }
00187 
00188 static void abomination(graph_t * g)
00189 {
00190     int r;
00191     rank_t *rptr;
00192 
00193     assert(GD_minrank(g) == 0);
00194     /* 3 = one for new rank, one for sentinel, one for off-by-one */
00195     r = GD_maxrank(g) + 3;
00196     rptr = ALLOC(r, GD_rank(g), rank_t);
00197     GD_rank(g) = rptr + 1;
00198     for (r = GD_maxrank(g); r >= 0; r--)
00199         GD_rank(g)[r] = GD_rank(g)[r - 1];
00200     GD_rank(g)[r].n = GD_rank(g)[0].an = 0;
00201     GD_rank(g)[r].v = GD_rank(g)[0].av = N_NEW(2, node_t *);
00202     GD_rank(g)[r].flat = NULL;
00203     GD_rank(g)[r].ht1 = GD_rank(g)[r].ht2 = 1;
00204     GD_rank(g)[r].pht1 = GD_rank(g)[r].pht2 = 1;
00205     GD_minrank(g)--;
00206 }
00207 
00208 /* flatAdjacent:
00209  * Return true if tn and hn are adjacent. 
00210  * Assume e is flat.
00211  */
00212 static int
00213 flatAdjacent (edge_t* e)
00214 {
00215     node_t* tn = e->tail;
00216     node_t* hn = e->head;
00217     int i, lo, hi;
00218     node_t* n;
00219     rank_t *rank;
00220 
00221     if (ND_order(tn) < ND_order(hn)) {
00222         lo = ND_order(tn);
00223         hi = ND_order(hn);
00224     }
00225     else {
00226         lo = ND_order(hn);
00227         hi = ND_order(tn);
00228     }
00229     rank = &(GD_rank(tn->graph)[ND_rank(tn)]);
00230     for (i = lo + 1; i < hi; i++) {
00231         n = rank->v[i];
00232         if ((ND_node_type(n) == VIRTUAL && ND_label(n)) || 
00233              ND_node_type(n) == NORMAL)
00234             break;
00235     }
00236     return (i == hi);
00237 }
00238  
00239 /* flat_edges:
00240  * Process flat edges.
00241  * First, mark flat edges as having adjacent endpoints or not.
00242  *
00243  * Second, if there are edge labels, nodes are placed on ranks 0,2,4,...
00244  * If we have a labeled flat edge on rank 0, add a rank -1.
00245  *
00246  * Finally, create label information. Add a virtual label node in the 
00247  * previous rank for each labeled, non-adjacent flat edge. If this is 
00248  * done for any edge, return true, so that main code will reset y coords.
00249  * For labeled adjacent flat edges, store label width in representative edge.
00250  * FIX: We should take into account any extra height needed for the latter
00251  * labels.
00252  * 
00253  * We leave equivalent flat edges in ND_other. Their ED_virt field should
00254  * still point to the class representative.
00255  */
00256 int 
00257 flat_edges(graph_t * g)
00258 {
00259     int i, j, reset = FALSE;
00260     node_t *n;
00261     edge_t *e;
00262     int found = FALSE;
00263 
00264     for (n = GD_nlist(g); n; n = ND_next(n)) {
00265         if (!ND_flat_out(n).list) continue; 
00266         for (j = 0; (e = ND_flat_out(n).list[j]); j++) {
00267             if (flatAdjacent (e)) ED_adjacent(e) = 1;
00268         }
00269     }
00270 
00271     if ((GD_rank(g)[0].flat) || (GD_n_cluster(g) > 0)) {
00272         for (i = 0; (n = GD_rank(g)[0].v[i]); i++) {
00273             for (j = 0; (e = ND_flat_in(n).list[j]); j++) {
00274                 if ((ED_label(e)) && !ED_adjacent(e)) {
00275                     abomination(g);
00276                     found = TRUE;
00277                     break;
00278                 }
00279             }
00280             if (found)
00281                 break;
00282         }
00283     }
00284 
00285     rec_save_vlists(g);
00286     for (n = GD_nlist(g); n; n = ND_next(n)) {
00287           /* if n is the tail of any flat edge, one will be in flat_out */
00288         if (ND_flat_out(n).list) {
00289             for (i = 0; (e = ND_flat_out(n).list[i]); i++) {
00290                 if (ED_label(e)) {
00291                     if (ED_adjacent(e)) {
00292                         if (GD_flip(g)) ED_dist(e) = ED_label(e)->dimen.y;
00293                         else ED_dist(e) = ED_label(e)->dimen.x; 
00294                     }
00295                     else {
00296                         reset = TRUE;
00297                         flat_node(e);
00298                     }
00299                 }
00300             }
00301                 /* look for other flat edges with labels */
00302             for (j = 0; j < ND_other(n).size; j++) {
00303                 edge_t* le;
00304                 e = ND_other(n).list[j];
00305                 if (ND_rank(e->tail) != ND_rank(e->head)) continue;
00306                 if (e->tail == e->head) continue; /* skip loops */
00307                 le = e;
00308                 while (ED_to_virt(le)) le = ED_to_virt(le);
00309                 ED_adjacent(e) = ED_adjacent(le); 
00310                 if (ED_label(e)) {
00311                     if (ED_adjacent(e)) {
00312                         double lw;
00313                         if (GD_flip(g)) lw = ED_label(e)->dimen.y;
00314                         else lw = ED_label(e)->dimen.x; 
00315                         ED_dist(le) = MAX(lw,ED_dist(le));
00316                     }
00317                     else {
00318                         reset = TRUE;
00319                         flat_node(e);
00320                     }
00321                 }
00322             }
00323         }
00324     }
00325     if (reset)
00326         rec_reset_vlists(g);
00327     return reset;
00328 }

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