Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
class2.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11
12/* classify edges for mincross/nodepos/splines, using given ranks */
13
14#include <dotgen/dot.h>
15#include <stdbool.h>
16#include <stdlib.h>
17#include <util/alloc.h>
18
19static node_t*
21{
22 node_t *v;
23 pointf dimen;
24
25 dimen = ED_label(orig)->dimen;
26 v = virtual_node(g);
27 ND_label(v) = ED_label(orig);
28 ND_lw(v) = GD_nodesep(agroot(v));
29 if (!ED_label_ontop(orig)) {
30 if (GD_flip(agroot(g))) {
31 ND_ht(v) = dimen.x;
32 ND_rw(v) = dimen.y;
33 } else {
34 ND_ht(v) = dimen.y;
35 ND_rw(v) = dimen.x;
36 }
37 }
38 return v;
39}
40
41static void
43{
44 int width = GD_nodesep(g) / 2;
45 ND_lw(v) += width;
46 ND_rw(v) += width;
47}
48
50 node_t *v;
51 v = virtual_node(g);
52 incr_width(g, v);
53 return v;
54}
55
56static node_t *leader_of(node_t * v) {
57 graph_t *clust;
58 node_t *rv;
59
60 if (ND_ranktype(v) != CLUSTER) {
61 rv = UF_find(v);
62 } else {
63 clust = ND_clust(v);
64 rv = GD_rankleader(clust)[ND_rank(v)];
65 }
66 return rv;
67}
68
69/* make_chain:
70 * Create chain of dummy nodes for edge orig.
71 */
72static void
73make_chain(graph_t * g, node_t * from, node_t * to, edge_t * orig)
74{
75 int r, label_rank;
76 node_t *u, *v;
77 edge_t *e;
78
79 u = from;
80 if (ED_label(orig))
81 label_rank = (ND_rank(from) + ND_rank(to)) / 2;
82 else
83 label_rank = -1;
84 assert(ED_to_virt(orig) == NULL);
85 for (r = ND_rank(from) + 1; r <= ND_rank(to); r++) {
86 if (r < ND_rank(to)) {
87 if (r == label_rank)
88 v = label_vnode(g, orig);
89 else
90 v = plain_vnode(g);
91 ND_rank(v) = r;
92 } else
93 v = to;
94 e = virtual_edge(u, v, orig);
96 u = v;
97 }
98 assert(ED_to_virt(orig) != NULL);
99}
100
101static void
103{
104 node_t *t, *h;
105 edge_t *ve;
106
107 t = leader_of(agtail(e));
108 h = leader_of(aghead(e));
109 if (ND_rank(t) > ND_rank(h)) {
110 node_t *t0 = t;
111 t = h;
112 h = t0;
113 }
114 if (ND_clust(t) != ND_clust(h)) {
115 if ((ve = find_fast_edge(t, h))) {
116 merge_chain(g, e, ve, true);
117 return;
118 }
119 if (ND_rank(t) == ND_rank(h))
120 return;
121 make_chain(g, t, h, e);
122
123 /* mark as cluster edge */
124 for (ve = ED_to_virt(e); ve && ND_rank(aghead(ve)) <= ND_rank(h);
125 ve = ND_out(aghead(ve)).list[0])
127 }
128 /* else ignore intra-cluster edges at this point */
129}
130
131static bool is_cluster_edge(edge_t *e) {
132 return ND_ranktype(agtail(e)) == CLUSTER || ND_ranktype(aghead(e)) == CLUSTER;
133}
134
135void merge_chain(graph_t *g, edge_t *e, edge_t *f, bool update_count) {
136 edge_t *rep;
137 int lastrank = MAX(ND_rank(agtail(e)), ND_rank(aghead(e)));
138
139 assert(ED_to_virt(e) == NULL);
140 ED_to_virt(e) = f;
141 rep = f;
142 do {
143 /* interclust multi-edges are not counted now */
144 if (update_count)
145 ED_count(rep) += ED_count(e);
146 ED_xpenalty(rep) += ED_xpenalty(e);
147 ED_weight(rep) += ED_weight(e);
148 if (ND_rank(aghead(rep)) == lastrank)
149 break;
150 incr_width(g, aghead(rep));
151 rep = ND_out(aghead(rep)).list[0];
152 } while (rep);
153}
154
155bool mergeable(edge_t *e, edge_t *f) {
156 return e && f && agtail(e) == agtail(f) && aghead(e) == aghead(f) &&
157 ED_label(e) == ED_label(f) && ports_eq(e, f);
158}
159
161{
162 int c;
163 node_t *n, *t, *h;
164 edge_t *e, *prev, *opp;
165
166 GD_nlist(g) = NULL;
167
168 mark_clusters(g);
169 for (c = 1; c <= GD_n_cluster(g); c++)
170 build_skeleton(g, GD_clust(g)[c]);
171 for (n = agfstnode(g); n; n = agnxtnode(g, n))
172 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
173 if (ND_weight_class(aghead(e)) <= 2)
175 if (ND_weight_class(agtail(e)) <= 2)
177 }
178
179 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
180 if (ND_clust(n) == NULL && n == UF_find(n)) {
181 fast_node(g, n);
182 }
183 prev = NULL;
184 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
185
186 /* already processed */
187 if (ED_to_virt(e)) {
188 prev = e;
189 continue;
190 }
191
192 /* edges involving sub-clusters of g */
193 if (is_cluster_edge(e)) {
194 /* following is new cluster multi-edge code */
195 if (mergeable(prev, e)) {
196 if (ED_to_virt(prev)) {
197 merge_chain(g, e, ED_to_virt(prev), false);
198 other_edge(e);
199 } else if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
200 merge_oneway(e, prev);
201 other_edge(e);
202 }
203 /* else is an intra-cluster edge */
204 continue;
205 }
206 interclrep(g, e);
207 prev = e;
208 continue;
209 }
210 /* merge multi-edges */
211 if (prev && agtail(e) == agtail(prev) && aghead(e) == aghead(prev)) {
212 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
213 merge_oneway(e, prev);
214 other_edge(e);
215 continue;
216 }
217 if (ED_label(e) == NULL && ED_label(prev) == NULL
218 && ports_eq(e, prev)) {
219 if (Concentrate)
221 else {
222 merge_chain(g, e, ED_to_virt(prev), true);
223 other_edge(e);
224 }
225 continue;
226 }
227 /* parallel edges with different labels fall through here */
228 }
229
230 /* self edges */
231 if (agtail(e) == aghead(e)) {
232 other_edge(e);
233 prev = e;
234 continue;
235 }
236
237 t = UF_find(agtail(e));
238 h = UF_find(aghead(e));
239
240 /* non-leader leaf nodes */
241 if (agtail(e) != t || aghead(e) != h) {
242 /* FIX need to merge stuff */
243 continue;
244 }
245
246
247 /* flat edges */
248 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
249 flat_edge(g, e);
250 prev = e;
251 continue;
252 }
253
254 /* forward edges */
255 if (ND_rank(aghead(e)) > ND_rank(agtail(e))) {
256 make_chain(g, agtail(e), aghead(e), e);
257 prev = e;
258 continue;
259 }
260
261 /* backward edges */
262 else {
263 /* avoid when opp==e in undirected graph */
264 for (opp = agfstout(g, aghead(e)); opp != NULL; opp = agnxtout(g, opp)) {
265 if (aghead(opp) != agtail(e) || aghead(opp) == aghead(e) ||
266 ED_edge_type(opp) == IGNORED) {
267 continue;
268 }
269 /* shadows a forward edge */
270 if (ED_to_virt(opp) == NULL)
271 make_chain(g, agtail(opp), aghead(opp), opp);
272 if (ED_label(e) == NULL && ED_label(opp) == NULL
273 && ports_eq(e, opp)) {
274 if (Concentrate) {
276 ED_conc_opp_flag(opp) = true;
277 } else { /* see above. this is getting out of hand */
278 other_edge(e);
279 merge_chain(g, e, ED_to_virt(opp), true);
280 }
281 break;
282 }
283 }
284 if (opp != NULL) {
285 continue;
286 }
287 make_chain(g, aghead(e), agtail(e), e);
288 prev = e;
289 }
290 }
291 }
292 /* since decompose() is not called on subgraphs */
293 if (g != dot_root(g)) {
294 free(GD_comp(g).list);
295 GD_comp(g).list = gv_alloc(sizeof(node_t *));
296 GD_comp(g).list[0] = GD_nlist(g);
297 }
298}
299
Memory allocation wrappers that exit on failure.
static void * gv_alloc(size_t size)
Definition alloc.h:47
static void make_chain(graph_t *g, node_t *from, node_t *to, edge_t *orig)
Definition class2.c:73
void merge_chain(graph_t *g, edge_t *e, edge_t *f, bool update_count)
Definition class2.c:135
static void interclrep(graph_t *g, edge_t *e)
Definition class2.c:102
static node_t * leader_of(node_t *v)
Definition class2.c:56
static node_t * plain_vnode(graph_t *g)
Definition class2.c:49
static bool is_cluster_edge(edge_t *e)
Definition class2.c:131
void class2(graph_t *g)
Definition class2.c:160
bool mergeable(edge_t *e, edge_t *f)
Definition class2.c:155
static node_t * label_vnode(graph_t *g, edge_t *orig)
Definition class2.c:20
static void incr_width(graph_t *g, node_t *v)
Definition class2.c:42
node_t * UF_find(node_t *n)
Definition utils.c:98
#define IGNORED
Definition const.h:30
#define CLUSTER_EDGE
Definition const.h:29
#define CLUSTER
Definition const.h:40
Agraph_t * dot_root(void *p)
Definition dotinit.c:496
void other_edge(Agedge_t *)
Definition fastgr.c:115
Agedge_t * virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *)
Definition fastgr.c:172
void virtual_weight(Agedge_t *)
Definition mincross.c:1770
void flat_edge(Agraph_t *, Agedge_t *)
Definition fastgr.c:217
void fast_node(Agraph_t *, Agnode_t *)
Definition fastgr.c:177
void merge_oneway(Agedge_t *, Agedge_t *)
Definition fastgr.c:291
int ports_eq(edge_t *, edge_t *)
Definition position.c:1011
Agedge_t * find_fast_edge(Agnode_t *, Agnode_t *)
Definition fastgr.c:41
Agnode_t * virtual_node(Agraph_t *)
Definition fastgr.c:202
bool Concentrate
Definition globals.h:58
void free(void *)
node NULL
Definition grammar.y:163
#define ED_conc_opp_flag(e)
Definition types.h:579
#define ED_label_ontop(e)
Definition types.h:591
#define ED_xpenalty(e)
Definition types.h:601
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
#define ED_count(e)
Definition types.h:580
#define agtail(e)
Definition cgraph.h:880
#define ED_edge_type(e)
Definition types.h:582
#define ED_weight(e)
Definition types.h:603
#define aghead(e)
Definition cgraph.h:881
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
#define ED_label(e)
Definition types.h:589
#define ED_to_virt(e)
Definition types.h:599
#define GD_clust(g)
Definition types.h:360
#define GD_nlist(g)
Definition types.h:393
#define GD_n_cluster(g)
Definition types.h:389
#define GD_comp(g)
Definition types.h:362
#define GD_nodesep(g)
Definition types.h:394
#define GD_flip(g)
Definition types.h:378
#define GD_rankleader(g)
Definition types.h:396
#define ND_rank(n)
Definition types.h:523
#define ND_ht(n)
Definition types.h:500
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#define ND_clust(n)
Definition types.h:489
#define ND_label(n)
Definition types.h:502
#define ND_rw(n)
Definition types.h:525
#define ND_lw(n)
Definition types.h:506
#define ND_weight_class(n)
Definition types.h:535
#define ND_ranktype(n)
Definition types.h:524
#define ND_out(n)
Definition types.h:515
Agraph_t * agroot(void *obj)
Definition obj.c:168
$2 u p prev
Definition htmlparse.y:297
void build_skeleton(graph_t *g, graph_t *subg)
Definition cluster.c:352
void mark_clusters(graph_t *g)
Definition cluster.c:308
graph or subgraph
Definition cgraph.h:425
double x
Definition geom.h:29
double y
Definition geom.h:29
#define MAX(a, b)
Definition write.c:31