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