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