Graphviz 13.0.0~dev.20250210.0415
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#include <util/gv_math.h>
19
20static node_t*
22{
23 node_t *v;
24 pointf dimen;
25
26 dimen = ED_label(orig)->dimen;
27 v = virtual_node(g);
28 ND_label(v) = ED_label(orig);
29 ND_lw(v) = GD_nodesep(agroot(v));
30 if (!ED_label_ontop(orig)) {
31 if (GD_flip(agroot(g))) {
32 ND_ht(v) = dimen.x;
33 ND_rw(v) = dimen.y;
34 } else {
35 ND_ht(v) = dimen.y;
36 ND_rw(v) = dimen.x;
37 }
38 }
39 return v;
40}
41
42static void
44{
45 int width = GD_nodesep(g) / 2;
46 ND_lw(v) += width;
47 ND_rw(v) += width;
48}
49
51 node_t *v;
52 v = virtual_node(g);
53 incr_width(g, v);
54 return v;
55}
56
57static node_t *leader_of(node_t * v) {
58 graph_t *clust;
59 node_t *rv;
60
61 if (ND_ranktype(v) != CLUSTER) {
62 rv = UF_find(v);
63 } else {
64 clust = ND_clust(v);
65 rv = GD_rankleader(clust)[ND_rank(v)];
66 }
67 return rv;
68}
69
70/* make_chain:
71 * Create chain of dummy nodes for edge orig.
72 */
73static void
74make_chain(graph_t * g, node_t * from, node_t * to, edge_t * orig)
75{
76 int r, label_rank;
77 node_t *u, *v;
78 edge_t *e;
79
80 u = from;
81 if (ED_label(orig))
82 label_rank = (ND_rank(from) + ND_rank(to)) / 2;
83 else
84 label_rank = -1;
85 assert(ED_to_virt(orig) == NULL);
86 for (r = ND_rank(from) + 1; r <= ND_rank(to); r++) {
87 if (r < ND_rank(to)) {
88 if (r == label_rank)
89 v = label_vnode(g, orig);
90 else
91 v = plain_vnode(g);
92 ND_rank(v) = r;
93 } else
94 v = to;
95 e = virtual_edge(u, v, orig);
97 u = v;
98 }
99 assert(ED_to_virt(orig) != NULL);
100}
101
102static void
104{
105 node_t *t, *h;
106 edge_t *ve;
107
108 t = leader_of(agtail(e));
109 h = leader_of(aghead(e));
110 if (ND_rank(t) > ND_rank(h)) {
111 SWAP(&t, &h);
112 }
113 if (ND_clust(t) != ND_clust(h)) {
114 if ((ve = find_fast_edge(t, h))) {
115 merge_chain(g, e, ve, true);
116 return;
117 }
118 if (ND_rank(t) == ND_rank(h))
119 return;
120 make_chain(g, t, h, e);
121
122 /* mark as cluster edge */
123 for (ve = ED_to_virt(e); ve && ND_rank(aghead(ve)) <= ND_rank(h);
124 ve = ND_out(aghead(ve)).list[0])
126 }
127 /* else ignore intra-cluster edges at this point */
128}
129
130static bool is_cluster_edge(edge_t *e) {
131 return ND_ranktype(agtail(e)) == CLUSTER || ND_ranktype(aghead(e)) == CLUSTER;
132}
133
134void merge_chain(graph_t *g, edge_t *e, edge_t *f, bool update_count) {
135 edge_t *rep;
136 int lastrank = MAX(ND_rank(agtail(e)), ND_rank(aghead(e)));
137
138 assert(ED_to_virt(e) == NULL);
139 ED_to_virt(e) = f;
140 rep = f;
141 do {
142 /* interclust multi-edges are not counted now */
143 if (update_count)
144 ED_count(rep) += ED_count(e);
145 ED_xpenalty(rep) += ED_xpenalty(e);
146 ED_weight(rep) += ED_weight(e);
147 if (ND_rank(aghead(rep)) == lastrank)
148 break;
149 incr_width(g, aghead(rep));
150 rep = ND_out(aghead(rep)).list[0];
151 } while (rep);
152}
153
154bool mergeable(edge_t *e, edge_t *f) {
155 return e && f && agtail(e) == agtail(f) && aghead(e) == aghead(f) &&
156 ED_label(e) == ED_label(f) && ports_eq(e, f);
157}
158
160{
161 int c;
162 node_t *n, *t, *h;
163 edge_t *e, *prev, *opp;
164
165 GD_nlist(g) = NULL;
166
167 mark_clusters(g);
168 for (c = 1; c <= GD_n_cluster(g); c++)
169 build_skeleton(g, GD_clust(g)[c]);
170 for (n = agfstnode(g); n; n = agnxtnode(g, n))
171 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
172 if (ND_weight_class(aghead(e)) <= 2)
174 if (ND_weight_class(agtail(e)) <= 2)
176 }
177
178 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
179 if (ND_clust(n) == NULL && n == UF_find(n)) {
180 fast_node(g, n);
181 }
182 prev = NULL;
183 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
184
185 /* already processed */
186 if (ED_to_virt(e)) {
187 prev = e;
188 continue;
189 }
190
191 /* edges involving sub-clusters of g */
192 if (is_cluster_edge(e)) {
193 /* following is new cluster multi-edge code */
194 if (mergeable(prev, e)) {
195 if (ED_to_virt(prev)) {
196 merge_chain(g, e, ED_to_virt(prev), false);
197 other_edge(e);
198 } else if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
199 merge_oneway(e, prev);
200 other_edge(e);
201 }
202 /* else is an intra-cluster edge */
203 continue;
204 }
205 interclrep(g, e);
206 prev = e;
207 continue;
208 }
209 /* merge multi-edges */
210 if (prev && agtail(e) == agtail(prev) && aghead(e) == aghead(prev)) {
211 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
212 merge_oneway(e, prev);
213 other_edge(e);
214 continue;
215 }
216 if (ED_label(e) == NULL && ED_label(prev) == NULL
217 && ports_eq(e, prev)) {
218 if (Concentrate)
220 else {
221 merge_chain(g, e, ED_to_virt(prev), true);
222 other_edge(e);
223 }
224 continue;
225 }
226 /* parallel edges with different labels fall through here */
227 }
228
229 /* self edges */
230 if (agtail(e) == aghead(e)) {
231 other_edge(e);
232 prev = e;
233 continue;
234 }
235
236 t = UF_find(agtail(e));
237 h = UF_find(aghead(e));
238
239 /* non-leader leaf nodes */
240 if (agtail(e) != t || aghead(e) != h) {
241 /* FIX need to merge stuff */
242 continue;
243 }
244
245
246 /* flat edges */
247 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
248 flat_edge(g, e);
249 prev = e;
250 continue;
251 }
252
253 /* forward edges */
254 if (ND_rank(aghead(e)) > ND_rank(agtail(e))) {
255 make_chain(g, agtail(e), aghead(e), e);
256 prev = e;
257 continue;
258 }
259
260 /* backward edges */
261 else {
262 /* avoid when opp==e in undirected graph */
263 for (opp = agfstout(g, aghead(e)); opp != NULL; opp = agnxtout(g, opp)) {
264 if (aghead(opp) != agtail(e) || aghead(opp) == aghead(e) ||
265 ED_edge_type(opp) == IGNORED) {
266 continue;
267 }
268 /* shadows a forward edge */
269 if (ED_to_virt(opp) == NULL)
270 make_chain(g, agtail(opp), aghead(opp), opp);
271 if (ED_label(e) == NULL && ED_label(opp) == NULL
272 && ports_eq(e, opp)) {
273 if (Concentrate) {
275 ED_conc_opp_flag(opp) = true;
276 } else { /* see above. this is getting out of hand */
277 other_edge(e);
278 merge_chain(g, e, ED_to_virt(opp), true);
279 }
280 break;
281 }
282 }
283 if (opp != NULL) {
284 continue;
285 }
286 make_chain(g, aghead(e), agtail(e), e);
287 prev = e;
288 }
289 }
290 }
291 /* since decompose() is not called on subgraphs */
292 if (g != dot_root(g)) {
293 free(GD_comp(g).list);
294 GD_comp(g).list = gv_alloc(sizeof(node_t *));
295 GD_comp(g).list[0] = GD_nlist(g);
296 }
297}
298
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:74
void merge_chain(graph_t *g, edge_t *e, edge_t *f, bool update_count)
Definition class2.c:134
static void interclrep(graph_t *g, edge_t *e)
Definition class2.c:103
static node_t * leader_of(node_t *v)
Definition class2.c:57
static node_t * plain_vnode(graph_t *g)
Definition class2.c:50
static bool is_cluster_edge(edge_t *e)
Definition class2.c:130
void class2(graph_t *g)
Definition class2.c:159
bool mergeable(edge_t *e, edge_t *f)
Definition class2.c:154
static node_t * label_vnode(graph_t *g, edge_t *orig)
Definition class2.c:21
static void incr_width(graph_t *g, node_t *v)
Definition class2.c:43
node_t * UF_find(node_t *n)
Definition utils.c:100
#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:506
void other_edge(Agedge_t *)
Definition fastgr.c:115
Agedge_t * virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *)
Definition fastgr.c:170
void virtual_weight(Agedge_t *)
Definition mincross.c:1763
void flat_edge(Agraph_t *, Agedge_t *)
Definition fastgr.c:215
void fast_node(Agraph_t *, Agnode_t *)
Definition fastgr.c:175
void merge_oneway(Agedge_t *, Agedge_t *)
Definition fastgr.c:289
int ports_eq(edge_t *, edge_t *)
Definition position.c:1008
Agedge_t * find_fast_edge(Agnode_t *, Agnode_t *)
Definition fastgr.c:41
Agnode_t * virtual_node(Agraph_t *)
Definition fastgr.c:200
bool Concentrate
Definition globals.h:59
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:883
#define ED_edge_type(e)
Definition types.h:582
#define ED_weight(e)
Definition types.h:603
#define aghead(e)
Definition cgraph.h:884
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
Arithmetic helper functions.
#define SWAP(a, b)
Definition gv_math.h:130
$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:424
double x
Definition geom.h:29
double y
Definition geom.h:29
#define MAX(a, b)
Definition write.c:31