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