1 /***
2 * Virtual Mockup for Machine Vision Copyright (C) 2001-2003 Fabio R. de
3 * Miranda, João E. Kogler Jr., Carlos S. Santos. Virtual Mockup for Machine
4 * Vision Project funded by SENAC-SP Permission is granted to redistribute
5 * and/or modify this software under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either version 2.1 of
7 * the License, or (at your option) any later version. This software is
8 * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 * PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * (http://www.gnu.org/copyleft/lesser.html) for more details.
12 */
13
14 package camera3d;
15 import camera3d.event.*;
16 import com.sun.j3d.loaders.*;
17 import com.sun.j3d.utils.behaviors.keyboard.*;
18 import com.sun.j3d.utils.universe.*;
19
20 import java.awt.*;
21 import java.io.*;
22 import java.util.*;
23 import javax.media.j3d.*;
24
25
26 import javax.vecmath.*;
27
28 /***
29 * This class encapsulates the basic scene graph structure and provides some
30 * functionality (adding, retrieving, removing ) to manage the objects in the
31 * scene graph. It also permits loading VRML files into the virtual world.
32 *
33 *@author Fábio Roberto de Miranda, Carlos da Silva dos Santos
34 *@created October 22, 2003
35 */
36 public class J3DBase implements VcObjectChangeListener {
37 /***
38 * Vector containing all the VcObjects currently in the scene graph. It
39 * must be synchronized.
40 */
41 private Vector vcObjectVec;
42
43 /***
44 * Vector containing all the VcViews currently in the scene.
45 */
46 private Vector vcViewVec;
47
48 /***
49 * Vector containing all objects currently listening to changes in the
50 * scene graph.
51 */
52 private Vector listeners;
53
54 /***
55 * Object that encapsulates the basic scene graph structure.
56 */
57 private CoreScene coreScene;
58
59 /***
60 * Internal loader for VRML files.
61 */
62 private VcLoader vcLoader;
63 //VcLoader2 vcLoader;
64
65 /***
66 * Used to set the influencing bounds of lights added to the scene.
67 */
68 private BoundingSphere lightsBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 1000.0);
69
70 /*
71 * A separate reference is kept to a defaultView, and this view cannot be deleted, for
72 * Java3D needs at least one View Branch to keep working
73 */
74 private VcView defaultView;
75
76 // auxiliary objects; used to avoid multiple instantiation.
77 private Vector3d tempUp = new Vector3d(0.0, 1.0, 0.0);
78 private Transform3D tempT3D = new Transform3D();
79 private Transform3D auxT3D = new Transform3D();
80 private Matrix3f tempM3f = new Matrix3f();
81 private Vector3f tempVec3f = new Vector3f();
82
83 /*
84 * used to compute the bounding box.
85 */
86 private Point3d lowerP3d = new Point3d();
87 private Point3d upperP3d = new Point3d();
88 private Point3d tempP3d = new Point3d();
89
90 /*
91 *
92 */
93 private GeometryBag defaultBag;
94
95 /*
96 * Holds the most recent event.
97 */
98 private SceneObjectsChangedEvent currentEvent;
99 /*
100 * Event to signal when an object has been added to the scene graph.
101 */
102 private ObjectAddedEvent addEvent;
103 /*
104 * Event to signal when an object has been removed from the scene graph.
105 */
106 private ObjectRemovedEvent removeEvent;
107 /*
108 * Event to inform new listeners of objects already present in the scene graph.
109 */
110 private InitialListEvent initialEvent = new InitialListEvent(this);
111
112
113 /***
114 * Creates a new scene and adds the default views to it.
115 */
116 public J3DBase() {
117 vcObjectVec = new Vector(20, 5);
118 vcViewVec = new Vector(20, 5);
119
120 coreScene = new CoreScene();
121
122 addEvent = new ObjectAddedEvent(this);
123 removeEvent = new ObjectRemovedEvent(this);
124 //vcLoader = new VcLoader2();
125 vcLoader = new VcLoader();
126
127 listeners = new Vector(20, 5);
128 defaultView = new VcView();
129
130 defaultView.setLabel("Default View");
131 addView(defaultView);
132 addDefaultViews();
133 }
134
135
136 /***
137 * Sets a view that already belongs to the collection of VcViews as the
138 * default view.
139 *
140 *@param view the new default view
141 */
142 public void setDefaultView(VcView view) {
143 if(vcViewVec.contains(view)) {
144 System.out.println("Setting default view: " + view.getLabel());
145 defaultView = view;
146 } else {
147 System.out.println("View " + view.getLabel() + " does not belong to the scene graph");
148 }
149 }
150
151
152 /***
153 * Returns a Vector containing the list of objects in the scene graph.
154 *
155 *@return The objectList value
156 */
157 public Vector getObjectList() {
158 return this.vcObjectVec;
159 }
160
161
162 /***
163 * Returns a Vector containing the list of VcViews in the scene graph.
164 *
165 *@return The viewList value
166 */
167 public java.util.List getViewList() {
168 return new Vector(this.vcViewVec);
169 }
170
171
172 /***
173 * Returns a VcObject given its label. It returns null in case there is no
174 * VcObject in the scene graph associated with the input label
175 *
176 *@param label name of object to be searched for
177 *@return VcObjet associated with the label, if it exists; null
178 * otherwise
179 */
180 public VcObject getByLabel(String label) {
181 Iterator iter = vcObjectVec.iterator();
182 VcObject returnObject = null;
183 // iterates through the list of objects in search for the desired object
184 while(iter.hasNext()) {
185 VcObject vcObj = (VcObject) iter.next();
186 if(vcObj.getLabel().equals(label)) {
187 returnObject = vcObj;
188 break;
189 }
190 }
191 return returnObject;
192 }
193
194
195 /***
196 * Returns the current default view
197 *
198 *@return The defaultView value
199 */
200 public VcView getDefaultView() {
201 return this.defaultView;
202 }
203
204
205 /***
206 * Gets the j3DRootBranchGroup attribute of the J3DBase object
207 *
208 *@return The j3DRootBranchGroup value
209 */
210 public BranchGroup getJ3DRootBranchGroup() {
211 return coreScene.getRootBranchGroup();
212 }
213
214
215 /***
216 *@return The defaultGeometryBag value
217 */
218 public GeometryBag getDefaultGeometryBag() {
219 if(defaultBag == null) {
220 defaultBag = new GeometryBag();
221 this.addGeometryBag(defaultBag);
222 }
223 return defaultBag;
224 }
225
226
227 /***
228 * Adds default ortographic VcViews: Front, Back, Left, Right, Top and
229 * Bottom.
230 */
231 void addDefaultViews() {
232 Transform3D tempT3D = new Transform3D();
233 Transform3D auxT3D = new Transform3D();
234 // sets a translation in Z direction
235 auxT3D.setTranslation(new Vector3d(0.0, 0.0, 60.0));
236
237 VcView frontView = new VcView();
238 frontView.setLabel("Front");
239
240 VcView backView = new VcView();
241 backView.setLabel("Back");
242
243 VcView leftView = new VcView();
244 leftView.setLabel("Left");
245
246 VcView rightView = new VcView();
247 rightView.setLabel("Right");
248
249 VcView topView = new VcView();
250 topView.setLabel("Top");
251
252 VcView bottomView = new VcView();
253 bottomView.setLabel("Bottom");
254
255 // front view is placed at the origin of coordinates.
256 addView(frontView);
257
258 /*
259 * to create the transformation for the other cameras first we set tempT3D
260 * to a rotation of +/-pi/2 radians around either the X or Y axis (depending
261 * on the camera we want). Then we multiply it by auxT3D, which contains a
262 * translation translation in the Z axis. Finally, we set the view transform
263 * to the transform we obtained in the preceeding step.
264 */
265
266 tempT3D.rotX(Math.PI / 2);
267 tempT3D.mul(auxT3D);
268 bottomView.setTransform(tempT3D);
269 addView(bottomView);
270
271 tempT3D.rotX(-Math.PI / 2);
272 tempT3D.mul(auxT3D);
273 topView.setTransform(tempT3D);
274 addView(topView);
275
276 tempT3D.rotY(Math.PI / 2);
277 tempT3D.mul(auxT3D);
278 rightView.setTransform(tempT3D);
279 addView(rightView);
280
281 tempT3D.rotY(-Math.PI / 2);
282 tempT3D.mul(auxT3D);
283 leftView.setTransform(tempT3D);
284 addView(leftView);
285
286 tempT3D.rotY(Math.PI);
287 tempT3D.mul(auxT3D);
288 backView.setTransform(tempT3D);
289 addView(backView);
290 }
291
292
293 /***
294 * Adds a VcLight to the scene graph. Light capabilities are set so its
295 * parameters are made editable; notifyChangeListeners() is called at the
296 * end of execution.
297 *
298 *@param light the new VcLight.
299 */
300 public void addLight(VcLight light) {
301 vcObjectVec.addElement(light);
302 //light.addChangeListener(this);
303 Light j3dLight = light.getJ3DLight();
304 // sets light general capabilities
305 j3dLight.setCapability(Node.ALLOW_BOUNDS_READ);
306 j3dLight.setCapability(Node.ALLOW_BOUNDS_WRITE);
307 j3dLight.setCapability(Light.ALLOW_COLOR_READ);
308 j3dLight.setCapability(Light.ALLOW_COLOR_WRITE);
309 j3dLight.setCapability(Light.ALLOW_STATE_READ);
310 j3dLight.setCapability(Light.ALLOW_STATE_WRITE);
311 j3dLight.setInfluencingBounds(lightsBounds);
312 //j3dLight.addScope(coreScene.getContentBG());
313 // sets specific light capabilities
314 if(j3dLight instanceof PointLight) {
315 ((PointLight) j3dLight).setCapability(PointLight.ALLOW_ATTENUATION_READ);
316 ((PointLight) j3dLight).setCapability(PointLight.ALLOW_ATTENUATION_WRITE);
317 ((PointLight) j3dLight).setCapability(PointLight.ALLOW_POSITION_READ);
318 ((PointLight) j3dLight).setCapability(PointLight.ALLOW_POSITION_WRITE);
319 }
320 if(j3dLight instanceof SpotLight) {
321 ((SpotLight) j3dLight).setCapability(SpotLight.ALLOW_CONCENTRATION_READ);
322 ((SpotLight) j3dLight).setCapability(SpotLight.ALLOW_CONCENTRATION_WRITE);
323 }
324
325 coreScene.getLightBG().addChild(light.getBranchGroup());
326
327 // computes bounding box for lights--which results in very small
328 // boxes that don't help much with visualization
329 //if(! (light instanceof VcAmbientLight)){
330 // light.computeBoundingBox();
331 //}
332 // sets the event and call listeners
333
334 addEvent.setObject(light);
335 currentEvent = addEvent;
336 notifyChangeListeners();
337 }
338
339
340 /***
341 * Adds a VcView to the scene graph; notifyChangeListeners is called at the
342 * end of execution.
343 *
344 *@param view the new VcView
345 */
346 public void addView(VcView view) {
347 vcObjectVec.addElement(view);
348 vcViewVec.addElement(view);
349 try {
350 coreScene.getViewBG().addChild(view.getBranchGroup());
351 //view.addChangeListener(this);
352 addEvent.setObject(view);
353 currentEvent = addEvent;
354 notifyChangeListeners();
355 } catch(IllegalSharingException ex) {
356 debugln("Error adding view " + view.getLabel() + ":");
357 ex.printStackTrace();
358 }
359 /*
360 * Listeners interested in addition/subtraction/change of View objects must
361 * subscribe themselves as objects interested
362 */
363 }
364
365
366 /***
367 * Adds a VcLaserArray to the scene graph; notifyChangeListeners is called
368 * at the end of execution.
369 *
370 *@param array the new VcLaserArray
371 */
372 public void addLaserArray(VcLaserArray array) {
373 vcObjectVec.addElement(array);
374 array.setBranchGroup(coreScene.getContentBG());
375 coreScene.getHelperBG().addChild(array.getBranchGroup());
376 // ?!
377 //array.addChangeListener(this);
378 DimensionsManager.getDimensionsManager().computeTranslationControlsIncrement(array);
379 // sets the event and notify listeners
380 addEvent.setObject(array);
381 currentEvent = addEvent;
382 notifyChangeListeners();
383 }
384
385
386 /***
387 * Adds a VcContent object to the scene graph; notifyChangeListeners is
388 * called at the end of execution.
389 *
390 *@param content the new VcContent
391 */
392 public void addContent(VcContent content) {
393 vcObjectVec.addElement(content);
394 //debugln("BG autocompute bounds: "+content.getBranchGroup().getBoundsAutoCompute());
395 //debugln("parent trans TG autocompute bounds: "+content.parentTransTG.getBoundsAutoCompute());
396 //debugln("parent rot scale TG autocompute bounds: "+content.parentRotScaleTG.getBoundsAutoCompute());
397 //debugln("parent pivot TG autocompute bounds: "+content.pivotTG.getBoundsAutoCompute());
398 //debugln("parent child TG autocompute bounds: "+content.childTG.getBoundsAutoCompute());
399
400 coreScene.getContentBG().addChild(content.getBranchGroup());
401 //content.addChangeListener(this);
402 content.computeBoundingBox();
403 content.setDegradeMode(VcContent.DEGRADE_SIMPLIFIED);
404 DimensionsManager.getDimensionsManager().computeTranslationControlsIncrement(content);
405 // sets event and notify listeners
406 addEvent.setObject(content);
407 currentEvent = addEvent;
408 notifyChangeListeners();
409 }
410
411
412 /***
413 * Adds a VcHelper object to the scene graph; notifyChangeListeners is
414 * called at the end of execution.
415 *
416 *@param helper the new VcHelper
417 */
418 public void addHelper(VcHelper helper) {
419 vcObjectVec.addElement(helper);
420 coreScene.getHelperBG().addChild(helper.getBranchGroup());
421 //helper.addChangeListener(this);
422 DimensionsManager.getDimensionsManager().computeTranslationControlsIncrement(helper);
423 // sets event and notify listeners
424 addEvent.setObject(helper);
425 currentEvent = addEvent;
426 notifyChangeListeners();
427 }
428
429
430 /***
431 * Added 06/2002. GeometryBag will be kept at helper's BG for a while
432 *
433 *@param bag The feature to be added to the GeometryBag attribute
434 */
435 public void addGeometryBag(GeometryBag bag) {
436 vcObjectVec.addElement(bag);
437 coreScene.getHelperBG().addChild(bag.getBranchGroup());
438 //bag.addChangeListener(this);
439
440 addEvent.setObject(bag);
441 currentEvent = addEvent;
442 notifyChangeListeners();
443 }
444
445
446 /***
447 * Removes an VcObject from the scene graph.
448 *
449 *@param vcObject the VcObject to be deleted.
450 */
451 public synchronized void removeVcObject(VcObject vcObject) {
452 /*
453 * removes object from object list (the delete action will keep a reference to
454 * the object in the case we want to undo that change
455 */
456 if(vcObject instanceof VcView) {
457 // Checks whether this is the last view.
458 if(vcViewVec.size() == 1) {
459 debugln("Cannot remove " + defaultView.getLabel() + ".");
460 debugln("Java3D requires at least one camera to keep running.");
461 // returns without doing anything.
462 return;
463 }
464 vcViewVec.remove(vcObject);
465 // if(defaultView==null)System.out.println("defaultView = null");
466 // else System.out.println("defaultView: "+defaultView.getLabel());
467
468 // sets a new default view in case we removed it.
469 if((VcView) vcObject == defaultView) {
470 setDefaultView((VcView) vcViewVec.get(0));
471 }
472 }
473 /*
474 * remove object (by detaching BG) from Java3D infrastructure
475 */
476 vcObject.detach();
477
478 /*
479 * This command removes this object (J3DBase) and all other objects interested
480 * in notification about changes in the vcObject object
481 */
482 vcObject.removeAllChangeListeners();
483
484 // If the object was the default GeometryBag, we must forget about it
485 if(vcObject == defaultBag) {
486 defaultBag = null;
487 }
488
489 if(vcObjectVec.remove(vcObject)) {
490 // If the instruction succeeds in removing the object this code will be executed
491 /*
492 * Notifies all those who are interested in knowing of changes in the
493 * scene
494 */
495 removeEvent.setObject(vcObject);
496 currentEvent = removeEvent;
497 notifyChangeListeners();
498 } else {
499 System.out.println("Attempted to remove an unexistant object.");
500 return;
501 }
502
503 }
504
505
506 /***
507 * Loads a VMRL 2.0 file into the scene graph. Lights and cameras in the
508 * VRML file are turned into VcLights and VcViews, respectively. All
509 * geometries are put in a single VcContent object.
510 *
511 *@param filename name of VRML file to be loaded
512 */
513 public void loadVRMLScene(String filename) {
514 vcLoader.load(filename, this, coreScene);
515 }
516
517
518 /***
519 * Adds a listener to this object. Listeners are notified of changes in the
520 * list of objects in the scene graph.
521 *
522 *@param listener new listener to be added
523 */
524 public void addSceneObjectsChangeListener(SceneObjectsChangeListener listener) {
525 this.listeners.addElement(listener);
526 initialEvent.setInitialList(vcObjectVec);
527 listener.sceneObjectsChanged(initialEvent);
528 }
529
530
531 /***
532 * Notifies listeners that the list of objects in the scene graph has been
533 * changed.
534 */
535 void notifyChangeListeners() {
536 synchronized(currentEvent) {
537 if(currentEvent == null) {
538 return;
539 }
540 Iterator iter = listeners.iterator();
541 //System.out.println("J3DBase.notifyChangeListeners(); Number of listeners: "+listeners.size());
542 while(iter.hasNext()) {
543 SceneObjectsChangeListener listener = (SceneObjectsChangeListener) iter.next();
544 //System.out.println("__listener: "+listener.toString());
545 //listener.sceneObjectsChanged(this);
546 listener.sceneObjectsChanged(currentEvent);
547 }
548 currentEvent = null;
549 }
550 }
551
552
553 /***
554 * Iterates through the list of objects in the scene graph and prints the
555 * label associated with each one.
556 */
557 public void printLabels() {
558 Iterator iter = vcObjectVec.iterator();
559 debugln("Printing labels of elements:");
560 while(iter.hasNext()) {
561 VcObject vcObj = (VcObject) iter.next();
562 debugln(vcObj.getLabel());
563 }
564 }
565
566
567 /***
568 * Prints a debug message. It is controlled by the debug flag.
569 *
570 *@param s message to be printed.
571 */
572 public void debugln(String s) {
573 if(GUIControl.debugflag) {
574 System.out.println(s);
575 }
576 }
577
578
579 /***
580 * Toggles exhibition of helping grid.
581 */
582 public void toggleHelpingGrid() {
583 coreScene.toggleHelpingGrid();
584 }
585
586
587 /***
588 * Description of the Method
589 *
590 *@param event Description of the Parameter
591 */
592 public void vcObjectChanged(VcObjectEvent event) {
593
594 }
595
596
597 /*
598 * Makes it possible to VcObject object be seen by
599 * the VcView view.
600 * POR QUE este método não está em VcView? Fábio, 14/03/2002
601 */
602 /***
603 * Description of the Method
604 *
605 *@param view Description of the Parameter
606 *@param vcObject Description of the Parameter
607 */
608 public void frameObjectInView(VcView view, VcObject vcObject) {
609 view.frameObjectInView(vcObject);
610 }
611
612
613 /*
614 * POR QUE este método não está em VcView? Fábio, 14/03/2002
615 */
616 /***
617 * Description of the Method
618 *
619 *@param view Description of the Parameter
620 */
621 public void frameAllObjectsInView(VcView view) {
622 Point3d p1 = new Point3d();
623 Iterator iter = vcObjectVec.iterator();
624 boolean firstElement = true;
625 while(iter.hasNext()) {
626 Object obj = iter.next();
627 VcObject vcObject = (VcObject) obj;
628 /*
629 * Now we try to find a BoundingBox that bounds all
630 * the objects in the scene
631 */
632 //if (!(vcObject instanceof DistanceMeasurer)){
633 if(vcObject instanceof VcContent) {
634 // Only VcContent objects count by now
635 BoundingBox b = new BoundingBox();
636 vcObject.getBoundingBoxInVWorld(b);
637 if(firstElement) {
638 b.getLower(p1);
639 lowerP3d.set(p1);
640 upperP3d.set(p1);
641 }
642 b.getLower(tempP3d);
643 compareAndSet(lowerP3d, upperP3d, tempP3d);
644 b.getUpper(tempP3d);
645 compareAndSet(lowerP3d, upperP3d, tempP3d);
646 }
647 //}
648 }
649
650 /*
651 * At this point both lowerP3d and upperP3d contain
652 * the corners of a boundingBox that bounds the whole scene
653 */
654 view.frameBoundingBox(lowerP3d, upperP3d);
655 }
656
657
658 /*
659 * Este método talvez tivesse mais sucesso declarado em VcView, também . Fábio, 14/3/2002
660 */
661 /***
662 * Description of the Method
663 *
664 *@param view Description of the Parameter
665 *@param vcObject Description of the Parameter
666 */
667 public void lookAt(VcView view, VcObject vcObject) {
668 Point3d viewOriginP3d = new Point3d();
669 view.getTransforms(auxT3D);
670 //view.getParentTransTG(auxT3D);
671 //view.getParentRotScaleTG(tempT3D);
672 //auxT3D.mul(tempT3D);
673 // Finds camera center in world coordinates
674 auxT3D.transform(viewOriginP3d);
675 Point3d objectOriginP3d = new Point3d();
676 vcObject.getTransforms(auxT3D);
677 //vcObject.getParentTransTG(auxT3D);
678 //vcObject.getParentRotScaleTG(tempT3D);
679 // Finds object origin in world coordinates
680 //auxT3D.mul(tempT3D);
681 auxT3D.transform(objectOriginP3d);
682 tempT3D.setIdentity();
683 tempT3D.lookAt(viewOriginP3d, objectOriginP3d, tempUp);
684 tempT3D.invert();
685 view.setTransform(tempT3D);
686 }
687
688
689 /***
690 *@param lower Description of the Parameter
691 *@param upper Description of the Parameter
692 *@param point Description of the Parameter
693 */
694 private void compareAndSet(Point3d lower, Point3d upper, Point3d point) {
695 if(point.x < lower.x) {
696 lower.x = point.x;
697 } else if(point.x > upper.x) {
698 upper.x = point.x;
699 }
700
701 if(point.y < lower.y) {
702 lower.y = point.y;
703 } else if(point.y > upper.y) {
704 upper.y = point.y;
705 }
706
707 if(point.z < lower.z) {
708 lower.z = point.z;
709 } else if(point.z > upper.z) {
710 upper.z = point.z;
711 }
712 }
713
714
715 /***
716 * Description of the Method
717 *
718 *@param contentLength Description of the Parameter
719 */
720 private void adjustCoreSceneMagnitudes(double contentLength) {
721 double length = contentLength;
722 /*
723 * frontClipQuocient, backClipFactor and boundingFactor are all
724 * guessed, they can be changed at will if needed
725 */
726 double boundingFactor = 10;
727
728 if(coreScene.getGlobalBoundsRadius() < boundingFactor * length) {
729 // coreScene.setGlobalBoundsRadius(boundingFactor*length);
730 // coreScene.setGlobalBoundsCenter(xCenter, yCenter, zCenter);
731 }
732 }
733
734 }
This page was automatically generated by Maven