2
This software may only be used by you under license from AT&T Corp.
3
("AT&T"). A copy of AT&T's Source Code Agreement is available at
4
AT&T's Internet website having the URL:
5
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
6
If you received this software without first entering into a license
7
with AT&T, you have an infringing copy of this software and cannot use
8
it without violating AT&T's intellectual property rights.
12
/* classify edges for mincross/nodepos/splines, using given ranks */
20
void class2(graph_t* g)
28
g->u.n_nodes = 0; /* new */
31
for (c = 1; c <= g->u.n_cluster; c++)
32
build_skeleton(g,g->u.clust[c]);
33
for (n = agfstnode(g); n; n = agnxtnode(g,n))
34
for (e = agfstout(g,n); e; e = agnxtout(g,e)) {
35
if (e->head->u.weight_class <= 2) e->head->u.weight_class++;
36
if (e->tail->u.weight_class <= 2) e->tail->u.weight_class++;
39
for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
40
if ((n->u.clust == NULL) && (n == UF_find(n))) {fast_node(g,n); g->u.n_nodes++;}
42
for (e = agfstout(g,n); e; e = agnxtout(g,e)) {
44
/* already processed */
45
if (e->u.to_virt) continue;
47
/* edges involving sub-clusters of g */
48
if (is_cluster_edge(e)) {
49
/* following is new cluster multi-edge code */
50
if (mergeable(prev,e)) {
51
if (prev->u.to_virt) {
52
merge_chain(g,e,prev->u.to_virt,FALSE);
55
else if (e->tail->u.rank == e->head->u.rank) {
59
/* else is an intra-cluster edge */
66
/* merge multi-edges */
67
if (prev && (e->tail == prev->tail) && (e->head == prev->head)) {
68
if (e->tail->u.rank == e->head->u.rank) {
73
if ((e->u.label == NULL) && (prev->u.label == NULL) && ports_eq(e,prev)) {
75
e->u.edge_type = IGNORED;
77
merge_chain(g,e,prev->u.to_virt,TRUE);
82
/* parallel edges with different labels fall through here */
86
if (e->tail == e->head) {
95
/* non-leader leaf nodes */
96
if ((e->tail != t) || (e->head != h)) {
97
/* ### need to merge stuff */
103
if (e->tail->u.rank == e->head->u.rank) {
110
if (e->head->u.rank > e->tail->u.rank) {
111
make_chain(g,e->tail,e->head,e);
119
if ((opp = agfindedge(g,e->head,e->tail))) {
120
/* shadows a forward edge */
121
if (opp->u.to_virt == NULL)
122
make_chain(g,opp->tail,opp->head,opp);
123
if ((e->u.label == NULL) && (opp->u.label == NULL) && ports_eq(e,opp)) {
125
e->u.edge_type = IGNORED;
126
opp->u.conc_opp_flag = TRUE;
128
else{ /* see above. this is getting out of hand */
130
merge_chain(g,e,opp->u.to_virt,TRUE);
135
make_chain(g,e->head,e->tail,e);
140
/* since decompose() is not called on subgraphs */
142
g->u.comp.list = ALLOC(1,g->u.comp.list,node_t*);
143
g->u.comp.list[0] = g->u.nlist;
148
label_vnode(graph_t* g, edge_t* orig)
153
dimen = orig->u.label->dimen;
155
v->u.label = orig->u.label;
156
v->u.lw = v->graph->u.nodesep;
157
if (!orig->u.label_ontop) {
158
if (g->u.left_to_right) {
159
v->u.ht = POINTS(dimen.x); v->u.rw = POINTS(dimen.y);
162
v->u.ht = POINTS(dimen.y); v->u.rw = POINTS(dimen.x);
169
plain_vnode(graph_t* g, edge_t* orig)
178
void incr_width(graph_t* g, node_t* v)
180
int width = g->u.nodesep / 2;
185
void make_chain(graph_t *g, node_t *from, node_t *to, edge_t *orig)
192
if (orig->u.label) label_rank = (from->u.rank + to->u.rank) / 2;
193
else label_rank = -1;
194
assert(orig->u.to_virt == NULL);
195
for (r = from->u.rank + 1; r <= to->u.rank; r++) {
196
if (r < to->u.rank) {
197
if (r == label_rank) v = label_vnode(g,orig);
198
else v = plain_vnode(g,orig);
202
e = virtual_edge(u,v,orig);
206
assert(orig->u.to_virt != NULL);
209
void merge_chain(graph_t *g, edge_t *e, edge_t *f, int flag)
212
int lastrank = MAX(e->tail->u.rank,e->head->u.rank);
214
assert(e->u.to_virt == NULL);
218
/* interclust multi-edges are not counted now */
219
if (flag) rep->u.count += e->u.count;
220
rep->u.xpenalty += e->u.xpenalty;
221
rep->u.weight += e->u.weight;
222
if (rep->head->u.rank == lastrank) break;
223
incr_width(g,rep->head);
224
rep = rep->head->u.out.list[0];
229
leader_of(graph_t* g, node_t* v)
234
if (v->u.ranktype != CLUSTER) {
235
/*assert(v == UF_find(v)); could be leaf, so comment out */
240
rv = clust->u.rankleader[v->u.rank];
245
void interclrep(graph_t* g, edge_t* e)
250
t = leader_of(g,e->tail);
251
h = leader_of(g,e->head);
252
if (t->u.rank > h->u.rank) {node_t *t0 = t; t = h; h = t0;}
253
if (t->u.clust != h->u.clust) {
254
if ((ve = find_fast_edge(t,h))) {
255
merge_chain(g,e,ve,TRUE);
258
if (t->u.rank == h->u.rank) return;
261
/* mark as cluster edge */
262
for (ve = e->u.to_virt; ve && (ve->head->u.rank <= h->u.rank);
263
ve = ve->head->u.out.list[0]) ve->u.edge_type = CLUSTER_EDGE;
265
/* else ignore intra-cluster edges at this point */
268
int is_cluster_edge(edge_t* e)
270
return ((e->tail->u.ranktype==CLUSTER) || (e->head->u.ranktype==CLUSTER));
273
int mergeable(edge_t *e, edge_t *f)
275
if (e && f && (e->tail == f->tail) && (e->head == f->head) &&
276
(e->u.label == f->u.label) && ports_eq(e,f))