1
2
3
4
5
6
7
8
9
10
11
12 package edu.uci.ics.jung.algorithms.layout;
13
14 import java.awt.Dimension;
15 import java.awt.geom.Point2D;
16 import java.util.HashMap;
17 import java.util.Map;
18
19 import edu.uci.ics.jung.graph.Graph;
20 import edu.uci.ics.jung.graph.util.Pair;
21
22
23
24
25
26
27
28
29
30
31
32
33 public class DAGLayout<V, E> extends SpringLayout<V,E> {
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 private Map<V,Number> minLevels = new HashMap<V,Number>();
50
51 static int graphHeight;
52 static int numRoots;
53 final double SPACEFACTOR = 1.3;
54
55 final double LEVELATTRACTIONRATE = 0.8;
56
57
58
59
60
61
62
63
64
65 final double MSV_THRESHOLD = 10.0;
66 double meanSquareVel;
67 boolean stoppingIncrements = false;
68 int incrementsLeft;
69 final int COOL_DOWN_INCREMENTS = 200;
70
71 public DAGLayout(Graph<V,E> g) {
72 super(g);
73 }
74
75
76
77
78
79
80 public void setRoot() {
81 numRoots = 0;
82 Graph<V, E> g = getGraph();
83 for(V v : g.getVertices()) {
84 if (g.getSuccessors(v).isEmpty()) {
85 setRoot(v);
86 numRoots++;
87 }
88 }
89 }
90
91
92
93
94
95 public void setRoot(V v) {
96 minLevels.put(v, new Integer(0));
97
98 propagateMinimumLevel(v);
99 }
100
101
102
103
104
105
106
107
108 public void propagateMinimumLevel(V v) {
109 int level = minLevels.get(v).intValue();
110 for(V child : getGraph().getPredecessors(v)) {
111 int oldLevel, newLevel;
112 Number o = minLevels.get(child);
113 if (o != null)
114 oldLevel = o.intValue();
115 else
116 oldLevel = 0;
117 newLevel = Math.max(oldLevel, level + 1);
118 minLevels.put(child, new Integer(newLevel));
119
120 if (newLevel > graphHeight)
121 graphHeight = newLevel;
122 propagateMinimumLevel(child);
123 }
124 }
125
126
127
128
129
130
131
132
133 private void initializeLocation(
134 V v,
135 Point2D coord,
136 Dimension d) {
137
138 int level = minLevels.get(v).intValue();
139 int minY = (int) (level * d.getHeight() / (graphHeight * SPACEFACTOR));
140 double x = Math.random() * d.getWidth();
141 double y = Math.random() * (d.getHeight() - minY) + minY;
142 coord.setLocation(x,y);
143 }
144
145 @Override
146 public void setSize(Dimension size) {
147 super.setSize(size);
148 for(V v : getGraph().getVertices()) {
149 initializeLocation(v,apply(v),getSize());
150 }
151 }
152
153
154
155
156 @Override
157 public void initialize() {
158 super.initialize();
159 setRoot();
160 }
161
162
163
164
165
166
167 @Override
168 protected void moveNodes() {
169
170 double oldMSV = meanSquareVel;
171 meanSquareVel = 0;
172
173 synchronized (getSize()) {
174
175 for(V v : getGraph().getVertices()) {
176 if (isLocked(v))
177 continue;
178 SpringLayout.SpringVertexData vd = springVertexData.getUnchecked(v);
179 Point2D xyd = apply(v);
180
181 int width = getSize().width;
182 int height = getSize().height;
183
184
185 int level =
186 minLevels.get(v).intValue();
187 int minY = (int) (level * height / (graphHeight * SPACEFACTOR));
188 int maxY =
189 level == 0
190 ? (int) (height / (graphHeight * SPACEFACTOR * 2))
191 : height;
192
193
194 vd.dx += 2 * vd.repulsiondx + vd.edgedx;
195 vd.dy += vd.repulsiondy + vd.edgedy;
196
197
198
199 double delta = xyd.getY() - minY;
200 vd.dy -= delta * LEVELATTRACTIONRATE;
201 if (level == 0)
202 vd.dy -= delta * LEVELATTRACTIONRATE;
203
204
205
206 meanSquareVel += (vd.dx * vd.dx + vd.dy * vd.dy);
207
208
209 xyd.setLocation(xyd.getX()+Math.max(-5, Math.min(5, vd.dx)) , xyd.getY()+Math.max(-5, Math.min(5, vd.dy)) );
210
211 if (xyd.getX() < 0) {
212 xyd.setLocation(0, xyd.getY());
213 } else if (xyd.getX() > width) {
214 xyd.setLocation(width, xyd.getY());
215 }
216
217
218 if (xyd.getY() < minY) {
219 xyd.setLocation(xyd.getX(), minY);
220
221 } else if (xyd.getY() > maxY) {
222 xyd.setLocation(xyd.getX(), maxY);
223 }
224
225
226
227 if (numRoots == 1 && level == 0) {
228 xyd.setLocation(width/2, xyd.getY());
229 }
230 }
231 }
232
233 if (!stoppingIncrements
234 && Math.abs(meanSquareVel - oldMSV) < MSV_THRESHOLD) {
235 stoppingIncrements = true;
236 incrementsLeft = COOL_DOWN_INCREMENTS;
237 } else if (
238 stoppingIncrements
239 && Math.abs(meanSquareVel - oldMSV) <= MSV_THRESHOLD) {
240 incrementsLeft--;
241 if (incrementsLeft <= 0)
242 incrementsLeft = 0;
243 }
244 }
245
246
247
248
249 @Override
250 public boolean done() {
251 if (stoppingIncrements && incrementsLeft == 0)
252 return true;
253 else
254 return false;
255 }
256
257
258
259
260
261
262
263
264 @Override
265 public void setLocation(V picked, double x, double y) {
266 Point2D coord = apply(picked);
267 coord.setLocation(x,y);
268 stoppingIncrements = false;
269 }
270
271
272
273
274
275
276
277 @Override
278 public void setLocation(V picked, Point2D p) {
279 setLocation(picked, p.getX(), p.getY());
280 }
281
282
283
284
285
286
287 @Override
288 protected void relaxEdges() {
289 for(E e : getGraph().getEdges()) {
290 Pair<V> endpoints = getGraph().getEndpoints(e);
291 V v1 = endpoints.getFirst();
292 V v2 = endpoints.getSecond();
293
294 Point2D p1 = apply(v1);
295 Point2D p2 = apply(v2);
296 double vx = p1.getX() - p2.getX();
297 double vy = p1.getY() - p2.getY();
298 double len = Math.sqrt(vx * vx + vy * vy);
299
300
301 int level1 =
302 minLevels.get(v1).intValue();
303 int level2 =
304 minLevels.get(v2).intValue();
305
306 double desiredLen = lengthFunction.apply(e);
307
308
309 len = (len == 0) ? .0001 : len;
310
311
312
313
314
315
316 double f = force_multiplier * (desiredLen - len) / len;
317
318 f = f * Math.pow(stretch / 100.0,
319 (getGraph().degree(v1) + getGraph().degree(v2) -2));
320
321
322
323 if (level1 != level2)
324 f = f / Math.pow(Math.abs(level2 - level1), 1.5);
325
326
327
328 double dx = f * vx;
329 double dy = f * vy;
330 SpringVertexData v1D, v2D;
331 v1D = springVertexData.getUnchecked(v1);
332 v2D = springVertexData.getUnchecked(v2);
333
334 v1D.edgedx += dx;
335 v1D.edgedy += dy;
336 v2D.edgedx += -dx;
337 v2D.edgedy += -dy;
338 }
339 }
340 }