1
|
/*******************************************************************************
|
2
|
* Copyright (c) 2003, 2010 IBM Corporation and others.
|
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
|
* http://www.eclipse.org/legal/epl-v10.html
|
7
|
*
|
8
|
* Contributors:
|
9
|
* IBM Corporation - initial API and implementation
|
10
|
*******************************************************************************/
|
11
|
package org.eclipse.draw2d.graph;
|
12
|
|
13
|
import java.util.ArrayList;
|
14
|
import java.util.List;
|
15
|
import java.util.Stack;
|
16
|
|
17
|
/**
|
18
|
* Assigns a valid rank assignment to all nodes based on their edges. The
|
19
|
* assignment is not optimal in that it does not provide the minimum global
|
20
|
* length of edge lengths.
|
21
|
*
|
22
|
* @author Randy Hudson
|
23
|
* @since 2.1.2
|
24
|
*/
|
25
|
class InitialRankSolver extends GraphVisitor {
|
26
|
|
27
|
protected DirectedGraph graph;
|
28
|
protected EdgeList candidates = new EdgeList();
|
29
|
protected NodeList members = new NodeList();
|
30
|
|
31
|
public void visit(DirectedGraph graph) {
|
32
|
this.graph = graph;
|
33
|
graph.edges.resetFlags(false);
|
34
|
graph.nodes.resetFlags();
|
35
|
solve();
|
36
|
}
|
37
|
|
38
|
protected void solve() {
|
39
|
if (graph.nodes.size() == 0)
|
40
|
return;
|
41
|
NodeList unranked = new NodeList(graph.nodes);
|
42
|
NodeList rankMe = new NodeList();
|
43
|
Node node;
|
44
|
int i;
|
45
|
while (!unranked.isEmpty()) {
|
46
|
rankMe.clear();
|
47
|
for (i = 0; i < unranked.size();) {
|
48
|
node = unranked.getNode(i);
|
49
|
if (node.incoming.isCompletelyFlagged()) {
|
50
|
rankMe.add(node);
|
51
|
unranked.remove(i);
|
52
|
} else
|
53
|
i++;
|
54
|
}
|
55
|
if (rankMe.size() == 0)
|
56
|
throw new RuntimeException("Cycle detected in graph"); //$NON-NLS-1$
|
57
|
for (i = 0; i < rankMe.size(); i++) {
|
58
|
node = rankMe.getNode(i);
|
59
|
assignMinimumRank(node);
|
60
|
node.outgoing.setFlags(true);
|
61
|
}
|
62
|
}
|
63
|
|
64
|
connectForest();
|
65
|
}
|
66
|
|
67
|
private void connectForest() {
|
68
|
List forest = new ArrayList();
|
69
|
Stack stack = new Stack();
|
70
|
NodeList tree;
|
71
|
graph.nodes.resetFlags();
|
72
|
for (int i = 0; i < graph.nodes.size(); i++) {
|
73
|
Node neighbor, n = graph.nodes.getNode(i);
|
74
|
if (n.flag)
|
75
|
continue;
|
76
|
tree = new NodeList();
|
77
|
stack.push(n);
|
78
|
while (!stack.isEmpty()) {
|
79
|
n = (Node) stack.pop();
|
80
|
n.flag = true;
|
81
|
tree.add(n);
|
82
|
for (int s = 0; s < n.incoming.size(); s++) {
|
83
|
neighbor = n.incoming.getEdge(s).source;
|
84
|
if (!neighbor.flag)
|
85
|
stack.push(neighbor);
|
86
|
}
|
87
|
for (int s = 0; s < n.outgoing.size(); s++) {
|
88
|
neighbor = n.outgoing.getEdge(s).target;
|
89
|
if (!neighbor.flag)
|
90
|
stack.push(neighbor);
|
91
|
}
|
92
|
}
|
93
|
forest.add(tree);
|
94
|
}
|
95
|
|
96
|
if (forest.size() > 1) {
|
97
|
// connect the forest
|
98
|
graph.forestRoot = new Node("the forest root"); //$NON-NLS-1$
|
99
|
graph.nodes.add(graph.forestRoot);
|
100
|
for (int i = 0; i < forest.size(); i++) {
|
101
|
tree = (NodeList) forest.get(i);
|
102
|
graph.edges.add(new Edge(graph.forestRoot, tree.getNode(0), 0,
|
103
|
0));
|
104
|
}
|
105
|
}
|
106
|
}
|
107
|
|
108
|
private void assignMinimumRank(Node node) {
|
109
|
int rank = 0;
|
110
|
Edge e;
|
111
|
for (int i1 = 0; i1 < node.incoming.size(); i1++) {
|
112
|
e = node.incoming.getEdge(i1);
|
113
|
rank = Math.max(rank, e.delta + e.source.rank);
|
114
|
}
|
115
|
node.rank = rank;
|
116
|
}
|
117
|
|
118
|
}
|