1
2
3
4
5
6
7
8 package edu.uci.ics.jung.visualization3d;
9
10
11
12
13 import java.awt.BorderLayout;
14 import java.awt.Font;
15 import java.awt.GraphicsConfiguration;
16 import java.awt.event.ItemEvent;
17 import java.awt.event.ItemListener;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import javax.media.j3d.AmbientLight;
22 import javax.media.j3d.Appearance;
23 import javax.media.j3d.BoundingSphere;
24 import javax.media.j3d.Bounds;
25 import javax.media.j3d.BranchGroup;
26 import javax.media.j3d.Canvas3D;
27 import javax.media.j3d.DirectionalLight;
28 import javax.media.j3d.Font3D;
29 import javax.media.j3d.FontExtrusion;
30 import javax.media.j3d.Group;
31 import javax.media.j3d.Material;
32 import javax.media.j3d.Node;
33 import javax.media.j3d.OrientedShape3D;
34 import javax.media.j3d.Text3D;
35 import javax.media.j3d.Transform3D;
36 import javax.media.j3d.TransformGroup;
37 import javax.swing.JPanel;
38 import javax.swing.event.ChangeEvent;
39 import javax.swing.event.ChangeListener;
40 import javax.vecmath.Color3f;
41 import javax.vecmath.Point3d;
42 import javax.vecmath.Point3f;
43 import javax.vecmath.Vector3f;
44
45 import org.apache.commons.collections15.BidiMap;
46 import org.apache.commons.collections15.bidimap.DualHashBidiMap;
47
48 import com.sun.j3d.utils.behaviors.mouse.MouseWheelZoom;
49 import com.sun.j3d.utils.geometry.Primitive;
50 import com.sun.j3d.utils.picking.PickTool;
51 import com.sun.j3d.utils.picking.behaviors.PickingCallback;
52 import com.sun.j3d.utils.universe.SimpleUniverse;
53
54 import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
55 import edu.uci.ics.jung.algorithms.layout3d.Layout;
56 import edu.uci.ics.jung.algorithms.util.IterativeContext;
57 import edu.uci.ics.jung.graph.Graph;
58 import edu.uci.ics.jung.graph.util.Context;
59 import edu.uci.ics.jung.graph.util.Pair;
60 import edu.uci.ics.jung.visualization.picking.MultiPickedState;
61 import edu.uci.ics.jung.visualization.picking.PickedState;
62 import edu.uci.ics.jung.visualization3d.control.MouseRotate;
63 import edu.uci.ics.jung.visualization3d.control.MouseTranslate;
64 import edu.uci.ics.jung.visualization3d.control.PickSphereBehavior;
65 import edu.uci.ics.jung.visualization3d.control.PickTranslateBehavior;
66 import edu.uci.ics.jung.visualization3d.layout.LayoutEventBroadcaster;
67
68
69
70
71
72
73 public class VisualizationViewer<V,E> extends JPanel {
74
75 BranchGroup objRoot;
76 TransformGroup objTrans;
77
78
79 Appearance grayLook;
80
81
82
83
84 protected ItemListener pickEventListener;
85
86
87
88
89 protected PickedState<V> pickedVertexState;
90
91
92
93
94
95 protected PickedState<E> pickedEdgeState;
96
97 protected RenderContext<V,E> renderContext = new PluggableRenderContext<V,E>();
98
99 BidiMap<V,VertexGroup> vertexMap = new DualHashBidiMap<V,VertexGroup>();
100 Map<E,EdgeGroup> edgeMap = new HashMap<E,EdgeGroup>();
101 Graph<V,E> graph;
102 Layout<V,E> layout;
103
104 public VisualizationViewer() {
105
106 setLayout(new BorderLayout());
107
108 renderContext.setPickedVertexState(new MultiPickedState<V>());
109 renderContext.setPickedEdgeState(new MultiPickedState<E>());
110 GraphicsConfiguration config =
111 SimpleUniverse.getPreferredConfiguration();
112 final Canvas3D c = new Canvas3D(config);
113 add(c, BorderLayout.CENTER);
114 setPickedVertexState(new MultiPickedState<V>());
115 setPickedEdgeState(new MultiPickedState<E>());
116
117
118 BranchGroup scene = createSceneGraph(c);
119 SimpleUniverse u = new SimpleUniverse(c);
120 u.getViewer().getView().setUserHeadToVworldEnable(true);
121
122
123
124 u.getViewingPlatform().setNominalViewingTransform();
125
126 u.addBranchGraph(scene);
127 }
128
129 public Layout<V,E> getGraphLayout() {
130 return layout;
131 }
132
133
134 public BranchGroup createSceneGraph(final Canvas3D canvas) {
135
136 objRoot = new BranchGroup();
137 objRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
138 objRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
139
140 TransformGroup objScale = new TransformGroup();
141 Transform3D t3d = new Transform3D();
142
143 objScale.setTransform(t3d);
144 objRoot.addChild(objScale);
145
146 Transform3D tt = new Transform3D();
147 tt.setScale(.05);
148 tt.setTranslation(new Vector3f(0, 0, -30.f));
149 objTrans = new TransformGroup(tt);
150 objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
151 objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ );
152 objTrans.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
153 objScale.addChild(objTrans);
154
155
156
157 Appearance look = new Appearance();
158 Color3f objColor = new Color3f(0.7f, 0.7f, 0.7f);
159 Color3f black = new Color3f(0.f, 0.f, 0.f);
160 Color3f white = new Color3f(1.0f, 1.0f, 0.6f);
161 Color3f gray = new Color3f(.2f, .2f, .2f);
162 Color3f red = new Color3f(1.0f, 0, 0);
163 Color3f yellow = new Color3f(1,1,0);
164
165 Material objMaterial = new Material(objColor, black,
166 objColor, white, 100.0f);
167 Material blackMaterial = new Material(objColor, black,
168 black, objColor, 10.0f);
169 Material whiteMaterial = new Material(white, white,
170 white, white, 100.0f);
171 Material grayMaterial = new Material(gray, black,
172 gray, gray, 100.0f);
173
174 Material redMaterial = new Material(red, black,
175 red, red, 100.0f);
176 Material yellowMaterial = new Material(yellow, black,
177 yellow, yellow, 100);
178
179 look.setMaterial(new Material(objColor, black,
180 objColor, white, 100.0f));
181 Appearance blackLook = new Appearance();
182 blackLook.setMaterial(blackMaterial);
183
184 Appearance whiteLook = new Appearance();
185 whiteLook.setMaterial(whiteMaterial);
186
187 Appearance grayLook = new Appearance();
188 grayLook.setMaterial(grayMaterial);
189 grayLook.setCapability(Appearance.ALLOW_MATERIAL_READ);
190 grayLook.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
191
192 final Appearance redLook = new Appearance();
193 redLook.setMaterial(redMaterial);
194
195
196 Appearance objLook = new Appearance();
197 objLook.setMaterial(objMaterial);
198 grayLook = objLook;
199 final Appearance yellowLook = new Appearance();
200 yellowLook.setMaterial(yellowMaterial);
201 Bounds bounds =
202 new BoundingSphere(new Point3d(),
203 300);
204
205 MouseRotate behavior1 = new MouseRotate();
206 behavior1.setTransformGroup(objTrans);
207 objTrans.addChild(behavior1);
208 behavior1.setSchedulingBounds(bounds);
209
210 MouseWheelZoom behavior2 = new MouseWheelZoom();
211 behavior2.setTransformGroup(objTrans);
212
213 objTrans.addChild(behavior2);
214 behavior2.setSchedulingBounds(bounds);
215
216 MouseTranslate behavior3 = new MouseTranslate();
217 behavior3.setTransformGroup(objTrans);
218 objTrans.addChild(behavior3);
219 behavior3.setSchedulingBounds(bounds);
220
221 PickTranslateBehavior ptb = new PickTranslateBehavior(objRoot,canvas,bounds,PickTool.GEOMETRY);
222 ptb.setSchedulingBounds(bounds);
223
224 ptb.setupCallback(new PickingCallback() {
225
226 public void transformChanged(int type, TransformGroup tg) {
227 if(tg == null) return;
228 Transform3D t3d = new Transform3D();
229 tg.getTransform(t3d);
230
231 Point3f p1 = new Point3f();
232 V v = vertexMap.getKey(tg);
233
234
235
236
237
238 Point3f p0 = layout.transform(v);
239
240
241
242
243 t3d.transform(p1);
244
245 System.err.println("change location for vertex "+v+", transformGroup "+tg+" from "+p0+" to "+p1);
246
247
248
249 }});
250
251 PickSphereBehavior psb = new PickSphereBehavior(objRoot,canvas,bounds);
252
253 PickVertexBehavior pvb = new PickVertexBehavior(objRoot,canvas,bounds,renderContext.getPickedVertexState());
254 objTrans.addChild(pvb);
255 pvb.addChangeListener(new ChangeListener() {
256
257 public void stateChanged(ChangeEvent e) {
258 for(V v : graph.getVertices()) {
259 VertexGroup<V> vg = vertexMap.get(v);
260 Appearance look = redLook;
261 if(renderContext.getPickedVertexState().isPicked(v)) {
262 look = yellowLook;
263 }
264 Node node = vg.getShape();
265 if(node instanceof Primitive) {
266 ((Primitive)node).setAppearance(look);
267 }
268 }
269
270 }});
271
272
273 Color3f lColor1 = new Color3f(.5f, .5f, .5f);
274 Color3f lColor2 = new Color3f(1.0f, 1.0f, 1.0f);
275 Vector3f lDir2 = new Vector3f(-1.0f, 0.0f, -1.0f);
276 DirectionalLight lgt2 = new DirectionalLight(lColor2, lDir2);
277 AmbientLight ambient = new AmbientLight(lColor1);
278 lgt2.setInfluencingBounds(bounds);
279 ambient.setInfluencingBounds(bounds);
280 objRoot.addChild(lgt2);
281 objRoot.addChild(ambient);
282
283
284 objRoot.compile();
285
286
287
288
289 return objRoot;
290 }
291
292 public void setGraphLayout(Layout<V,E> inLayout) {
293
294
295 this.graph = inLayout.getGraph();
296 BranchGroup branch = new BranchGroup();
297 LayoutEventBroadcaster<V,E> elayout =
298 new LayoutEventBroadcaster<V,E>(inLayout);
299 this.layout = elayout;
300 for(V v : graph.getVertices()) {
301 VertexGroup<V> vg = new VertexGroup<V>(v, renderContext.getVertexShapeTransformer().transform(v));
302 vg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
303 vg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
304 vertexMap.put(v, vg);
305 branch.addChild(vg);
306 String label = renderContext.getVertexStringer().transform(v);
307 if(label != null) {
308 String fontName = "Serif";
309 Font3D f3d = new Font3D(new Font(fontName, Font.PLAIN, 2),
310 new FontExtrusion());
311 Text3D txt = new Text3D(f3d, label,
312 new Point3f(2f,2f,0));
313 OrientedShape3D textShape = new OrientedShape3D();
314 textShape.setGeometry(txt);
315 textShape.setAppearance(grayLook);
316
317 textShape.setAlignmentMode(OrientedShape3D.ROTATE_ABOUT_POINT);
318 textShape.setRotationPoint(new Point3f());
319
320
321
322
323
324
325
326
327 Transform3D tt = new Transform3D();
328
329 tt.setScale(5);
330 TransformGroup tg = new TransformGroup(tt);
331
332 tg.addChild(textShape);
333 BranchGroup bg = new BranchGroup();
334 bg.addChild(tg);
335
336 vg.getLabelNode().addChild(bg);
337
338 }
339
340 }
341 System.err.println("vertexMap = "+vertexMap);
342
343 for(E edge : graph.getEdges()) {
344 EdgeGroup<E> eg =
345 new EdgeGroup<E>(edge, renderContext.getEdgeShapeTransformer().transform(Context.<Graph<V,E>,E>getInstance(graph, edge)));
346 eg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
347 eg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
348 edgeMap.put(edge, eg);
349 branch.addChild(eg);
350 }
351
352
353
354
355
356
357 objTrans.addChild(branch);
358 elayout.addChangeListener(new ChangeListener() {
359
360 public void stateChanged(ChangeEvent e) {
361 for(V v : vertexMap.keySet()) {
362 Point3f p = VisualizationViewer.this.layout.transform(v);
363 Vector3f pv = new Vector3f(p.getX(), p.getY(), p.getZ());
364 Transform3D tx = new Transform3D();
365 tx.setTranslation(pv);
366 vertexMap.get(v).setTransform(tx);
367 }
368
369 for(E edge : graph.getEdges()) {
370 Pair<V> endpoints = graph.getEndpoints(edge);
371 V start = endpoints.getFirst();
372 V end = endpoints.getSecond();
373 EdgeGroup eg = edgeMap.get(edge);
374 eg.setEndpoints(layout.transform(start), layout.transform(end));
375 }
376 }});
377
378 elayout.setSize(new BoundingSphere(new Point3d(), 200));
379 elayout.initialize();
380 VisRunner runner = new VisRunner((IterativeContext)elayout);
381 runner.relax();
382
383
384
385
386
387 }
388
389 public void setPickedVertexState(PickedState<V> pickedVertexState) {
390 if(pickEventListener != null && this.pickedVertexState != null) {
391 this.pickedVertexState.removeItemListener(pickEventListener);
392 }
393 this.pickedVertexState = pickedVertexState;
394 this.renderContext.setPickedVertexState(pickedVertexState);
395 if(pickEventListener == null) {
396 pickEventListener = new ItemListener() {
397
398 public void itemStateChanged(ItemEvent e) {
399 System.err.println(e.getItem()+" was picked");
400 }
401 };
402 }
403 pickedVertexState.addItemListener(pickEventListener);
404 }
405
406
407
408
409 public void setPickedEdgeState(PickedState<E> pickedEdgeState) {
410 if(pickEventListener != null && this.pickedEdgeState != null) {
411 this.pickedEdgeState.removeItemListener(pickEventListener);
412 }
413 this.pickedEdgeState = pickedEdgeState;
414 this.renderContext.setPickedEdgeState(pickedEdgeState);
415 if(pickEventListener == null) {
416 pickEventListener = new ItemListener() {
417
418 public void itemStateChanged(ItemEvent e) {
419 repaint();
420 }
421 };
422 }
423 pickedEdgeState.addItemListener(pickEventListener);
424 }
425
426
427
428
429 public RenderContext<V, E> getRenderContext() {
430 return renderContext;
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444
445 }
446