View Javadoc

1   /*
2    * Copyright (c) 2003, the JUNG Project and the Regents of the University of
3    * California All rights reserved.
4    * 
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or http://jung.sourceforge.net/license.txt for a description.
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   * @author Tom Nelson - tomnelson@dev.java.net
71   *
72   */
73  public class VisualizationViewer<V,E> extends JPanel {
74  
75  	BranchGroup objRoot;
76  	TransformGroup objTrans;
77  //	Appearance vertexLook;
78  //	Appearance edgeLook;
79  	Appearance grayLook;
80      /**
81       * a listener used to cause pick events to result in
82       * repaints, even if they come from another view
83       */
84      protected ItemListener pickEventListener;
85  	/**
86  	 * holds the state of which vertices of the graph are
87  	 * currently 'picked'
88  	 */
89  	protected PickedState<V> pickedVertexState;
90  	
91  	/**
92  	 * holds the state of which edges of the graph are
93  	 * currently 'picked'
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 //		controls = createControls();
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 		// Create a SpringGraph scene and attach it to the virtual universe
118 		BranchGroup scene = createSceneGraph(c);
119 		SimpleUniverse u = new SimpleUniverse(c);
120 		u.getViewer().getView().setUserHeadToVworldEnable(true);	
121 
122 		// This will move the ViewPlatform back a bit so the
123 		// objects in the scene can be viewed.
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 //		t3d.setScale(0.05);
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 //		objRoot.addChild(objTrans);
155 
156 		// Create Colors, Materials,  and Appearances.
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 //		vertexLook = redLook;
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 //		behavior2.setFactor(10);
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 //		objTrans.addChild(ptb);
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 //				System.err.println(tg+" transformChanged \n"+t3d);
231 				Point3f p1 = new Point3f();
232 				V v = vertexMap.getKey(tg);
233 //				Transform3D lvw = new Transform3D();
234 //				tg.getLocalToVworld(lvw);
235 //				System.err.println("lvw = \n"+lvw);
236 //				lvw.invert();
237 //				System.err.println("invert lvw = \n"+lvw);
238 				Point3f p0 = layout.transform(v);
239 //				Transform3D vwip = new Transform3D();
240 //				canvas.getVworldToImagePlate(vwip);
241 //				System.err.println("vwip=\n"+vwip);
242 //				t3d.mul(lvw);
243 				t3d.transform(p1);
244 //				scale.transform(p1);
245 				System.err.println("change location for vertex "+v+", transformGroup "+tg+" from "+p0+" to "+p1);
246 //				p1.set(p1.getX()*2,p1.getY()*2,p1.getZ()*2);
247 //				layout.setLocation(v, p1);
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 		//Shine it with two colored lights.
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 		// Let Java 3D perform optimizations on this scene graph.
284 		objRoot.compile();
285 
286 //		VisRunner runner = new VisRunner((IterativeContext)elayout);
287 //		runner.relax();
288 
289 		return objRoot;
290 	}
291 	
292 	public void setGraphLayout(Layout<V,E> inLayout) {
293 
294 //		this.layout = inLayout;
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 //				textShape.setAlignmentAxis( 0.0f, 1.0f, 0.0f);
317 				textShape.setAlignmentMode(OrientedShape3D.ROTATE_ABOUT_POINT);
318 				textShape.setRotationPoint(new Point3f());
319 //				objScale.addChild( textShape );
320 //				BranchGroup bg = new BranchGroup();
321 //				bg.addChild(textShape);
322 //				branch.addChild(bg);
323 				
324 				
325 				
326 //				Text2D text = new Text2D(label+" more text here", new Color3f(0,0,0),"Serif",50,Font.BOLD);
327 				Transform3D tt = new Transform3D();
328 //				tt.setTranslation(new Vector3f(100,100,100));
329 				tt.setScale(5);
330 				TransformGroup tg = new TransformGroup(tt);
331 //				textShape.setGeometry(text);
332 				tg.addChild(textShape);
333 				BranchGroup bg = new BranchGroup();
334 				bg.addChild(tg);
335 //				branch.addChild(bg);
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 //		System.err.println("branch is "+branch);
353 //		for(int i=0; i<branch.numChildren(); i++) {
354 //			System.err.println("branch child ["+i+"] is "+branch.getChild(i));
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 //		for(int i=0; i<objTrans.numChildren(); i++) {
384 //			System.err.println("objTrans child ["+i+"] is "+objTrans.getChild(i));
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     /* (non-Javadoc)
407      * @see edu.uci.ics.jung.visualization.VisualizationServer#setPickedEdgeState(edu.uci.ics.jung.visualization.picking.PickedState)
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 	 * @return the renderContext
428 	 */
429 	public RenderContext<V, E> getRenderContext() {
430 		return renderContext;
431 	}
432 
433 	
434 //	public static void main(String argv[])
435 //	{
436 //		final VisualizationViewer enigma = new VisualizationViewer();
437 //		JFrame f = new JFrame();
438 //		f.add(enigma);
439 //		f.setSize(600,600);
440 //		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
441 ////			new MainFrame(enigma, 500, 500);
442 ////		f.pack();
443 //		f.setVisible(true);
444 //	}
445 }
446