View Javadoc
1 /***************************************************************************** 2 * Virtual Mockup for Machine Vision 3 * Copyright (C) 2001-2003 Fabio R. de Miranda, João E. Kogler Jr., 4 * Carlos S. Santos. 5 * Virtual Mockup for Machine Vision Project funded by SENAC-SP 6 * 7 * Permission is granted to redistribute and/or modify this 8 * software under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This software is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License (http://www.gnu.org/copyleft/lesser.html) 16 * for more details. 17 * 18 *****************************************************************************/ 19 20 package camera3d; 21 /* 22 * Title: Câmera Virtual - LIVES 23 * Description: Câmera Virtual para Controle via Sockets 24 * Copyright: Copyright (c) 2001 25 * Company: Centro de Educação em Informática - SENAC - SP 26 */ 27 28 import javax.vecmath.*; 29 import javax.media.j3d.*; 30 //import com.sun.j3d.utils.*; 31 import com.sun.j3d.utils.universe.*; 32 import com.sun.j3d.loaders.vrml97.*; 33 import com.sun.j3d.loaders.*; 34 import java.io.*; 35 import com.sun.j3d.utils.behaviors.keyboard.*; 36 import java.util.Enumeration; 37 import java.net.URL; 38 import javax.media.j3d.J3DGraphics2D; 39 import java.awt.Color; 40 import java.text.NumberFormat; 41 import java.util.*; 42 43 /*** 44 * This class is a loader for VRML 2.0 files. It translates lights into VcLights 45 * and viewpoints into VcViews. All remaining content is added to a single VcContent 46 * object. 47 * Requires Java 3D 1.3. 48 * @author Fábio Roberto de Miranda 49 * @version 1.0 50 */ 51 class VcLoader { 52 53 // temporary objects, used to avoid multiple instatiation 54 Transform3D tempT3D = new Transform3D(); 55 Transform3D tempT3D2 = new Transform3D(); 56 57 Light[] lights; 58 TransformGroup[] viewGroups; 59 Hashtable hashtable; 60 61 private int depthIndex = 0; 62 63 /*** 64 * Creates a new loader. 65 */ 66 public VcLoader() { 67 } 68 69 /*** 70 * Reads the content from a VRML97 file and adds it to a J3DBase object. A CoreScene 71 * object is necessary to temporarily adding the content and making it possible to 72 * get the local to vworld transform from some scene objects. Every light in 73 * the VRML file is turned into two VcLight objects. The first one is a 74 * VcAmbientLight, corresponding to the ambient component of VRML light. The second 75 * one will vary in type according to type of the VRML light. 76 * Cameras in the VRML file are turned into VcView objects. Any remaining 77 * content is transferred to a single VcContent object. Behaviors are disabled. 78 * @param filename complete path to VRML file 79 * @param base object to which is added VRML content 80 * @param coreScene used for temporarily adding content during load process 81 */ 82 public void load(String filename, J3DBase base, CoreScene coreScene){ 83 /* We'll import a VRML Scene from a file, Scene will hold it*/ 84 Scene scene = null; 85 86 // for now we are using Sun's VRML Loader - prossibly will change to 87 // Xj3D's in the near future 88 VrmlLoader vrmlLoader = new VrmlLoader(); 89 90 //debug("Base path before:"+vrmlLoader.getBasePath()); 91 vrmlLoader.setBasePath(null); 92 vrmlLoader.setBaseUrl(null); 93 //debug("Base path after:"+vrmlLoader.getBasePath()); 94 debug("File to load:"+filename); 95 96 /* Read the file */ 97 try { 98 scene = vrmlLoader.load(new URL("file:///"+filename)); 99 } catch (Exception e){ 100 //System.out.println("VRML file not found."); 101 e.printStackTrace(); 102 return; 103 } 104 105 hashtable = scene.getNamedObjects(); 106 107 // prints named objects 108 // printContents(hashtable); 109 110 BranchGroup tempGroup = scene.getSceneGroup(); 111 lights = scene.getLightNodes(); 112 viewGroups = scene.getViewGroups(); 113 114 115 // Set necessary capabilities 116 tempGroup.setCapability(BranchGroup.ALLOW_DETACH); 117 // We don't want tempGroup to get reported by picking, as picking utilities 118 // might mistake it by a VcObject root BranchGroup 119 tempGroup.clearCapability(Node.ENABLE_PICK_REPORTING); 120 tempGroup.setCapability(Node.ALLOW_PICKABLE_READ); 121 tempGroup.setCapability(Node.ALLOW_PICKABLE_WRITE); 122 tempGroup.setCapability(Node.ALLOW_BOUNDS_READ); 123 tempGroup.setCapability(Node.ALLOW_BOUNDS_WRITE); 124 tempGroup.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ); 125 tempGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND); 126 tempGroup.setCapability(Group.ALLOW_CHILDREN_WRITE); 127 tempGroup.setCapability(Group.ALLOW_CHILDREN_READ); 128 tempGroup.setBoundsAutoCompute(true); 129 130 // traverses tempGroup and sets capabilities conveniently 131 recursivelyFreeCapabilities(tempGroup); 132 133 /* VRML especifications establish that every light has an ambient component; 134 this means that every light in a VRML file will generate two lights in Java 135 3D, one of the original type (point, spot, etc) and one ambient light. Those 136 two light are put under a SharedGroup by the loader. 137 138 Strangely, VrmlLoader creates two Links pointing to each SharedGroup, one 139 is listed among the named objects, the other is under the Group returned 140 by Scene.getSceneGroup. 141 142 Getting the SharedGroups must be done now, as Light.getParent() does not 143 work on a live scene graph. In case we wanted to get the Links pointing to each 144 SharedGroup, that should be done after we set the scene graph live, as 145 SharedGroup.getLinks() does not work when the scene graph isn't live 146 (due to a Java 3D bug). 147 */ 148 // keeps SharedGroups which holds lights 149 ArrayList lightSGs = new ArrayList(); 150 for (int i=0; i<lights.length; i++){ 151 lights[i].setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ); 152 Node p = lights[i].getParent(); 153 if (p instanceof SharedGroup){ 154 // as each SG holds two lights, must check if 155 // it is already included 156 if(!lightSGs.contains(p)) lightSGs.add(p); 157 } 158 } 159 160 Collection values = hashtable.values(); 161 162 /* 163 Now we'll search for Links among the named objects.If one Link points 164 to a SG contained by lightSGs we will search the hashtable again, looking 165 for the name of the light. 166 */ 167 int foundSGs =0; 168 Iterator vIter = values.iterator(); 169 while(vIter.hasNext()){ 170 Object o = vIter.next(); 171 if(o instanceof Link){ 172 SharedGroup share = ((Link)o).getSharedGroup(); 173 if(lightSGs.contains(share)){ 174 // determine which is the ambient light 175 AmbientLight aLight; 176 Light light = (Light)share.getChild(0); 177 if(light instanceof AmbientLight){ 178 aLight = (AmbientLight)light; 179 light = (Light)share.getChild(1); 180 } else aLight = (AmbientLight) share.getChild(1); 181 // search for the name of the lights 182 Enumeration keyEnum = hashtable.keys(); 183 String lightName = null; 184 while(keyEnum.hasMoreElements()){ 185 Object obj = keyEnum.nextElement(); 186 if (hashtable.get(obj)==o){ 187 lightName = obj.toString(); 188 // breaks from while loop in case we found the name already 189 break; 190 } 191 } 192 if(lightName!=null) debugln("____lightName: "+lightName); 193 // removes lights from scene graph so they can be transferred 194 // to a VcLight 195 share.removeAllChildren(); 196 // remove shared group 197 ((Link)o).setSharedGroup(null); 198 199 VcLight tempLight = createLightByType(light); 200 if(lightName!=null)tempLight.setLabel(lightName); 201 base.addLight(tempLight); 202 // creates ambient light and adds "amb_" to the beggining of 203 // name to distinguish it 204 tempLight = createLightByType(aLight); 205 if(lightName!=null)tempLight.setLabel("amb_"+lightName); 206 base.addLight(tempLight); 207 // breaks away from loop in case we found all lightSGs 208 foundSGs++; 209 if(foundSGs>=lightSGs.size())break; 210 } 211 } 212 } 213 214 // Traverses tempGroup ripping off any Light or ViewPlatform, since their 215 // information has already been cloned 216 ripBG(tempGroup); 217 218 // This addition to view BG is arbitrary. Any BG 219 // in coreScene would serve our purposes well 220 // Necessary to get getLocalToVworld() working 221 coreScene.getViewBG().addChild(tempGroup); 222 223 // Create VcViews cloning VcView information present in scene 224 for (int i=0; i<viewGroups.length; i++){ 225 String name = null; 226 if (hashtable.containsValue(viewGroups[i])){ 227 Enumeration enum = hashtable.keys(); 228 while (enum.hasMoreElements()){ 229 Object obj = enum.nextElement(); 230 if (hashtable.get(obj)==viewGroups[i]){ 231 name = obj.toString(); 232 } 233 } 234 } 235 // Get transform 236 viewGroups[i].getLocalToVworld(tempT3D); 237 // as in a TG the getLocalToVworld doesn't include local 238 // transform we must explicitly get it 239 viewGroups[i].getTransform(tempT3D2); 240 tempT3D.mul(tempT3D2); 241 VcView vcView = new VcView(); 242 // Then we set the Transform 243 vcView.setTransform(tempT3D); 244 // TODO:Some parameters such as FOV are not captured by this moment 245 // extract all possible information available in VRML cameras in the future 246 if (name!=null){ 247 vcView.setLabel(name); 248 } 249 base.addView(vcView); 250 } 251 252 // The remainder of tempGroup will be wrapped up as a VcContent object 253 VcContent vcContent = new VcContent(); 254 // Detaches tempGroup from scene 255 tempGroup.detach(); 256 debugln("Detaching tempGroup"); 257 258 // now we can delete viewgroups from scene graph 259 for(int i=0;i<viewGroups.length;i++){ 260 Node n = viewGroups[i].getParent(); 261 if(n!=null && n instanceof Group) ((Group)n).removeChild(viewGroups[i]); 262 } 263 vcContent.addNode(tempGroup); 264 265 // The remainder is then added to scene 266 base.addContent(vcContent); 267 debugln("Finished loading content"); 268 } 269 270 void ripBG(Group bg){ 271 Enumeration enum = bg.getAllChildren(); 272 while(enum.hasMoreElements()){ 273 Object o = enum.nextElement(); 274 if (o instanceof Group){ 275 Group group = ((Group)o); 276 ripBG(group); 277 } 278 if (o instanceof Link){ 279 Link link = (Link)o; 280 SharedGroup sharedGroup = link.getSharedGroup(); 281 ripBG((Group) sharedGroup); 282 // if there is no child left to sharedGroup 283 // we can discard link 284 if(sharedGroup.numChildren()==0) bg.removeChild(link); 285 } 286 if (o instanceof Light){ 287 Light light = (Light)o; 288 bg.removeChild((Node)light); 289 //debug("removing light"); 290 } 291 292 if (o instanceof ViewPlatform){ 293 ViewPlatform vp = (ViewPlatform)o; 294 bg.removeChild(vp); 295 } 296 } 297 } 298 299 /*** 300 * Used to print debug messages. 301 */ 302 void debug(String s){ 303 if (GUIControl.debugflag){ 304 System.out.println(s); 305 } 306 } 307 308 /*** 309 * Used to print debug messages. 310 */ 311 void debugln(String s){ 312 debug(s); 313 debug("\n"); 314 } 315 316 /*** 317 * Sets capabilities recursively, so objects can be properly edited by the 318 * application. It traverses all elements under g, setting capabilities 319 * according to the element type. 320 */ 321 private void recursivelyFreeCapabilities(Group g){ 322 //debugln("recursivelyfreeCapabilities run"); 323 g.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ); 324 g.setCapability(Group.ALLOW_CHILDREN_READ); 325 g.setCapability(Group.ALLOW_CHILDREN_WRITE); 326 g.setCapability(Group.ALLOW_CHILDREN_EXTEND); 327 328 //System.out.println("_"+depthIndex+"_Group:"); 329 if (g instanceof TransformGroup){ 330 //System.out.println("___TG"); 331 TransformGroup tg = (TransformGroup)g; 332 tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 333 tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 334 } 335 336 if(g instanceof SharedGroup){ 337 //System.out.println("___SG"); 338 SharedGroup shg = (SharedGroup)g; 339 shg.setCapability(SharedGroup.ALLOW_LINK_READ); 340 } 341 342 Enumeration enum = g.getAllChildren(); 343 depthIndex++; 344 while(enum.hasMoreElements()){ 345 Object o = enum.nextElement(); 346 if (o instanceof Node){ 347 //System.out.println("___"+depthIndex+"__Node__"); 348 //debugln("Node instance"); 349 ((Node)o).setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ); 350 ((Node)o).setCapability(Node.ENABLE_PICK_REPORTING); 351 ((Node)o).setBoundsAutoCompute(true); 352 ((Node)o).setPickable(true); 353 354 if (o instanceof Link){ 355 //System.out.println("_Link"); 356 Link link = (Link)o; 357 link.setCapability(Link.ALLOW_SHARED_GROUP_READ); 358 SharedGroup sg = link.getSharedGroup(); 359 sg.setCapability(SharedGroup.ALLOW_LINK_READ); 360 //debugln("Link instance"); 361 depthIndex++; 362 recursivelyFreeCapabilities((Group)sg); 363 depthIndex--; 364 } 365 366 if (o instanceof Group){ 367 //System.out.println("_Group[1]"); 368 recursivelyFreeCapabilities((Group)o); 369 } 370 if (o instanceof Shape3D){ 371 //System.out.println("_Shape3D"); 372 Shape3D shape3D = ((Shape3D)o); 373 shape3D.setCapability(Shape3D.ALLOW_GEOMETRY_READ); 374 shape3D.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE); 375 shape3D.setCapability(Shape3D.ENABLE_PICK_REPORTING); 376 Enumeration shpEnum = shape3D.getAllGeometries(); 377 while (shpEnum.hasMoreElements()){ 378 Geometry geom = (Geometry)shpEnum.nextElement(); 379 freeGeometryCapabilities(geom); 380 } 381 } 382 383 } else if (o instanceof NodeComponent){ 384 //debugln("NodeComponent instance"); 385 } 386 } 387 depthIndex--; 388 } 389 390 /*** 391 * Sets capabilities for the geometry object passed as argument, so it can 392 * be edited by the application. 393 */ 394 private void freeGeometryCapabilities(Geometry g){ 395 if(g.isLive()){ 396 System.out.println("Error: "+g+" is live."); 397 return; 398 } 399 if(g.isCompiled()){ 400 System.out.println("Error: "+g+" is compiled."); 401 return; 402 } 403 g.setCapability(Geometry.ALLOW_INTERSECT); 404 if (g instanceof GeometryArray){ 405 ((GeometryArray)g).setCapability(GeometryArray.ALLOW_COORDINATE_READ); 406 ((GeometryArray)g).setCapability(GeometryArray.ALLOW_COORDINATE_WRITE); 407 ((GeometryArray)g).setCapability(GeometryArray.ALLOW_COUNT_READ); 408 ((GeometryArray)g).setCapability(GeometryArray.ALLOW_COUNT_WRITE); 409 ((GeometryArray)g).setCapability(GeometryArray.ALLOW_FORMAT_READ); 410 ((GeometryArray)g).setCapability(GeometryArray.ALLOW_FORMAT_READ); 411 //debugln("Setting geometryarray caps"); 412 } 413 } 414 415 /*** 416 * Used to print information about content of a hashtable - for debugging 417 * purposes. 418 */ 419 private void printContents(Hashtable hash){ 420 if(hash==null) debugln("printContents: hash==null"); 421 Enumeration enum = hash.elements(); 422 debugln("Enumerating keys of hashtable"); 423 enum = hash.keys(); 424 while (enum.hasMoreElements()){ 425 Object obj = enum.nextElement(); 426 debugln(obj.toString()); 427 if (hash.get(obj) instanceof TransformGroup){ 428 debugln("--- instanceof TransformGroup"); 429 } 430 } 431 432 } 433 434 /*** 435 * Creates a VcLight of appropriate type according to the type of inputLight. 436 * When necessary, parameters from inputLight are read and set accordingly in 437 * the output VcLight. 438 */ 439 private VcLight createLightByType(javax.media.j3d.Light inputLight){ 440 if (inputLight instanceof AmbientLight){ 441 VcAmbientLight ambientLight = new VcAmbientLight(); 442 ambientLight.setJ3DLight(inputLight); 443 return ambientLight; 444 445 } else if (inputLight instanceof DirectionalLight){ 446 VcDirectLight directionalLight = new VcDirectLight(); 447 directionalLight.setJ3DLight(inputLight); 448 /* we will turn the direction from inputLight into a rotational 449 component, transferring it to the VcLight transformation */ 450 // original direction 451 Vector3f dir = new Vector3f(); 452 ((DirectionalLight)inputLight).getDirection(dir); 453 // default direction of DirectionalLight 454 Vector3f defDir = new Vector3f(0.0f,0.0f,-1.0f); 455 rotateLight(defDir,dir,directionalLight); 456 ((DirectionalLight)inputLight).setDirection(defDir); 457 return directionalLight; 458 } else if (inputLight instanceof PointLight){ 459 VcPointLight retVal = null; 460 if (inputLight instanceof SpotLight){ 461 retVal = (VcPointLight) new VcSpotLight(); 462 retVal.setJ3DLight(inputLight); 463 Vector3f dir = new Vector3f(); 464 ((SpotLight)inputLight).getDirection(dir); 465 // default direction of SpotLight 466 Vector3f defDir = new Vector3f(0.0f,0.0f,-1.0f); 467 rotateLight(defDir,dir,retVal); 468 ((SpotLight)inputLight).setDirection(defDir); 469 }else{ 470 retVal = new VcPointLight(); 471 } 472 retVal.setJ3DLight(inputLight); 473 Point3f pos = new Point3f(); 474 ((PointLight)inputLight).getPosition(pos); 475 retVal.translate((double)pos.x,(double)pos.y,(double)pos.z); 476 //System.out.println("Point pos: x: "+pos.x+" y: "+pos.y+" z: "+pos.z); 477 ((PointLight)inputLight).setPosition(0.0f,0.0f,0.0f); 478 return retVal; 479 } 480 481 /* 482 * 483 */ 484 return null; 485 } 486 487 /*** 488 * Generates a quaternion which represents a rotation around a given axis. 489 * @param axis rotation axis 490 * @param angle angle of rotation, in radians 491 * @param rotQuat output rotation quaternion 492 */ 493 private void generateRotationQuaternion(Vector3f axis, double angle, Quat4d rotQuat){ 494 axis.normalize(); 495 double sa = Math.sin(angle/2); 496 double ca = Math.cos(angle/2); 497 rotQuat.x = axis.x*sa; 498 rotQuat.y = axis.y*sa; 499 rotQuat.z = axis.z*sa; 500 rotQuat.w = ca; 501 rotQuat.normalize(); 502 } 503 504 /*** 505 * Changes the tranform of input light so that it performs a rotation from startDirection 506 * to finalDirection. All previous translational components in light are discarded. 507 */ 508 private void rotateLight(Vector3f startDirection, Vector3f finalDirection, VcLight light){ 509 // cosine of angle of rotation 510 double cosAng = startDirection.dot(finalDirection); 511 /* if the dot product is zero, both directions are the same and no 512 rotation should be performed */ 513 if(cosAng >0){ 514 // rotation axis 515 Vector3f rotAxis = new Vector3f(); 516 rotAxis.cross(startDirection,finalDirection); 517 // angle of rotation 518 double angle = Math.acos(cosAng); 519 Quat4d rotQuat = new Quat4d(); 520 // generates a quaternion to perform desired rotation 521 generateRotationQuaternion(rotAxis,angle,rotQuat); 522 tempT3D.set(rotQuat); 523 light.setTransform(tempT3D); 524 } 525 } 526 527 }

This page was automatically generated by Maven