|
Graphviz
2.31.20130523.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 /* 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
1.7.5