View Javadoc

1   package org.textensor.vis;
2   
3   
4   import java.awt.BorderLayout;
5   import java.awt.Dimension;
6   import java.awt.FlowLayout;
7   import java.awt.GraphicsConfiguration;
8   import java.awt.GraphicsEnvironment;
9   import java.awt.GridLayout;
10  import java.awt.event.ActionEvent;
11  import java.awt.event.ActionListener;
12  import java.awt.event.InputEvent;
13  import java.awt.event.MouseEvent;
14  import java.awt.event.MouseListener;
15  import java.awt.event.MouseMotionListener;
16  import java.util.ArrayList;
17  import java.util.HashMap;
18  import java.util.HashSet;
19  
20  import javax.media.j3d.AmbientLight;
21  import javax.media.j3d.BoundingSphere;
22  import javax.media.j3d.BranchGroup;
23  import javax.media.j3d.Canvas3D;
24  import javax.media.j3d.DirectionalLight;
25  import javax.media.j3d.GraphicsConfigTemplate3D;
26  import javax.media.j3d.Light;
27  import javax.media.j3d.Locale;
28  import javax.media.j3d.Node;
29  import javax.media.j3d.PhysicalBody;
30  import javax.media.j3d.PhysicalEnvironment;
31  import javax.media.j3d.PickConeRay;
32  import javax.media.j3d.PickCylinderRay;
33  import javax.media.j3d.PickInfo;
34  import javax.media.j3d.PickRay;
35  import javax.media.j3d.PickShape;
36  import javax.media.j3d.RenderingAttributes;
37  import javax.media.j3d.Shape3D;
38  import javax.media.j3d.Transform3D;
39  import javax.media.j3d.TransformGroup;
40  import javax.media.j3d.View;
41  import javax.media.j3d.ViewPlatform;
42  import javax.media.j3d.VirtualUniverse;
43  import javax.swing.ButtonGroup;
44  import javax.swing.JButton;
45  import javax.swing.JCheckBox;
46  import javax.swing.JPanel;
47  import javax.swing.JRadioButton;
48  import javax.swing.JSlider;
49  import javax.swing.event.ChangeEvent;
50  import javax.swing.event.ChangeListener;
51  import javax.vecmath.AxisAngle4d;
52  import javax.vecmath.Color3f;
53  import javax.vecmath.Matrix4d;
54  import javax.vecmath.Point3d;
55  import javax.vecmath.Vector3d;
56  import javax.vecmath.Vector3f;
57  
58  import org.textensor.report.E;
59  
60  
61  import com.sun.j3d.utils.geometry.Sphere;
62  
63  
64  
65  public class SceneGraphViewer implements ActionListener, MouseListener, MouseMotionListener, ChangeListener {
66  
67      JPanel panel;
68  
69      Canvas3D canvas;
70  
71      VirtualUniverse universe;
72      Locale locale;
73      View view;
74  
75      int xdown;
76      int ydown;
77      boolean dragging = false;
78  
79      public final static int PAN = 0;
80      public final static int ZOOM = 1;
81      public final static int ROLL = 2;
82      public final static int HIDE = 3;
83      int mode = PAN;
84  
85  
86      public final static int NONE = 0;
87      public final static int LEFT = 1;
88      public final static int RIGHT = 2;
89      int button = NONE;
90  
91  
92      Transform3D rootTransform;
93      TransformGroup rootTransformGroup;
94  
95      TransformGroup decTransformGroup;
96  
97      PickInfo[] lastPickInfos;
98  
99      BranchGroup baseGroup;
100     ArrayList<Shape3D> shapes;
101 
102 
103     HashMap<String, SceneItem> sceneItemHM = new HashMap<String, SceneItem>();
104 
105 
106     float scale = 1.0f;
107     Transform3D downTransform;
108     Point3d wcdown;
109 
110     Transform3D fcTrans = new Transform3D();
111     Transform3D tcTrans = new Transform3D();
112 
113     Transform3D fwTrans = new Transform3D();
114     Transform3D twTrans = new Transform3D();
115 
116 
117     Transform3D fwrcTrans = new Transform3D();
118     Transform3D twrcTrans = new Transform3D();
119 
120     float downscale = 0.f;
121 
122 
123     float brightness = 0.7f;
124 
125     BranchGroup lights;
126 
127     DirectionalLight directionalLight;
128     AmbientLight ambientLight;
129 
130 
131     int nshowing = 0;
132 
133 
134     public SceneGraphViewer() {
135 
136         GraphicsConfiguration config = getPreferredConfiguration();
137         canvas = new Canvas3D(config);
138         canvas.setPreferredSize(new Dimension(800, 600));
139         canvas.setFocusable(true);
140 
141 
142         panel = new JPanel();
143 
144         panel.setLayout(new BorderLayout());
145 
146         JPanel jp = new JPanel();
147         jp.setLayout(new FlowLayout(FlowLayout.CENTER, 6, 0));
148 
149         JRadioButton bpan = new JRadioButton("pan", true);
150         bpan.setActionCommand("pan");
151         bpan.addActionListener(this);
152 
153         JRadioButton bzoom = new JRadioButton("zoom");
154         bzoom.setActionCommand("zoom");
155         bzoom.addActionListener(this);
156 
157         JRadioButton broll = new JRadioButton("roll");
158         broll.setActionCommand("roll");
159         broll.addActionListener(this);
160 
161         JRadioButton bhide = new JRadioButton("hide");
162         bhide.setActionCommand("hide");
163         bhide.addActionListener(this);
164 
165 
166 
167         ButtonGroup g = new ButtonGroup();
168         g.add(bpan);
169         g.add(bzoom);
170         g.add(broll);
171         g.add(bhide);
172 
173         jp.add(bpan);
174         jp.add(bzoom);
175         jp.add(broll);
176         jp.add(bhide);
177 
178         JButton jbsa = new JButton("Show all");
179         jbsa.setActionCommand("showall");
180         jbsa.addActionListener(this);
181         jp.add(jbsa);
182 
183 
184         JCheckBox jcb = new JCheckBox("Smooth", false);
185         jcb.addActionListener(this);
186         jcb.setActionCommand("antialias");
187         jp.add(jcb);
188 
189         JButton jbb = new JButton("+");
190         jbb.setActionCommand("brighter");
191         jbb.addActionListener(this);
192         jp.add(jbb);
193 
194         JButton jbd = new JButton("-");
195         jbd.setActionCommand("darker");
196         jbd.addActionListener(this);
197         jp.add(jbd);
198 
199 
200         JPanel ptop = new JPanel();
201         ptop.setLayout(new GridLayout(2, 1, 2, 2));
202         ptop.add(jp);
203 
204 
205         JSlider slider = new JSlider(0, 1000, 1000);
206         slider.addChangeListener(this);
207         ptop.add(slider);
208 
209 
210         panel.add(ptop, BorderLayout.NORTH);
211 
212 
213 
214         panel.add(canvas, BorderLayout.CENTER);
215 
216 
217 
218         universe = new VirtualUniverse();
219         locale = new Locale(universe);
220 
221 
222         ViewPlatform platform = new ViewPlatform();
223         TransformGroup tg = new TransformGroup();
224         Transform3D wk = new Transform3D();
225         wk.setTranslation(new Vector3d(0., 0., 100.));
226         tg.setTransform(wk);
227         tg.addChild(platform);
228         BranchGroup platformBG = new BranchGroup();
229         platformBG.addChild(tg);
230 
231         locale.addBranchGraph(platformBG);
232 
233 
234         view = new View();
235         view.setPhysicalBody(new PhysicalBody());
236         view.setPhysicalEnvironment(new PhysicalEnvironment());
237 
238         //   view.setSceneAntialiasingEnable(true);
239         view.setProjectionPolicy(View.PARALLEL_PROJECTION);
240         view.setFrontClipDistance(1.);
241         view.setBackClipDistance(200.);
242         //	view.setFieldOfView(5. * Math.PI / 180.);
243         view.addCanvas3D(canvas);
244         view.attachViewPlatform(platform);
245 
246 
247         lights = createLightGraph(brightness);
248         //	lights.setCapability(BranchGroup.ALLOW_DETACH);
249         //	lights.compile();
250         locale.addBranchGraph(lights);
251 
252         BranchGroup scene = createDummySceneGraph();
253 
254         setSceneGraph(scene, null);
255 
256         canvas.addMouseListener(this);
257         canvas.addMouseMotionListener(this);
258     }
259 
260 
261 
262     public void deltaLights(double d) {
263         double br = brightness;
264         br += d;
265         if (br > 1.) {
266             br = 1.;
267         }
268         if (br < 0.) {
269             br = 0.;
270         }
271         setBrightness(br);
272     }
273 
274 
275 
276     public void setBrightness(double br) {
277         if (Math.abs(br - brightness) > 0.01) {
278             applyBrightness(br);
279         }
280     }
281 
282     private void applyBrightness(double br) {
283         brightness = (float)br;
284         Color3f c3 = new Color3f(brightness, brightness, brightness);
285         ambientLight.setColor(c3);
286         directionalLight.setColor(c3);
287     }
288 
289 
290 
291     public JPanel getPanel() {
292         return panel;
293     }
294 
295 
296 
297     public void setSceneGraph(BranchGroup bg, ArrayList<Shape3D> sha) {
298         if (baseGroup != null) {
299             locale.removeBranchGraph(baseGroup);
300         }
301         shapes = sha;
302         if (shapes != null) {
303             nshowing = shapes.size();
304         } else {
305             nshowing = 0;
306         }
307 
308         if (rootTransform == null) {
309             rootTransform= new Transform3D();
310             rootTransform.setTranslation(new Vector3d(0., 0., 0.));
311             rootTransform.setScale(0.1f);
312         }
313 
314         rootTransformGroup = new TransformGroup();
315         rootTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
316         rootTransformGroup.setTransform(rootTransform);
317         rootTransformGroup.addChild(bg);
318 
319         baseGroup = new BranchGroup();
320         baseGroup.addChild(rootTransformGroup);
321         baseGroup.setCapability(BranchGroup.ALLOW_DETACH);
322         baseGroup.compile();
323         locale.addBranchGraph(baseGroup);
324 
325 
326         if (decTransformGroup == null) {
327             decTransformGroup = new TransformGroup();
328             decTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
329             decTransformGroup.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
330             decTransformGroup.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
331             decTransformGroup.setTransform(rootTransform);
332             BranchGroup decGroup = new BranchGroup();
333             decGroup.addChild(decTransformGroup);
334             locale.addBranchGraph(decGroup);
335         }
336     }
337 
338 
339     private BranchGroup createDummySceneGraph() {
340         BranchGroup ret = new BranchGroup();
341 
342         for (int i = 0; i < 50; i++) {
343             TransformGroup trans = new TransformGroup();
344             Transform3D pos = new Transform3D();
345             pos.setTranslation(new Vector3f((float)(-1 + 2 * Math.random()), (float)(-1 + 2  * Math.random()),
346                                             (float)(-0.1 + 0.2 * Math.random())));
347             trans.setTransform(pos);
348             ret.addChild(trans);
349 
350             Sphere sp = new Sphere((float)(0.01 + 0.1 * Math.random()), Sphere.GENERATE_NORMALS, 50);
351             trans.addChild(sp);
352         }
353 
354         return ret;
355     }
356 
357 
358 
359 
360 
361 
362     private BranchGroup createLightGraph(double br) {
363         float fb = (float)br;
364         BranchGroup group = new BranchGroup();
365         BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
366 
367         // directed;
368         Color3f light1Color = new Color3f(fb, fb, fb);
369         Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -2.0f);
370         directionalLight = new DirectionalLight(light1Color, light1Direction);
371         directionalLight.setInfluencingBounds(bounds);
372         directionalLight.setCapability(Light.ALLOW_COLOR_WRITE);
373         group.addChild(directionalLight);
374 
375         /*
376         Color3f light2Color = new Color3f(.3f, .3f, 0.f);
377         Vector3f light2Direction = new Vector3f(-2.0f, -7.0f, -5.0f);
378         DirectionalLight light2 = new DirectionalLight(light2Color, light2Direction);
379         light2.setInfluencingBounds(bounds);
380         group.addChild(light2);
381         */
382 
383         // ambient;
384         Color3f ambientColor = new Color3f(fb, fb, fb);
385         ambientLight = new AmbientLight(ambientColor);
386         ambientLight.setCapability(Light.ALLOW_COLOR_WRITE);
387         ambientLight.setInfluencingBounds(bounds);
388         group.addChild(ambientLight);
389 
390         return group;
391     }
392 
393 
394 
395     public void actionPerformed(ActionEvent e) {
396         String s = e.getActionCommand();
397         if (s.equals("pan")) {
398             mode = PAN;
399 
400         } else if (s.equals("zoom")) {
401             mode = ZOOM;
402 
403         } else if (s.equals("roll")) {
404             mode = ROLL;
405 
406         } else if (s.equals("hide")) {
407             mode = HIDE;
408 
409         } else if (s.equals("antialias")) {
410             boolean b = ((JCheckBox)e.getSource()).isSelected();
411             setAA(b);
412 
413         } else if (s.equals("brighter")) {
414             deltaLights(0.07);
415 
416         } else if (s.equals("darker")) {
417             deltaLights(-0.07);
418 
419         } else if (s.equals("showall")) {
420             showAll();
421 
422         } else {
423             E.error("unhandled " + s);
424         }
425     }
426 
427 
428 
429 
430     void showFraction(double f) {
431         if (shapes == null) {
432             return;
433         }
434         RenderingAttributes rashow = new RenderingAttributes();
435         RenderingAttributes rahide = new RenderingAttributes();
436         rahide.setVisible(false);
437 
438         int nch = shapes.size();
439         int nshow = (int)(f * nch);
440 
441         if (nshowing < nshow) {
442             for (int i = nshowing; i < nshow; i++) {
443                 Shape3D s = shapes.get(i);
444                 s.getAppearance().setRenderingAttributes(rashow);
445                 s.setUserData(new Integer(1));
446             }
447 
448         } else {
449             for (int i = nshow; i < nshowing; i++) {
450                 Shape3D s = shapes.get(i);
451                 s.getAppearance().setRenderingAttributes(rahide);
452                 s.setUserData(new Integer(0));
453             }
454         }
455 
456         nshowing = nshow;
457     }
458 
459 
460     void showAll() {
461         if (shapes == null) {
462             return;
463         }
464         RenderingAttributes rashow = new RenderingAttributes();
465         RenderingAttributes rahide = new RenderingAttributes();
466         rahide.setVisible(false);
467 
468         int nch = shapes.size();
469 
470         for (int i = 0; i < nch; i++) {
471             Shape3D s = shapes.get(i);
472             s.getAppearance().setRenderingAttributes(rashow);
473             s.setUserData(new Integer(1));
474         }
475 
476         nshowing = nch;
477     }
478 
479 
480 
481     public void mouseClicked(MouseEvent e) {
482     }
483 
484 
485 
486     public void mousePressed(MouseEvent e) {
487         dragging = false;
488         downscale = scale;
489         xdown = e.getX();
490         ydown = e.getY();
491 
492 
493         downTransform = new Transform3D(rootTransform);
494         Transform3D motion = new Transform3D();
495         canvas.getImagePlateToVworld(motion);
496 
497         Point3d mouse_pos = new Point3d();
498         wcdown = new Point3d();
499         canvas.getPixelLocationInImagePlate(xdown, ydown, mouse_pos);
500         motion.transform(mouse_pos, wcdown);
501 
502         wcdown.z = 0;
503 
504         Transform3D t = new Transform3D(rootTransform);
505         t.invert();
506         Point3d cc = new Point3d();
507         t.transform(wcdown, cc);
508         Vector3d vc = new Vector3d(cc);
509 
510         tcTrans = new Transform3D();
511         tcTrans.setTranslation(vc);
512 
513         fcTrans = new Transform3D();
514         vc.negate();
515         fcTrans.setTranslation(vc);
516 
517         Vector3d vw = new Vector3d(wcdown);
518         twTrans = new Transform3D();
519         twTrans.setTranslation(vw);
520 
521         fwTrans = new Transform3D();
522         vw.negate();
523         fwTrans.setTranslation(vw);
524 
525 
526 
527 
528 
529         Transform3D t3 = getPickTransform(e.getX(), e.getY());
530         if (t3 != null) {
531             Point3d p3 = new Point3d();
532             t3.transform(p3);
533             Vector3d vp = new Vector3d(p3);
534             twrcTrans = new Transform3D();
535             twrcTrans.setTranslation(vp);
536 
537             fwrcTrans = new Transform3D();
538             vp.negate();
539             fwrcTrans.setTranslation(vp);
540 
541 
542             if (mode == HIDE) {
543                 toggleHide();
544             }
545 
546         } else {
547             // best guess for rotation center is point in z=0 plane under mouse
548             fwrcTrans = fwTrans;
549             twrcTrans = twTrans;
550         }
551 
552 
553         button = NONE;
554         int m = e.getModifiers();
555         button = LEFT;
556 
557         if ((m & InputEvent.BUTTON3_MASK) != 0) {
558             button = RIGHT;
559         } else {
560             int[] masks = {InputEvent.CTRL_MASK, InputEvent.META_MASK, InputEvent.SHIFT_MASK,
561                            InputEvent.BUTTON2_MASK
562                           };
563             for (int i = 0; i < masks.length; i++) {
564                 if ((m & masks[i]) != 0) {
565                     button = RIGHT;
566                     break;
567                 }
568             }
569         }
570     }
571 
572 
573 
574     private void toggleHide() {
575         if (lastPickInfos != null) {
576             int npi = lastPickInfos.length;
577             // for (int ipi = npi - 1; ipi >= 0; ipi--) {
578             for (int ipi = 0; ipi < npi; ipi++) {
579                 PickInfo pi = lastPickInfos[ipi];
580                 Node node = pi.getNode();
581                 if (node instanceof Shape3D) {
582                     Shape3D s3d = (Shape3D)node;
583                     boolean hid = hideShape(s3d);
584                     if (hid) {
585                         break;
586                     }
587 
588                 } else {
589                     // E.info("no node " + node);
590                 }
591             }
592         }
593     }
594 
595 
596 
597     private void toggleHideShape(Shape3D s3d) {
598         if (!(s3d.getUserData() instanceof Integer)) {
599             s3d.setUserData(new Integer(1));
600         }
601         int ival = ((Integer)(s3d.getUserData())).intValue();
602         if (ival == 1) {
603             hideShape(s3d);
604         } else {
605             showShape(s3d);
606         }
607     }
608 
609 
610     boolean hideShape(Shape3D s) {
611         boolean hid = false;
612         if (!(s.getUserData() instanceof Integer)) {
613             s.setUserData(new Integer(1));
614         }
615 
616         int ival = ((Integer)(s.getUserData())).intValue();
617         if (ival == 1) {
618             hid = true;
619             RenderingAttributes rahide = new RenderingAttributes();
620             rahide.setVisible(false);
621             s.setUserData(new Integer(0));
622             s.getAppearance().setRenderingAttributes(rahide);
623         }
624         return hid;
625     }
626 
627     void showShape(Shape3D s) {
628         RenderingAttributes rashow = new RenderingAttributes();
629         s.setUserData(new Integer(1));
630         s.getAppearance().setRenderingAttributes(rashow);
631     }
632 
633 
634     public void mouseReleased(MouseEvent e) {
635 
636         if (dragging) {
637 
638         } else if (mode == ZOOM) {
639             // no click actions for zoom;
640         } else if (mode == HIDE) {
641             // done toggle hide already
642 
643         } else {
644             if (button == LEFT) {
645                 zoomBy(1. / 0.7);
646             } else if (button == RIGHT) {
647                 zoomBy(0.7);
648 
649             }
650         }
651     }
652 
653 
654     private void zoomBy(double d) {
655         zoomTo(scale * d);
656     }
657 
658     private void zoomTo(double d) {
659         scale = (float)d;
660 
661         double fscale = d / downscale;
662         Transform3D tscale = new Transform3D();
663         tscale.setScale(fscale);
664         Transform3D tnew = new Transform3D();
665         /*
666         		tnew.mul(downTransform);
667         		tnew.mul(tcTrans);
668         		tnew.mul(tscale);
669         		tnew.mul(fcTrans);
670         */
671 
672         tnew.mul(twTrans);
673         tnew.mul(tscale);
674         tnew.mul(fwTrans);
675         tnew.mul(downTransform);
676 
677         setTransform(tnew);
678     }
679 
680     private void setTransform(Transform3D t3d) {
681         rootTransform = t3d;
682         rootTransformGroup.setTransform(rootTransform);
683         decTransformGroup.setTransform(rootTransform);
684     }
685 
686 
687 
688     @SuppressWarnings("unused")
689     public void intPan(int dx, int dy, Point3d cpos) {
690 
691 
692         Transform3D ttrans = new Transform3D();
693         Vector3d v = new Vector3d(cpos.x - wcdown.x, cpos.y - wcdown.y, 0.);
694         // v.scale(1. / scale);
695         ttrans.setTranslation(v);
696 
697         Transform3D tnew = new Transform3D();
698 
699         tnew.mul(ttrans);
700         tnew.mul(downTransform);
701         setTransform(tnew);
702     }
703 
704 
705 
706     private void intRoll(int dx, int dy) {
707 
708         double wdx = dx; // cpos.x - wcdown.x;
709         double wdy = dy; // cpos.y - wcdown.y;
710 
711         Transform3D trot = new Transform3D();
712         double theta = 0.005 * Math.sqrt(dx * dx + dy * dy);
713         AxisAngle4d aa4d = new AxisAngle4d(wdy, wdx, 0., theta);
714         trot.setRotation(aa4d);
715 
716 
717         Transform3D tnew = new Transform3D();
718 
719         tnew.mul(twrcTrans);
720         tnew.mul(trot);
721         tnew.mul(fwrcTrans);
722         tnew.mul(downTransform);
723 
724         setTransform(tnew);
725     }
726 
727 
728 
729 
730 
731 
732     public void mouseDragged(MouseEvent e) {
733         int x = e.getX();
734         int y = e.getY();
735         if (!dragging && (x-xdown)*(x-xdown) + (y-ydown)*(y-ydown) > 10) {
736             dragging = true;
737         }
738         if (dragging) {
739 
740             Point3d cpos = new Point3d();
741             canvas.getPixelLocationInImagePlate(x, y, cpos);
742             Transform3D motion = new Transform3D();
743             canvas.getImagePlateToVworld(motion);
744             motion.transform(cpos);
745 
746             if (mode == PAN) {
747                 intPan(x - xdown,  y - ydown, cpos);
748 
749             } else if (mode == ZOOM) {
750                 double f = Math.exp(0.01 * (y - ydown));
751                 zoomTo(f * downscale);
752 
753             } else {
754                 if (button == LEFT) {
755                     intRoll(x - xdown, y - ydown);
756                 } else {
757                     intPan(x - xdown,  y - ydown, cpos);
758                 }
759             }
760         }
761 
762 
763     }
764 
765 
766 
767 
768 
769     private Transform3D getPickTransform(int xpos, int ypos) {
770         float tolerance = 0.1f;
771 
772         Transform3D motion = new Transform3D();
773         Point3d eyePosn = new Point3d();
774         Point3d mousePosn = new Point3d();
775         Vector3d mouseVec = new Vector3d();
776         boolean isParallel = false;
777         double spreadAngle = 0.0;
778 
779         canvas.getCenterEyeInImagePlate(eyePosn);
780         canvas.getPixelLocationInImagePlate(xpos,ypos,mousePosn);
781 
782         if ((canvas.getView() != null) &&
783                 (canvas.getView().getProjectionPolicy() == View.PARALLEL_PROJECTION)) {
784             // just use a ray through the mouse position
785             eyePosn.x = mousePosn.x;
786             eyePosn.y = mousePosn.y;
787             isParallel = true;
788         }
789 
790         // Calculate radius for PickCylinderRay and spread angle for PickConeRay
791         Vector3d eyeToCanvas = new Vector3d();
792         eyeToCanvas.sub(mousePosn, eyePosn);
793         double distanceEyeToCanvas = eyeToCanvas.length();
794 
795         Point3d deltaImgPlate = new Point3d();
796         canvas.getPixelLocationInImagePlate(xpos+1, ypos, deltaImgPlate);
797 
798         Vector3d ptToDelta = new Vector3d();
799         ptToDelta.sub(mousePosn, deltaImgPlate);
800         double distancePtToDelta = ptToDelta.length();
801         distancePtToDelta *= tolerance;
802 
803         canvas.getImagePlateToVworld(motion);
804 
805         motion.transform(eyePosn);
806         motion.transform(mousePosn);
807         mouseVec.sub(mousePosn, eyePosn);
808         mouseVec.normalize();
809 
810 
811         PickShape pickShape = null;
812 
813         if (tolerance == 0.0) {
814             pickShape = new PickRay(eyePosn, mouseVec);
815 
816         } else if (isParallel) {
817             pickShape = new PickCylinderRay(eyePosn, mouseVec, distancePtToDelta);
818 
819         } else {
820             // Perspective projection, use a PickConeRay
821             // Calculate spread angle
822             spreadAngle = Math.atan(distancePtToDelta/distanceEyeToCanvas);
823             pickShape = new PickConeRay(eyePosn, mouseVec, spreadAngle);
824         }
825 
826 
827         PickInfo pickInfo = baseGroup.pickClosest(PickInfo.PICK_GEOMETRY, PickInfo.LOCAL_TO_VWORLD, pickShape);
828         Transform3D ret = null;
829         if (pickInfo != null) {
830             ret = pickInfo.getLocalToVWorld();
831         }
832 
833         lastPickInfos = baseGroup.pickAllSorted(PickInfo.PICK_GEOMETRY, PickInfo.NODE, pickShape);
834 
835         return ret;
836     }
837 
838 
839 
840 
841     public void mouseEntered(MouseEvent e) {
842         // TODO Auto-generated method stub
843 
844     }
845 
846     public void mouseExited(MouseEvent e) {
847         // TODO Auto-generated method stub
848 
849     }
850 
851     public void mouseMoved(MouseEvent e) {
852         // TODO Auto-generated method stub
853 
854     }
855 
856     public static GraphicsConfiguration getPreferredConfiguration() {
857         GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
858         // could set stereo stuff here (see SimpleUniverse)
859 
860         return GraphicsEnvironment.getLocalGraphicsEnvironment().
861                getDefaultScreenDevice().getBestConfiguration(template);
862     }
863 
864 
865 
866 
867     public void setDecoration(String id, BranchGroup root, boolean b) {
868         root.setCapability(BranchGroup.ALLOW_DETACH);
869         root.compile();
870         if (sceneItemHM.containsKey(id)) {
871             setDecorationVisibility(id, false);
872             sceneItemHM.remove(sceneItemHM.get(id));
873         }
874         SceneItem sit = new SceneItem(id, root);
875         sceneItemHM.put(id, sit);
876         setDecorationVisibility(id, b);
877     }
878 
879 
880     public void removeUnlistedDecoration(HashSet<String> keepHS) {
881         for (String s : sceneItemHM.keySet()) {
882             if (keepHS != null && keepHS.contains(s)) {
883                 // OK;
884             } else {
885                 setDecorationVisibility(s, false);
886                 sceneItemHM.remove(sceneItemHM.get(s));
887             }
888         }
889     }
890 
891 
892     public void removeAllDecoration() {
893         removeUnlistedDecoration(null);
894     }
895 
896 
897     public synchronized void setDecorationVisibility(String s, boolean b) {
898         SceneItem sit = sceneItemHM.get(s);
899         if (sit.showing) {
900             if (b) {
901                 // OK;
902             } else {
903                 decTransformGroup.removeChild(sit.getBranchGroup());
904                 sit.showing = false;
905             }
906 
907         } else  {
908             if (b) {
909                 sit.showing = true;
910                 decTransformGroup.addChild(sit.getBranchGroup());
911             } else {
912                 // OK;
913             }
914         }
915     }
916 
917 
918 
919     public void setAA(boolean b) {
920         view.setSceneAntialiasingEnable(b);
921     }
922 
923 
924 
925     public void setLightsPercent(int p) {
926         setBrightness(p / 100.);
927 
928     }
929 
930 
931 
932     public void setFourMatrix(double[] fmo) {
933         Matrix4d m4d = new Matrix4d();
934         m4d.set(fmo);
935         Transform3D t3d = new Transform3D(m4d);
936         setTransform(t3d);
937     }
938 
939 
940 
941     public double[] getFourMatrix() {
942         double[] mtx = new double[16];
943         rootTransform.get(mtx);
944         return mtx;
945     }
946 
947 
948 
949 
950     public void stateChanged(ChangeEvent e) {
951         JSlider js = (JSlider)e.getSource();
952         int val = js.getValue();
953         double fval = val / 1000.;
954         showFraction(fval);
955     }
956 
957 
958 
959 
960 }