View Javadoc
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