1
2
3
4
5
6
7
8
9
10 package edu.uci.ics.jung.algorithms.layout3d;
11
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.ConcurrentModificationException;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18
19 import javax.vecmath.Point3f;
20 import javax.vecmath.Vector3f;
21
22 import org.apache.commons.collections15.Factory;
23 import org.apache.commons.collections15.map.LazyMap;
24
25 import edu.uci.ics.jung.algorithms.util.IterativeContext;
26 import edu.uci.ics.jung.graph.Graph;
27
28
29
30
31
32
33
34 public class ISOMLayout<V, E> extends AbstractLayout<V,E> implements IterativeContext {
35
36 Map<V, ISOMVertexData> isomVertexData =
37 LazyMap.decorate(new HashMap<V, ISOMVertexData>(),
38 new Factory<ISOMVertexData>() {
39 public ISOMVertexData create() {
40 return new ISOMVertexData();
41 }});
42
43 private int maxEpoch;
44 private int epoch;
45
46 private int radiusConstantTime;
47 private int radius;
48 private int minRadius;
49
50 private double adaption;
51 private double initialAdaption;
52 private double minAdaption;
53
54 protected GraphElementAccessor<V,E> elementAccessor =
55 new RadiusGraphElementAccessor<V,E>();
56
57 private double coolingFactor;
58
59 private List<V> queue = new ArrayList<V>();
60 private String status = null;
61
62
63
64
65 public String getStatus() {
66 return status;
67 }
68
69 public ISOMLayout(Graph<V,E> g) {
70 super(g);
71 }
72
73 public void initialize() {
74
75 setInitializer(new RandomLocationTransformer<V>(getSize()));
76 maxEpoch = 2000;
77 epoch = 1;
78
79 radiusConstantTime = 100;
80 radius = 5;
81 minRadius = 1;
82
83 initialAdaption = 90.0D / 100.0D;
84 adaption = initialAdaption;
85 minAdaption = 0;
86
87
88 coolingFactor = 2;
89
90
91
92
93
94
95 }
96
97
98
99
100
101 public void step() {
102 status = "epoch: " + epoch + "; ";
103 if (epoch < maxEpoch) {
104 adjust();
105 updateParameters();
106 status += " status: running";
107
108 } else {
109 status += "adaption: " + adaption + "; ";
110 status += "status: done";
111
112 }
113 }
114
115 ISOMVertexData tempISOM;
116 Point3f tempXYD;
117
118 private synchronized void adjust() {
119
120 tempISOM = new ISOMVertexData();
121 tempXYD = new Point3f();
122
123
124 tempXYD.set((float)(10 + Math.random() * getSize().getRadius()),
125 (float)(10 + Math.random() * getSize().getRadius()),
126 (float)(10 + Math.random() * getSize().getRadius()));
127
128
129 V winner = elementAccessor.getVertex(this, tempXYD);
130
131 while(true) {
132 try {
133 for(V v : getGraph().getVertices()) {
134 ISOMVertexData ivd = getISOMVertexData(v);
135 ivd.distance = 0;
136 ivd.visited = false;
137 }
138 break;
139 } catch(ConcurrentModificationException cme) {}
140 }
141 adjustVertex(winner);
142 }
143
144 private synchronized void updateParameters() {
145 epoch++;
146 double factor = Math.exp(-1 * coolingFactor * (1.0 * epoch / maxEpoch));
147 adaption = Math.max(minAdaption, factor * initialAdaption);
148
149
150 if ((radius > minRadius) && (epoch % radiusConstantTime == 0)) {
151 radius--;
152 }
153 }
154
155 private synchronized void adjustVertex(V v) {
156 queue.clear();
157 ISOMVertexData ivd = getISOMVertexData(v);
158 ivd.distance = 0;
159 ivd.visited = true;
160 queue.add(v);
161 V current;
162
163 while (!queue.isEmpty()) {
164 current = queue.remove(0);
165 ISOMVertexData currData = getISOMVertexData(current);
166 Point3f currXYData = transform(current);
167
168 double dx = tempXYD.getX() - currXYData.getX();
169 double dy = tempXYD.getY() - currXYData.getY();
170 double dz = tempXYD.getZ() - currXYData.getZ();
171 double factor = adaption / Math.pow(2, currData.distance);
172
173 currXYData.set((float)(currXYData.getX()+(factor*dx)),
174 (float)(currXYData.getY()+(factor*dy)),
175 (float)(currXYData.getZ()+(factor*dz)));
176
177
178
179 if (currData.distance < radius) {
180 Collection<V> s = getGraph().getNeighbors(current);
181
182 while(true) {
183 try {
184 for(V child : s) {
185
186
187 ISOMVertexData childData = getISOMVertexData(child);
188 if (childData != null && !childData.visited) {
189 childData.visited = true;
190 childData.distance = currData.distance + 1;
191 queue.add(child);
192 }
193 }
194 break;
195 } catch(ConcurrentModificationException cme) {}
196 }
197 }
198 }
199 }
200
201 public ISOMVertexData getISOMVertexData(V v) {
202 return isomVertexData.get(v);
203 }
204
205
206
207
208
209 public boolean isIncremental() {
210 return true;
211 }
212
213
214
215
216
217 public boolean done() {
218 return epoch >= maxEpoch;
219 }
220
221 public static class ISOMVertexData {
222 public Vector3f disp;
223
224 int distance;
225 boolean visited;
226
227 public ISOMVertexData() {
228 initialize();
229 }
230
231 public void initialize() {
232 disp = new Vector3f();
233
234 distance = 0;
235 visited = false;
236 }
237
238 public double getXDisp() {
239 return disp.getX();
240 }
241
242 public double getYDisp() {
243 return disp.getY();
244 }
245
246 public double getZDisp() {
247 return disp.getZ();
248 }
249
250 public void setDisp(double x, double y, double z) {
251 disp.set((float)x, (float)y, (float)z);
252
253 }
254
255 public void incrementDisp(double x, double y, double z) {
256 disp.add(new Vector3f((float)x, (float)y, (float)z));
257
258 }
259
260 public void decrementDisp(double x, double y, double z) {
261 disp.sub(new Vector3f((float)x, (float)y, (float)z));
262
263 }
264 }
265
266 public void reset() {
267 epoch = 0;
268 }
269 }