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 import javax.media.j3d.*;
23 import javax.vecmath.*;
24 import java.util.*;
25 import javax.swing.Icon;
26 import camera3d.event.*;
27 import camera3d.manipulation.RotatableObject;
28 import camera3d.manipulation.TranslatableObject;
29 import camera3d.manipulation.ScalableObject;
30
31 /***
32 * Abstract superclass to all objects that can be added to the scene graph.
33 *
34 * @author Fábio Roberto de Miranda, Carlos da Silva dos Santos
35 */
36 public abstract class VcObject implements RotatableObject,
37 TranslatableObject,
38 ScalableObject {
39
40
41 private static final boolean autoComputeBounds = false;
42
43 private boolean debugflag = true;
44
45 String tooltipText;
46
47 /*** Holds rotation angles. */
48 Vector3f rotAngles;
49 /*** Holds local rotation angles. */
50 Vector3d localRotAngles;
51 /*** Holds translation values. */
52 Vector3d transVec;
53 /*** Holds scale values. */
54 Vector3d scaleVec;
55
56 /*** For local rotation values. */
57 Quat4d localRotQ4d;
58 /*** For rotation values. */
59 Quat4d rotQ4d;
60
61 //02-06-2002 Added temporary preallocated variables
62 Point3d tempP3d1 = new Point3d();
63 Point3d tempP3d2 = new Point3d();
64 Point3d tempP3d3 = new Point3d();
65 Vector3f tempVec3f = new Vector3f();
66
67 private static int instanceCounter = 0;
68
69 /*** Flag signaling if this object is undergoing a transformation. */
70 private boolean transforming=false;
71
72 // holds BoundingBox diagonal; used to set axis length
73 private double diagonal;
74 // indicates whether Bounding box geometry has already been created
75 private boolean bBoxCreated = false;
76
77 /*** Holds reference to objects which are interested in changes made to this object. */
78 private Vector changeListeners = new Vector(5, 3);
79 /*** Indicates whether positional components are updated. */
80 boolean invalidData = true;
81
82
83 // Reserved for future implementation of
84 // a service that calls back any objects
85 // that display any data related to this object
86 Vector propertyChangeListeners;
87
88 /*** Root BranchGroup for this object. */
89 BranchGroup bg;
90 BranchGroup decoratorsBG; // This branchGroup will hold elements that are not
91 // part of the object but can be used by the system,
92 // such as boundingBoxes and labels showing the object name
93
94 /*** Holds translation components. */
95 TransformGroup parentTransTG;
96 /*** Holds rotation and scale components. */
97 TransformGroup parentRotScaleTG;
98 TransformGroup pivotTG;
99
100 /*** Absolute axis system. */
101 Axis globalAxis;
102 /*** Local (object) axis system. */
103 Axis localAxis;
104
105 // used in misimported methods from CoreScene
106 Transform3D backupVPTransT3D = new Transform3D();
107 Transform3D tempTransT3D = new Transform3D();
108 //
109
110 Quat4d tempQ4d = new Quat4d();
111 Quat4d tempQ4d2 = new Quat4d();
112 Quat4d tempQ4d3 = new Quat4d();
113
114 Transform3D tempT3D = new Transform3D();
115 Transform3D auxT3D = new Transform3D();
116 Transform3D auxT3D2 = new Transform3D();
117 Transform3D backupT3D = new Transform3D();
118 private Transform3D tempRotT3D = new Transform3D();
119 private Transform3D tempRotT3D2 = new Transform3D();
120 Matrix3d tempRot = new Matrix3d();
121 Vector3d tempTrans = new Vector3d();
122
123 Vector3d tempVec3d = new Vector3d();
124 Vector3d tempScaleVec = new Vector3d();
125
126
127 String label;
128
129 private StringBuffer strBuffer = new StringBuffer();
130 BoundingBox boundingBox = new BoundingBox();
131 // the boxAvatarShape will be used to display the bounding box
132 // when necessary
133 Shape3D boxAvatarShape = new Shape3D();
134 BranchGroup shapeBG; // holds the boxAvatarShape
135
136 Point3d lowerP3d = new Point3d();
137 Point3d upperP3d = new Point3d();
138
139 private boolean selected = false;
140 /*** Holds reference to other VcObjects that are added as children to this one. */
141 List childrenList = new ArrayList();
142
143 // protected TransformType transformationType;
144 protected TransformMode transformationMode;
145
146 /*** Event that signal changes in this object's transform.*/
147 VcTransformChangedEvent transformEvent;
148 VcTranslationChangedEvent translationEvent;
149 VcRotationChangedEvent rotationEvent;
150 VcScaleChangedEvent scaleEvent;
151 /*** Event that signal changes in this object's label.*/
152 VcLabelChangedEvent labelEvent;
153
154 /*** Event that signal generic changes*/
155 VcObjectEvent genericEvent;
156
157 /*** Event that signals that a Node has been added to this object. */
158 VcNodeAddedEvent addNodeEvent;
159
160 /*** Event that signals that a Node has been removed from this object. */
161 VcNodeRemovedEvent removeNodeEvent;
162
163 /*** Event that signals that a VcObject has been added as a child to this object. */
164 VcChildAddedEvent addChildEvent;
165
166 /*** Event that signals that a VcObject that was a child to this object has been removed. */
167 VcChildRemovedEvent removeChildEvent;
168
169 /*** Holds most recent event generated by this object. */
170 VcObjectEvent currentEvent;
171
172 /***
173 * Default Constructor.
174 */
175 public VcObject() {
176 this.instanceCounter++;
177 bg = new BranchGroup();
178
179 assembleSubGraph(bg);
180
181 bg.setCapability(Group.ALLOW_CHILDREN_EXTEND);
182 bg.setCapability(Group.ALLOW_CHILDREN_WRITE);
183 bg.setCapability(Group.ALLOW_CHILDREN_READ);
184 bg.setCapability(BranchGroup.ALLOW_DETACH);
185 bg.setCapability(Node.ALLOW_PICKABLE_READ);
186 bg.setCapability(Node.ALLOW_PICKABLE_WRITE);
187 bg.setCapability(Node.ENABLE_PICK_REPORTING);
188 bg.setCapability(Node.ALLOW_BOUNDS_READ);
189 bg.setCapability(BranchGroup.ALLOW_LOCAL_TO_VWORLD_READ);
190 bg.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
191 bg.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
192 bg.setBoundsAutoCompute(autoComputeBounds);
193
194 rotAngles = new Vector3f();
195 localRotAngles = new Vector3d();
196 transVec = new Vector3d();
197 scaleVec = new Vector3d();
198 //localScaleVec = new Vector3d();
199 rotQ4d = new Quat4d();
200 localRotQ4d = new Quat4d();
201 updateData();
202 setInvalidData(true);
203
204 /* Sets this as the user data for picking purposes. */
205 bg.setUserData(this);
206 boxAvatarShape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
207 boxAvatarShape.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
208 boxAvatarShape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
209 boxAvatarShape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
210
211 shapeBG = new BranchGroup();
212 shapeBG.setCapability(BranchGroup.ALLOW_DETACH);
213 shapeBG.addChild(boxAvatarShape);
214
215 /* When any of the children of this BranchGroup collides,
216 * it is as if this bg collided
217 */
218 //bg.setAlternateCollisionTarget(true);
219 /*
220 * Allows the autocomputing of bounds for picking
221 */
222 //bg.setBoundsAutoCompute(true);
223
224 /* Makes this object pickable*/
225 bg.setPickable(true);
226
227 /* creates event objects; these will be reused any time the corresponding
228 event happens */
229 transformEvent = new VcTransformChangedEvent(this);
230 translationEvent = new VcTranslationChangedEvent(this);
231 rotationEvent = new VcRotationChangedEvent(this);
232 scaleEvent = new VcScaleChangedEvent(this);
233 labelEvent = new VcLabelChangedEvent(this);
234 genericEvent = new VcObjectEvent(this);
235 currentEvent = genericEvent;
236 }
237
238 /*** Rotates this object around local X axis.
239 *
240 * @param x_angle Rotation to be applied (in degreees).
241 */
242 public void rotateEulerLocalX(double x_angle){
243 this.rotateEulerLocal(x_angle, 0.0, 0.0);
244 }
245
246 /*** Rotates this object around local Y axis.
247 *
248 * @param y_angle Rotation to be applied (in degreees).
249 */
250 public void rotateEulerLocalY(double y_angle){
251 this.rotateEulerLocal(0.0, y_angle, 0.0);
252 }
253
254 /*** Rotates this object around local Z axis.
255 *
256 * @param z_angle Rotation to be applied (in degreees).
257 */
258 public void rotateEulerLocalZ(double z_angle){
259 this.rotateEulerLocal(0.0, 0.0, z_angle);
260 }
261
262 /***
263 * Rotates objects relative to its local coordinate system.
264 * At the end of execution notifyChangeListeners() is called.
265 * @param x_angle angle of rotation to be applied (X axis) in radians.
266 * @param y_angle angle of rotation to be applied (Y axis) in radians.
267 * @param z_angle angle of rotation to be applied (Z axis) in radians.
268 */
269 public void rotateEulerLocal(double x_angle, double y_angle, double z_angle){
270 debugln("rotate euler local: "+x_angle+" "+y_angle+" "+z_angle);
271 // Converted degree input to radians -- when input was in degrees.
272 /*
273 double x = Math.toRadians(x_angle);
274 double y = Math.toRadians(y_angle);
275 double z = Math.toRadians(z_angle);
276 */
277
278 // Vector with local rotation angles is updated.
279 localRotAngles.x = (float)x_angle;
280 localRotAngles.y = (float)y_angle;
281 localRotAngles.z = (float)z_angle;
282
283 parentRotScaleTG.getTransform(auxT3D);
284 auxT3D.getScale(scaleVec);
285 auxT3D.setScale(1.0);
286
287 tempT3D.setEuler(localRotAngles);
288
289 // local rotation is applied to parentRotScale transform by means of
290 // multiplication; after that we set the new transform.
291 auxT3D.mul(tempT3D);
292 auxT3D.setScale(scaleVec);
293 parentRotScaleTG.setTransform(auxT3D);
294
295 // data is set as invalid because we didn't update rotAngles Vector.
296 setInvalidData(true);
297 currentEvent = rotationEvent;
298 notifyChangeListeners();
299 }
300
301 /*
302 * Caution:
303 * The following methods cannot be used to perform manipulation by mouse
304 * in absolute mode.
305 * For instance, a call to rotateEulerX(angle) will not have the visual
306 * effect of a rotation around the X axis.
307 */
308
309 /***
310 * Sets the value of the rotation around the absolute X axis. Other angles remain
311 * unchanged. Field invalidData is set to false, as rotAngles is updated. Method
312 * notifyChangeListeners() is called at the end of execution.
313 *
314 * @param x_angle new value of X rotation (in degrees).
315 */
316 public void rotateEulerX(double x_angle){
317 rotAngles.x = (float)x_angle;
318 MathUtility.eulerToQuat(rotAngles.x, rotAngles.y, rotAngles.z, rotQ4d);
319 rotate(this.rotQ4d);
320 setInvalidData(false);
321 currentEvent = rotationEvent;
322 notifyChangeListeners();
323 }
324
325 /***
326 * Sets the value of the rotation around the absolute Y axis. Other angles remain
327 * unchanged. Field invalidData is set to false, as rotAngles is updated. Method
328 * notifyChangeListeners() is called at the end of execution.
329 *
330 * @param y_angle new value of Y rotation (in degrees).
331 */
332 public void rotateEulerY(double y_angle){
333 rotAngles.y = (float)y_angle;
334 MathUtility.eulerToQuat(rotAngles.x, rotAngles.y, rotAngles.z, rotQ4d);
335 rotate(this.rotQ4d);
336 setInvalidData(false);
337 currentEvent = rotationEvent;
338 notifyChangeListeners();
339 }
340
341 /***
342 * Sets the value of the rotation around the absolute Z axis. Other angles remain
343 * unchanged. Field invalidData is set to false, as rotAngles is updated. Method
344 * notifyChangeListeners() is called at the end of execution.
345 * @param z_angle new value of Z rotation (in degrees).
346 */
347 public void rotateEulerZ(double z_angle){
348 rotAngles.z = (float)z_angle;
349 MathUtility.eulerToQuat(rotAngles.x, rotAngles.y, rotAngles.z, rotQ4d);
350 rotate(this.rotQ4d);
351 setInvalidData(false);
352 currentEvent = rotationEvent;
353 notifyChangeListeners();
354 }
355
356 /***
357 * Sets the value of the rotation around the absolute X,Y and Z axis. Field invalidData
358 * is set to false, as rotAngles is updated. Method notifyChangeListeners() is called
359 * at the end of execution.
360 *
361 * @param x_angle new value of X rotation (in degrees).
362 * @param y_angle new value of Y rotation (in degrees).
363 * @param z_angle new value of Z rotation (in degrees).
364 */
365 public void rotateEuler(double x_angle, double y_angle, double z_angle){
366 debugln("rotate euler: "+x_angle+" "+y_angle+" "+z_angle);
367 /*
368 rotAngles.x = (float)Math.toRadians(x_angle);
369 rotAngles.y = (float)Math.toRadians(y_angle);
370 rotAngles.z = (float)Math.toRadians(z_angle);
371 */
372 rotAngles.x = (float)x_angle;
373 rotAngles.y = (float)y_angle;
374 rotAngles.z = (float)z_angle;
375
376
377 MathUtility.eulerToQuat(rotAngles.x, rotAngles.y, rotAngles.z, rotQ4d);
378 rotate(this.rotQ4d);
379
380 //following block uses setEuler method instead of quaternions
381 // to achieve the same effect
382 /*
383 parentRotScaleTG.getTransform(backupT3D);
384 tempVec3d.set(rotAngles);
385 tempT3D.setEuler(tempVec3d);
386 backupT3D.getScale(tempVec3d);
387 tempT3D.setScale(tempVec3d);
388 parentRotScaleTG.setTransform(tempT3D);
389 */
390
391 // as we update value of rotAngles, data remains valid
392 setInvalidData(false);
393 currentEvent = rotationEvent;
394 notifyChangeListeners();
395 }
396
397 /***
398 * Sets the rotation to the one described by the input quaternion.
399 * @param rotQ4d quaternion containing the new value of the rotation.
400 */
401 void rotate(Quat4d rotQ4d){
402
403 parentRotScaleTG.getTransform(tempT3D);
404 backupT3D.set(tempT3D);
405 tempT3D.getScale(tempVec3d);
406 //debugln("__PRIOR scale: "+tempVec3d.x+" "+tempVec3d.y+" "+tempVec3d.z);
407 //tempT3D.getScale(scaleVec);
408
409 tempRotT3D.set(rotQ4d);
410 tempRotT3D.setScale(tempVec3d);
411 //debugln("__AFTER scale: "+tempVec3d.x+" "+tempVec3d.y+" "+tempVec3d.z);
412 //tempRotT3D.setScale(scaleVec);
413 try {
414 parentRotScaleTG.setTransform(tempRotT3D);
415 } catch (BadTransformException bt){
416 parentRotScaleTG.setTransform(backupT3D);
417 }
418 // for the moment, it seems to be a better option to delegate to the methods that
419 // called this one the responsibility of notifying listeners
420 //setInvalidData(true);
421 //notifyChangeListeners();
422 }
423
424 public void rotateLocal(TransformScope axis, double deltaAngle){
425 if(axis==TransformScope.X) rotateEulerLocalX(deltaAngle);
426 if(axis==TransformScope.Y) rotateEulerLocalY(deltaAngle);
427 if(axis==TransformScope.Z) rotateEulerLocalZ(deltaAngle);
428 }
429
430 /***
431 * Performs incremental rotation around one of the absolute axis. It is suitable
432 * to be called by manipulators, in order to perform absolute rotation.<br>
433 * Method from RotatableObject interface.
434 * @param axis the axis around which the rotation will be performed.
435 * @param deltaAngle of the increment (in radians).
436 */
437 public void rotateAbsolute(TransformScope axis, double deltaAngle){
438 //double angle = Math.toRadians(deltaAngle)/2;
439 /*
440 double angle = deltaAngle/2;
441 double sin = Math.sin(angle);
442 double cos = Math.cos(angle);
443 if(axis==TransformScope.X){
444 tempQ4d.set(sin,0,0,cos);
445 }else if(axis==TransformScope.Y){
446 tempQ4d.set(0,sin,0,cos);
447 }else if(axis==TransformScope.Z){
448 tempQ4d.set(0,0,sin,cos);
449 }else{
450 // will default to X rotation
451 tempQ4d.set(sin,0,0,cos);
452 }*/
453 MathUtility.generateRotQuat(axis,deltaAngle,tempQ4d);
454 parentRotScaleTG.getTransform(auxT3D2);
455 auxT3D2.get(tempQ4d2);
456 tempQ4d.mul(tempQ4d2);
457 tempQ4d.normalize();
458 rotate(tempQ4d);
459 setInvalidData(true);
460 currentEvent = rotationEvent;
461 notifyChangeListeners();
462 }
463
464 /***
465 * Adds a node to pivot transform group.
466 * Method notifyChangeListeners() is called by the end of execution.
467 * @param n Node to be added.
468 */
469 public void addNode(Node n){
470 this.pivotTG.addChild(n);
471 // genericEvent.setType(VcObjectEvent.NODE_ADDED);
472 if(addNodeEvent==null){
473 addNodeEvent = new VcNodeAddedEvent(this,n);
474 }else addNodeEvent.setNode(n);
475
476 currentEvent = addNodeEvent;
477 notifyChangeListeners();
478 }
479
480
481 /***
482 * Removes a node from pivot transform group.
483 * Method notifyChangeListeners() is called at the end of execution.
484 * @param n Node to be removed.
485 */
486 public void removeNode(Node n){
487 this.pivotTG.removeChild(n);
488 //genericEvent.setType(VcObjectEvent.NODE_REMOVED);
489 if(removeNodeEvent==null){
490 removeNodeEvent = new VcNodeRemovedEvent(this,n);
491 }else removeNodeEvent.setNode(n);
492
493 currentEvent = removeNodeEvent;
494 notifyChangeListeners();
495 }
496
497 /***
498 * Removes all nodes currently under pivot transform group.
499 * Method notifyChangeListeners() is called at the end of execution.
500 */
501 public void removeAllNodes(){
502 this.pivotTG.removeAllChildren();
503 genericEvent.setType(VcObjectEvent.ALLNODES_REMOVED);
504 currentEvent = genericEvent;
505 notifyChangeListeners();
506 }
507
508
509 /***
510 * Returns root BranchGroup
511 * @return root BG
512 */
513 public BranchGroup getBranchGroup(){
514 return this.bg;
515 }
516
517 /*** Returns the label which identifies this object.
518 * @return String containing the label.
519 */
520 public String getLabel(){
521 return this.label;
522 }
523
524 /*** Sets the label which identifies this object. Listeners are notified after the change.
525 * @param s String containing new label.
526 */
527 public void setLabel(String s){
528 labelEvent.setOldLabel(this.label);
529 this.label = s;
530 labelEvent.setNewLabel(s);
531 currentEvent = labelEvent;
532 notifyChangeListeners();
533 }
534
535 /***
536 * Removes the BranchGroup from its parent in Java 3D tree.
537 */
538 public void detach(){
539 bg.detach();
540 genericEvent.setType(VcObjectEvent.OBJECT_DETACHED);
541 currentEvent = genericEvent;
542 // notifyChangeListeners();
543 }
544
545 /***
546 * Returns this object's translation into the Vector3d object passed as input.
547 */
548 public void getTranslation(Point3d transP3d){
549 transP3d.set(this.transVec);
550 }
551
552
553 // getLocal?Angle methods commented out on 05/08/2003, as they were never used.
554 /*** Returns the value (degrees) of X angle in local coordinate system.*/
555 /*
556 public double getLocalXAngle(){
557 //updateData();
558 return Math.toDegrees(localRotAngles.x);
559 }*/
560
561 /*** Returns the value (degrees) of Y angle in local coordinate system.*/
562 /*
563 public double getLocalYAngle(){
564 //updateData();
565 return Math.toDegrees(localRotAngles.y);
566 }*/
567
568 /*** Returns the value (degrees) of Z angle in local coordinate system.*/
569 /*
570 public double getLocalZAngle(){
571 //updateData();
572 return Math.toDegrees(localRotAngles.z);
573 }*/
574
575 /*** Returns the value (degrees) of X angle in absolute coordinate system.
576 */
577 public double getXAngleDeg(){
578 updateData();
579 return Math.toDegrees(rotAngles.x);
580 }
581
582 /*** Returns the value (degrees) of Y angle in absolute coordinate system.
583 */
584 public double getYAngleDeg(){
585 updateData();
586 return Math.toDegrees(rotAngles.y);
587 }
588
589 /*** Returns the value (degrees) of Z angle in absolute coordinate system.
590 */
591 public double getZAngleDeg(){
592 updateData();
593 return Math.toDegrees(rotAngles.z);
594 }
595
596
597 /*** Returns the value (radians) of X angle in absolute coordinate system.
598 */
599 public double getXAngleRad(){
600 updateData();
601 return rotAngles.x;
602 }
603
604 /*** Returns the value (radians) of Y angle in absolute coordinate system.
605 */
606 public double getYAngleRad(){
607 updateData();
608 return rotAngles.y;
609 }
610
611 /*** Returns the value (radians) of Z angle in absolute coordinate system.
612 */
613 public double getZAngleRad(){
614 updateData();
615 return rotAngles.z;
616 }
617
618
619 /*** Returns the value of translation in X axis direction.
620 */
621 public double getXTranslation(){
622 //updateData();
623 return transVec.x;
624 }
625
626 /*** Returns the value translation in Y axis direction.
627 */
628 public double getYTranslation(){
629 //updateData();
630 return transVec.y;
631 }
632
633 /*** Returns the value of translation in Z axis direction.
634 */
635 public double getZTranslation(){
636 //updateData();
637 return transVec.z;
638 }
639
640 /*** Returns the value of scale in X axis direction.
641 */
642 public double getXScale(){
643 // updateData();
644 return scaleVec.x;
645 }
646
647 /*** Returns the value of scale in Y axis direction.
648 * @return Y scale
649 */
650 public double getYScale(){
651 // updateData();
652 return scaleVec.y;
653 }
654
655 /*** Returns the value of scale in Z axis direction.
656 * @return Z scale
657 */
658 public double getZScale(){
659 // updateData();
660 return scaleVec.z;
661 }
662
663 /***
664 * Returns a Vector of rotation angles (X,Y,Z), corresponding to the Transform3D
665 * object given as input.
666 * Code derived from the one at Eric Reiss' Homepage, at:
667 * http://jamaica.ee.pitt.edu/Eric/java3d/rotation.htm
668 * Changes due to different order of multiplication of matrices (X.Y.Z in original code,
669 * Z.Y.X in present one). Also changed the name of some variables to use pre-allocated ones
670 * and thus reduce memory usage.
671 */
672 Vector3f getRotAngle(Transform3D t3D)
673 {
674 //System.out.println("___getRotAngle called");
675 // Matrix3d m1 = new Matrix3d();
676 double c,tRx,tRy;
677 //Vector3f Angles = new Vector3f();
678
679 t3D.get(tempRot);
680 //tempVec3f.y = (float)Math.asin(tempRot.getElement(0,2));
681 tempVec3f.y = (float)Math.asin(-tempRot.getElement(2,0));
682 c = Math.cos(tempVec3f.y);
683 if (Math.abs(c) > 0.00001)
684 {
685 tRx = tempRot.getElement(2,2)/c;
686 //tRy = -tempRot.getElement(1,2)/c;
687 tRy = tempRot.getElement(2,1)/c;
688 tempVec3f.x = (float)Math.atan2(tRy,tRx);
689 tRx = tempRot.getElement(0,0)/c;
690 //tRy = -tempRot.getElement(0,1)/c;
691 tRy = tempRot.getElement(1,0)/c;
692 tempVec3f.z = (float)Math.atan2(tRy,tRx);
693 }
694 else
695 {
696 // Gimbal lock has occurred
697 tempVec3f.x = (float)0.0;
698
699 //tRx = tempRot.getElement(1,1)/c;
700 //tRy = tempRot.getElement(1,0)/c;
701 // here we are using the fact that the rotation around X axii
702 // is zero, so cos(X) = 1 and sin(X) = 0, which simplifies some
703 // terms.
704 tRx = tempRot.getElement(1,1);
705 tRy = -tempRot.getElement(0,1);
706 tempVec3f.z = (float)Math.atan2(tRy,tRx);
707 }
708
709 if (tempVec3f.x < 0.0)
710 {
711 tempVec3f.x+=2*Math.PI;
712 }
713 else if (tempVec3f.x > (2*Math.PI))
714 {
715 tempVec3f.x-=2*Math.PI;
716 }
717 if (tempVec3f.y < 0.0)
718 {
719 tempVec3f.y+=2*Math.PI;
720 }
721 else if (tempVec3f.y > (2*Math.PI))
722 {
723 tempVec3f.y-=2*Math.PI;
724 }
725 if (tempVec3f.z < 0.0)
726 {
727 tempVec3f.z+=2*Math.PI;
728 }
729 else if (tempVec3f.z > (2*Math.PI))
730 {
731 tempVec3f.z-=2*Math.PI;
732 }
733 if ( ( tempVec3f.x < 0.001 ) && ( tempVec3f.x > -0.001 ) )
734 {
735 tempVec3f.x = (float)0.0;
736 }
737 if ( ( tempVec3f.y < 0.001 ) && ( tempVec3f.y > -0.001 ) )
738 {
739 tempVec3f.y = (float)0.0;
740 }
741 if ( ( tempVec3f.z < 0.001 ) && ( tempVec3f.z > -0.001 ) )
742 {
743 tempVec3f.z = (float)0.0;
744 }
745 if ( tempVec3f.x == 0.0)
746 {
747 tempVec3f.x = Math.abs(tempVec3f.x);
748 }
749 if ( tempVec3f.y == 0.0)
750 {
751 tempVec3f.y = Math.abs(tempVec3f.y);
752 }
753 if ( tempVec3f.z == 0.0)
754 {
755 tempVec3f.z = Math.abs(tempVec3f.z);
756 }
757 if ( tempVec3f.x == 2*Math.PI)
758 {
759 tempVec3f.x = (float)0.0;
760 }
761 if ( tempVec3f.y == 2*Math.PI)
762 {
763 tempVec3f.y = (float)0.0;
764 }
765 if ( tempVec3f.z == 2*Math.PI)
766 {
767 tempVec3f.z = (float)0.0;
768 }
769
770 return(tempVec3f);
771 }
772
773 public void updateData(){
774 debugln("VcObject.updateData() called");
775 if (invalidData){
776 debugln("VcObject.updateData(): data must be recalculated");
777 try {
778 parentTransTG.getTransform(tempT3D);
779 } catch (javax.media.j3d.RestrictedAccessException rte){
780 debugln("VcObject: Restricted access exception happened when trying to update data.");
781 setInvalidData(true);
782 //rte.printStackTrace();
783 }
784
785 // Finds translation values
786 tempT3D.get(transVec);
787
788 parentRotScaleTG.getTransform(tempT3D);
789 // Code below unnecessary since move to Quaternions.
790 // Finds value of x,y,and z angles
791 rotAngles = getRotAngle(tempT3D);
792 //
793 ///
794 tempT3D.getScale(scaleVec);
795 }
796 setInvalidData(false);
797 }
798
799 public void translateLocal(double x, double y, double z){
800 tempVec3d.x = x;
801 tempVec3d.y = y;
802 tempVec3d.z = z;
803
804 tempTransT3D.setIdentity();
805 tempTransT3D.setTranslation(tempVec3d);
806
807 // Extract the transform from local to vworld so that we know
808 // in world coordinates the value of the translation component present at tempT3D matrix
809 pivotTG.getLocalToVworld(auxT3D);
810
811 // Finds out the accumulated result of all transforms from the root of this object down to
812 // parentRotScaleTG
813 auxT3D.mul(tempTransT3D);
814
815 // Finds out the total translation
816 auxT3D.get(tempTrans);
817
818 /////Great place for new approach
819 ///////translate(tempTrans.x, tempTrans.y, tempTrans.z);
820 this.setTransform(auxT3D);
821
822 setInvalidData(true);
823 currentEvent = translationEvent;
824 notifyChangeListeners();
825 }
826
827
828 public void translate(double x, double y, double z){
829 transVec.x = x;
830 transVec.y = y;
831 transVec.z = z;
832
833 parentTransTG.getTransform(tempT3D); // copies the transform into tempT3D
834 backupVPTransT3D.set(tempT3D);
835
836 tempT3D.get(tempRot, tempTrans); // extracts rotational and scaling info
837 tempT3D.getScale(tempScaleVec);
838 tempRotT3D.setIdentity(); //resets the rotational transform
839
840 tempRotT3D.setRotation(tempRot); // reapply rotation, but we got rid of scaling component
841 tempT3D.setIdentity(); //resets transform
842
843 /* Assembles translation vector */
844 tempVec3d.x = x;
845 tempVec3d.y = y;
846 tempVec3d.z = z;
847
848 tempT3D.setTranslation(tempVec3d); //sets translation
849 tempT3D.setScale(tempScaleVec); //sets scaling again
850 tempT3D.mul(tempRotT3D); // restores rotation
851 try {
852 parentTransTG.setTransform(tempT3D);
853 } catch (BadTransformException bt) {
854 strBuffer.append(bt.getMessage());
855 strBuffer.append("\n\rBefore {");
856 strBuffer.append(backupVPTransT3D.toString());
857 strBuffer.append("}\nAfter:{");
858 strBuffer.append(tempT3D.toString());
859 strBuffer.append("}");
860 //canvas3d.enableMessage(strBuffer.toString());
861 debugln(strBuffer.toString());
862 parentTransTG.setTransform(backupVPTransT3D);
863 }
864 setInvalidData(true);
865 currentEvent = translationEvent;
866 notifyChangeListeners();
867 }
868
869 /***
870 * Sets this objects's absolute scale along (local) X axis. The notifyChangeListeners
871 * method is called at the end of execution.
872 * @param scale new absolute scale
873 */
874 public void scaleX(double scale){
875 parentRotScaleTG.getTransform(auxT3D);
876 scaleVec.x = scale;
877 auxT3D.setScale(scaleVec);
878 parentRotScaleTG.setTransform(auxT3D);
879 currentEvent = scaleEvent;
880 notifyChangeListeners();
881 }
882
883 /***
884 * Sets this objects's absolute scale along (local) Y axis. The notifyChangeListeners
885 * method is called at the end of execution.
886 * @param scale new absolute scale
887 */
888 public void scaleY(double scale){
889 parentRotScaleTG.getTransform(auxT3D);
890 scaleVec.y = scale;
891 auxT3D.setScale(scaleVec);
892 parentRotScaleTG.setTransform(auxT3D);
893 currentEvent = scaleEvent;
894 notifyChangeListeners();
895 }
896
897 /***
898 * Sets this objects's absolute scale along (local) Z axis. The notifyChangeListeners
899 * method is called at the end of execution.
900 * @param scale new absolute scale
901 */
902 public void scaleZ(double scale){
903 parentRotScaleTG.getTransform(auxT3D);
904 scaleVec.z = scale;
905 auxT3D.setScale(scaleVec);
906 parentRotScaleTG.setTransform(auxT3D);
907 currentEvent = scaleEvent;
908 notifyChangeListeners();
909 }
910
911 public void scaleXRelative(double scale){
912 setRelativeScale(scale,1,1);
913 /*
914 parentRotScaleTG.getTransform(auxT3D);
915 tempT3D.setIdentity();
916 tempVec3d.x = scale;
917 tempVec3d.y = tempVec3d.z = 1.0;
918 tempT3D.setScale(tempVec3d);
919 auxT3D.mul(tempT3D);
920 parentRotScaleTG.setTransform(auxT3D);
921 auxT3D.getScale(scaleVec);
922 currentEvent = scaleEvent;
923 notifyChangeListeners();
924 */
925 }
926
927 public void scaleYRelative(double scale){
928 setRelativeScale(1,scale,1);
929 /*
930 parentRotScaleTG.getTransform(auxT3D);
931 tempT3D.setIdentity();
932 tempVec3d.y = scale;
933 tempVec3d.x = tempVec3d.z = 1.0;
934 tempT3D.setScale(tempVec3d);
935 auxT3D.mul(tempT3D);
936 parentRotScaleTG.setTransform(auxT3D);
937 auxT3D.getScale(scaleVec);
938 //setInvalidData(true);
939 currentEvent = scaleEvent;
940 notifyChangeListeners();
941 */
942 }
943
944 public void scaleZRelative(double scale){
945 setRelativeScale(1,1,scale);
946 /*
947 parentRotScaleTG.getTransform(auxT3D);
948 tempT3D.setIdentity();
949 tempVec3d.z = scale;
950 tempVec3d.x = tempVec3d.y = 1.0;
951 tempT3D.setScale(tempVec3d);
952 auxT3D.mul(tempT3D);
953 parentRotScaleTG.setTransform(auxT3D);
954 auxT3D.getScale(scaleVec);
955 //setInvalidData(true);
956 currentEvent = scaleEvent;
957 notifyChangeListeners();
958 */
959 }
960
961 /***
962 *
963 */
964 public void setRelativeScale(double x, double y, double z){
965 parentRotScaleTG.getTransform(auxT3D);
966
967 /* Places relative scale in tempT3D */
968 tempT3D.setIdentity();
969 tempVec3d.x = x;
970 tempVec3d.y = y;
971 tempVec3d.z = z;
972 tempT3D.setScale(tempVec3d);
973 /* Multiplies former and temporary transformations */
974 auxT3D.mul(tempT3D);
975
976 /* Retrieves new value of this object's scale. */
977 auxT3D.getScale(scaleVec);
978
979 parentRotScaleTG.setTransform(auxT3D);
980 currentEvent = scaleEvent;
981 notifyChangeListeners();
982 }
983
984 /***
985 * Sets absolute scale for this object. The notifyChangeListeners method is called
986 * at the end of execution.
987 * @param x scale value along local X axis.
988 * @param y scale value along local Y axis.
989 * @param z scale value along local Z axis.
990 */
991 public void setAbsoluteScale(double x, double y, double z){
992 parentRotScaleTG.getTransform(auxT3D);
993 scaleVec.x = x;
994 scaleVec.y = y;
995 scaleVec.z = z;
996 auxT3D.setScale(scaleVec);
997 parentRotScaleTG.setTransform(auxT3D);
998 auxT3D.getScale(scaleVec);
999 currentEvent = scaleEvent;
1000 notifyChangeListeners();
1001 }
1002
1003 /*
1004 * This method must be called inside any other method that changes the state
1005 * of this object.
1006 */
1007 void notifyChangeListeners(){
1008 Iterator iter = changeListeners.iterator();
1009 while (iter.hasNext()){
1010 ((VcObjectChangeListener)iter.next()).vcObjectChanged(currentEvent);
1011 }
1012 }
1013
1014 /***
1015 * Removes all objects currently registered as listeners of changes made to this
1016 * object.
1017 */
1018 public void removeAllChangeListeners(){
1019 changeListeners.removeAllElements();
1020 }
1021
1022 /***
1023 * Removes one object currently registered as a listener of changes made to this
1024 * object.
1025 */
1026 public void removeChangeListener(VcObjectChangeListener chg){
1027 changeListeners.remove(chg);
1028 }
1029
1030 /***
1031 * Adds the specified VcObjectChangeListener to be notified of changes made
1032 * to this object. The updateData method is called prior to the addition.
1033 * @param listener Listener to be added
1034 */
1035 public void addChangeListener(VcObjectChangeListener listener){
1036 updateData();
1037 changeListeners.add(listener);
1038 }
1039
1040 /*
1041 * This method indicates that values previously extracted from
1042 * Transform matrices need to be recomputed
1043 */
1044 private void setInvalidData(boolean b){
1045 this.invalidData = b;
1046 }
1047
1048 /***
1049 * Convenience method for printing debug information
1050 * @param s Debug string to be printed
1051 */
1052 void debugln(String s){
1053 if (GUIControl.debugflag){
1054 //if(debugflag){
1055 System.out.println(s);
1056 }
1057 }
1058
1059 /***
1060 * Returns parameters of this object's BoundingBox, in local coordinates.
1061 * The settings of current BoundingBox are copied into returnBB.
1062 */
1063 public void getBoundingBox(BoundingBox returnBB){
1064 if(returnBB!=null){
1065 if(boundingBox!=null){
1066 boundingBox.getLower(tempP3d1);
1067 returnBB.setLower(tempP3d1);
1068 boundingBox.getUpper(tempP3d1);
1069 returnBB.setUpper(tempP3d1);
1070 }
1071 }
1072 }
1073
1074 void computeBoundingBox(){
1075 GeometryUtility.computeBoundingBox(this.getBranchGroup(),
1076 this.boundingBox);
1077
1078 }
1079
1080 public void showBoundingBox(){
1081 //computeBoundingBox();
1082 //13/05/2002 - prevents multiple execution
1083 if(!bBoxCreated){
1084 Color3f color = new Color3f(0.0f, 1.0f, 0.4f);
1085 GeometryUtility.createBoxGeometry(boundingBox, boxAvatarShape,color);
1086 // calculates diagonal of BoundingBox
1087 boundingBox.getUpper(tempP3d1);
1088 boundingBox.getLower(tempP3d2);
1089 this.diagonal = tempP3d2.distance(tempP3d1);
1090 bBoxCreated = true;
1091 }
1092 shapeBG.detach();
1093 this.decoratorsBG.addChild(shapeBG);
1094 }
1095
1096
1097 public void hideBoundingBox(){
1098 shapeBG.detach();
1099 //decoratorsBG.detach();
1100 }
1101
1102 public void removeBoundingBox(){
1103 if (decoratorsBG!=null){
1104 decoratorsBG.detach();
1105 }
1106 }
1107
1108 /***
1109 * Returns a flag indicating whether the object is part of a live scene graph.
1110 * @return true if object is part of a live scene graph, else false
1111 */
1112 public boolean isLive(){
1113 return this.bg.isLive();
1114 }
1115
1116 /***
1117 * Returns a flag indicating whether internal data representating state needs updating.
1118 */
1119 public boolean isInvalidData(){
1120 return this.invalidData;
1121 }
1122
1123
1124 /***
1125 * Adds a VcObject as a child to this one. Calling this method will have no effect if the
1126 * object given as parameter is already a live. Method notifyChangeListeners() is called
1127 * by the end of execution if the object could be added.
1128 * @param vcObject object to be added
1129 */
1130 public void addVcChild(VcObject vcObject){
1131 if(childrenList.contains(vcObject)){
1132 debugln("Error: "+this.getLabel()+" already contains "+vcObject.getLabel());
1133 }
1134 else{
1135 if(vcObject.bg.isLive()){
1136 debugln("Error: "+vcObject.label+" is live");
1137 }
1138 else{
1139 this.parentRotScaleTG.addChild(vcObject.bg);
1140 childrenList.add(vcObject);
1141 if(addChildEvent==null){
1142 addChildEvent = new VcChildAddedEvent(this,vcObject);
1143 }else addChildEvent.setChild(vcObject);
1144 currentEvent = addChildEvent;
1145 notifyChangeListeners();
1146 }
1147 }
1148 }
1149
1150 /***
1151 * Removes a VcObject from child transform group.
1152 * Method notifyChangeListeners() is called at the end of execution.
1153 * @param vcObject object to be removed
1154 */
1155 public void removeVcChild(VcObject vcObject){
1156 if(childrenList.contains(vcObject)){
1157 childrenList.remove(vcObject);
1158 parentRotScaleTG.removeChild(vcObject.bg);
1159 if(removeChildEvent==null){
1160 removeChildEvent = new VcChildRemovedEvent(this,vcObject);
1161 }else removeChildEvent.setChild(vcObject);
1162
1163 currentEvent = removeChildEvent;
1164 notifyChangeListeners();
1165 } else debugln("Error: "+vcObject.label+" was not child of "+this.label);
1166 }
1167
1168 /***
1169 * Removes a VcObject from child transform group.
1170 * Method notifyChangeListeners() is called at the end of execution.
1171 * @param n index of object to be removed
1172 */
1173 public void removeVcChild(int n){
1174 if(n<childrenList.size()){
1175 VcObject obj = (VcObject) childrenList.get(n);
1176 removeVcChild(obj);
1177 } else debugln("Error: number of children < "+n);
1178 }
1179
1180 /***
1181 * Returns a List containing all VcObjects kept as children of
1182 * this object
1183 * @return list of children
1184 */
1185 public List getChildrenList(){
1186 return this.childrenList;
1187 }
1188
1189 /***
1190 * Sets this object transform. The Transform3D passed as input is separated
1191 * into a translational component and a rotation-and-scaling component.
1192 */
1193 public void setTransform(Transform3D transform){
1194 //printTransform(transform);
1195 //this.parentTransTG.setTransform(transform);
1196
1197 transform.get(tempRot, tempTrans);
1198 tempT3D.setIdentity();
1199 tempT3D.setTranslation(tempTrans);
1200 parentTransTG.setTransform(tempT3D);
1201 tempT3D.setIdentity();
1202 tempT3D.setRotationScale(tempRot);
1203 // updates rotation angles
1204 rotAngles = getRotAngle(tempT3D);
1205 //tempT3D.setScale(1.0);
1206 parentRotScaleTG.setTransform(tempT3D);
1207
1208 //this.tg.setTransform(transform);
1209 setInvalidData(true);
1210 //updateData();
1211 currentEvent = transformEvent;
1212 notifyChangeListeners();
1213 }
1214
1215 /***
1216 * Returns parameters of this object's BoundingBox, in virtual world coordinates.
1217 * The settings of current BoundingBox are copied into returnBB.
1218 */
1219 public void getBoundingBoxInVWorld(BoundingBox returnBB){
1220 //
1221 pivotTG.getTransform(auxT3D);
1222 try {
1223 pivotTG.getLocalToVworld(tempT3D);
1224 } catch (CapabilityNotSetException ex) {
1225 debugln("Error in:"+this.getLabel());
1226 ex.printStackTrace();
1227 } catch (RestrictedAccessException ex){
1228 debugln("Could not get Local to VWorld for "+this.getLabel()+", exception stack trace");
1229 ex.printStackTrace();
1230 }
1231 tempT3D.mul(auxT3D);
1232 boundingBox.getLower(lowerP3d);
1233 boundingBox.getUpper(upperP3d);
1234 tempT3D.transform(lowerP3d);
1235 tempT3D.transform(upperP3d);
1236 returnBB.setLower(lowerP3d);
1237 returnBB.setUpper(upperP3d);
1238 }
1239
1240 /* Shows/Hides an object representing the global axis for this object*/
1241 public void setGlobalAxisVisible(boolean visible){
1242 // hides localAxis if we are to show global axis
1243 if(visible) localAxis.setVisible(false);
1244 globalAxis.setVisible(visible);
1245 }
1246
1247 /* Shows/Hides an object representing the local axis for this object*/
1248 public void setLocalAxisVisible(boolean visible){
1249 // hides localAxis if we are to show global axis
1250 if(visible) globalAxis.setVisible(false);
1251 localAxis.setVisible(visible);
1252 }
1253
1254 /*
1255 * Assembles internal graph.
1256 * 27/03/2003 - changed methos access from public to private
1257 */
1258 private void assembleSubGraph(BranchGroup root){
1259 decoratorsBG = new BranchGroup();
1260 parentTransTG = new TransformGroup();
1261 parentRotScaleTG = new TransformGroup();
1262 pivotTG = new TransformGroup();
1263 globalAxis = new Axis();
1264 localAxis = new Axis();
1265
1266 decoratorsBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
1267 decoratorsBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
1268 decoratorsBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
1269
1270 parentTransTG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
1271 parentTransTG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
1272 parentTransTG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
1273 parentTransTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
1274 parentTransTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
1275 parentTransTG.setCapability(TransformGroup.ALLOW_LOCAL_TO_VWORLD_READ);
1276 //parentTransTG.setBoundsAutoCompute(true);
1277 parentTransTG.setBoundsAutoCompute(true);
1278 parentTransTG.setCapability(Node.ENABLE_PICK_REPORTING);
1279 parentTransTG.setPickable(true);
1280
1281 parentRotScaleTG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
1282 parentRotScaleTG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
1283 parentRotScaleTG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
1284 parentRotScaleTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
1285 parentRotScaleTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
1286 parentRotScaleTG.setCapability(TransformGroup.ALLOW_LOCAL_TO_VWORLD_READ);
1287 //parentRotScaleTG.setBoundsAutoCompute(true);
1288 parentRotScaleTG.setBoundsAutoCompute(false);
1289 parentRotScaleTG.setCapability(Node.ENABLE_PICK_REPORTING);
1290 parentRotScaleTG.setPickable(true);
1291
1292
1293 pivotTG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
1294 pivotTG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
1295 pivotTG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
1296 pivotTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
1297 pivotTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
1298 pivotTG.setCapability(TransformGroup.ALLOW_LOCAL_TO_VWORLD_READ);
1299 //pivotTG.setBoundsAutoCompute(true);
1300 pivotTG.setBoundsAutoCompute(false);
1301 pivotTG.setCapability(Node.ENABLE_PICK_REPORTING);
1302 pivotTG.setPickable(true);
1303
1304 // Assemble subtree
1305 root.addChild(parentTransTG);
1306
1307 parentTransTG.addChild(globalAxis.getRootGroup());
1308 parentTransTG.addChild(parentRotScaleTG);
1309
1310 parentRotScaleTG.addChild(pivotTG);
1311 parentRotScaleTG.addChild(localAxis.getRootGroup());
1312 parentRotScaleTG.addChild(decoratorsBG);
1313 globalAxis.setVisible(false);
1314 localAxis.setVisible(false);
1315 }
1316
1317 public void printTransform(Transform3D t3d){
1318 if (GUIControl.debugflag){
1319 t3d.get(tempRot, tempTrans);
1320 debugln("Rotation: \n"+tempRot.m00+" "+tempRot.m01+" "+tempRot.m02+ " "+
1321 tempRot.m10+" "+tempRot.m11+" "+tempRot.m12+ " "+
1322 tempRot.m20+" "+tempRot.m21+" "+tempRot.m22+ " ");
1323 debugln("Translation: "+tempTrans.x+" "+tempTrans.y+" "+tempTrans.z);
1324 }
1325 }
1326
1327 protected void setTransformsToIdentity(){
1328 auxT3D.setIdentity();
1329 parentTransTG.setTransform(auxT3D);
1330 parentRotScaleTG.setTransform(auxT3D);
1331 pivotTG.setTransform(auxT3D);
1332 notifyChangeListeners();
1333 }
1334
1335
1336 public String getInfo(){
1337 String info = getLabel() +"\nTranslation:\t"+ "X: "+getXTranslation()+ " Y: "+getYTranslation()+
1338 " Z: "+getZTranslation()+ "\nRotation:\t\t" + "X: "+getXAngleDeg()+ " Y: "+getYAngleDeg()+
1339 " Z: "+getZAngleDeg() + "\n\n";
1340 return info;
1341 }
1342
1343
1344
1345 /***
1346 * By calling this object this object shows himself "selected", what is indicated
1347 * by some visual modifications.
1348 */
1349 public void select(){
1350 debugln(this.getLabel()+" selected");
1351 this.showBoundingBox();
1352 selected = true;
1353 localAxis.setVisible(true);
1354 // 13-05-2002
1355 // replaced call to DimensionsManager.getDimensionsManager().getAxisSize()
1356 // DimensionsManager keeps the axis size of the last object selected instead
1357 // of the current one; now the axis size is calculated internally (in createBoxGeometry)
1358 localAxis.setSize(this.diagonal);
1359 globalAxis.setSize(this.diagonal);
1360 }
1361
1362
1363 /*
1364 * By calling this method, this object shows itself unselected
1365 * 28-02-2002
1366 */
1367 public void unselect(){
1368 debugln(this.getLabel() +" unselect();");
1369 this.hideBoundingBox();
1370 globalAxis.setVisible(false);
1371 localAxis.setVisible(false);
1372 selected = false;
1373 }
1374
1375
1376 /*** Método para Luciano utilizar*/
1377 void lucianify(GeometryArray geometryArray, Transform3D t3D){
1378 Transform3D tempT3D = new Transform3D();
1379 Point3d tempP3d = new Point3d();
1380 tempT3D.set(t3D);
1381
1382 StringBuffer edgesStr = new StringBuffer(4000);
1383 StringBuffer facesStr = new StringBuffer(4000);
1384
1385 System.out.println("object {");
1386 if (geometryArray instanceof IndexedTriangleArray){
1387 IndexedTriangleArray tArray = (IndexedTriangleArray) geometryArray;
1388 int indexCount = tArray.getVertexCount();
1389 int vertexCount = tArray.getVertexCount();
1390
1391 for (int i=0; i < vertexCount; i++){
1392 tArray.getCoordinate(i, tempP3d);
1393 tempT3D.transform(tempP3d);
1394 System.out.println("vertex #"+i+"{"+tempP3d.x+","+tempP3d.y+","+tempP3d.z+"}");
1395 }
1396
1397 int edgeCounter = 0;
1398 int faceCounter = 0;
1399
1400 for (int j=0; j < indexCount - 1; j++){
1401 int index1 = tArray.getCoordinateIndex(j);
1402 int index2 = tArray.getCoordinateIndex(j+1);
1403 System.out.println("edge #"+(edgeCounter++)+" {"+index1+","+index2+"}");
1404 }
1405
1406 } else {
1407 System.out.println("Object to Lucianify doesn't have indexed triangles");
1408 }
1409 }
1410
1411
1412
1413 /***
1414 * Transforms euler angles into the corresponding rotation quaternion.
1415 * The order in which rotations are applied is:
1416 * roll(X axii)-->pitch(Y axii)-->yaw(Z axii)
1417 * Extracted from Nick Bobick's Gamasutra Code.
1418 * @param roll rotation around x axis
1419 * @param pitch rotation around y axis
1420 * @param yaw rotation around z axis
1421 */
1422 /*
1423 void eulerToQuat(double roll, double pitch, double yaw, Quat4d quat)
1424 {
1425 double cr, cp, cy, sr, sp, sy, cpcy, spsy;
1426 //
1427 The order in which rotations are applied is:
1428 roll(X axii)-->pitch(Y axii)-->yaw(Z axii)
1429 each rotation can be represented by a quaternion, say qr,qp and qy
1430 qr = cr + sr(1,0,0)
1431 qp = cp + sp(0,1,0)
1432 qy = cy + sy(0,0,1)
1433 Notes:
1434 - the first element of each quaternion is a scalar;
1435 - we use (X,Y,Z) triple to denote a vector;
1436 - the quaternion representing the combined rotations is:
1437 q = qy*qp*qr
1438
1439 if we represent a quaternion as n + v, where n is the scalar part and
1440 v is the vector part, the product between quaternions q1 = n1 + v1 and
1441 q2 = n2 + v2 is given by:
1442 q1*q2 = n1*n2 - v1.v2 + n1*v2 + n2*v1 + v1xv2
1443 where:
1444 * -> product by an scalar
1445 . -> internal product
1446 x -> cross product
1447
1448 thus:
1449 qy*qp = cp*cy + (-sp*sy,cy*sp,cp*sy)
1450 and:
1451 (qy*qp)*qr = cr*cp*cy - sr*sp*sy +
1452 + (sr*cp*cy - cr*sp*sy,
1453 cr*sp*cy + sr*cp*sy,
1454 cr*cp*sy - sr*sp*cy)
1455 //
1456
1457 //calculate trig identities
1458 cr = Math.cos(roll/2);
1459 cp = Math.cos(pitch/2);
1460 cy = Math.cos(yaw/2);
1461
1462 sr = Math.sin(roll/2);
1463 sp = Math.sin(pitch/2);
1464 sy = Math.sin(yaw/2);
1465
1466 cpcy = cp * cy;
1467 spsy = sp * sy;
1468
1469 quat.w = cr * cpcy + sr * spsy;
1470 quat.x = sr * cpcy - cr * spsy;
1471 quat.y = cr * sp * cy + sr * cp * sy;
1472 quat.z = cr * cp * sy - sr * sp * cy;
1473
1474 quat.normalize();
1475 }*/
1476
1477
1478 /***
1479 * Returns the transform 3D which keeps the translation part of this object's transform.
1480 * @param t3D Transform3D which will receive the parent translation transform.
1481 */
1482 public void getParentTransTG(Transform3D t3D){
1483 parentTransTG.getTransform(t3D);
1484 }
1485
1486 /***
1487 * Returns the transform 3D which keeps the rotation and scaling parts of this object's transform.
1488 * @param t3D Transform3D which will receive the parent rotation and scale transform.
1489 */
1490 public void getParentRotScaleTG(Transform3D t3D){
1491 parentRotScaleTG.getTransform(t3D);
1492 }
1493
1494 /***
1495 * Returns all accumulated transforms but pivot transforms.
1496 */
1497 public void getTransforms(Transform3D transforms){
1498 parentTransTG.getTransform(auxT3D);
1499 parentRotScaleTG.getTransform(tempT3D);
1500 auxT3D.mul(tempT3D);
1501 transforms.set(auxT3D);
1502 }
1503
1504 /***
1505 * Returns this objects Local to Vworld transform. Does not include pivot transform.
1506 * @param t3D object into which will be copied the required transform.
1507 */
1508 public void getLocalToVworld(Transform3D t3D){
1509 if(!this.isLive()){
1510 throw new RestrictedAccessException("Cannot get Local to Vworld transform: "+
1511 this.getLabel()+" is not live");
1512 }
1513 pivotTG.getLocalToVworld(t3D);
1514 }
1515
1516 /***
1517 * Sets flag used to indicate whether this object is undergoing a transformation or not.
1518 */
1519 public void setOngoingTransformation(boolean transforming){
1520 this.transforming = transforming;
1521 }
1522
1523 /***
1524 * Returns flag that indicates whether this object is undergoing a transformation or not.
1525 */
1526 public boolean underOngoingTransformation(){
1527 return transforming;
1528 }
1529
1530 /***
1531 * Sets a specific kind of transformation, useful for the displaying of gizmos, etc.
1532 *
1533 */
1534 public void setOngoingTransformationMode(TransformMode mode){
1535 //debugln(this.getLabel()+".setOnTransMode called");
1536
1537 this.transformationMode = mode;
1538 if (transformationMode == TransformMode.ABSOLUTE){
1539 globalAxis.setVisible(true);
1540 localAxis.setVisible(false);
1541 //debugln(this.getLabel()+" changed to absolute mode.");
1542 } else if (transformationMode == TransformMode.RELATIVE) {
1543 globalAxis.setVisible(false);
1544 localAxis.setVisible(true);
1545 //debugln(this.getLabel()+" changed to relative mode.");
1546 } else {
1547 //debugln(" transform mode set to "+mode.toString());
1548 }
1549 }
1550
1551 /***
1552 * Returns a flag indicating whether this object is selected or not
1553 * @return true if object is selected, false otherwise
1554 */
1555 public boolean isSelected(){
1556 return this.selected;
1557 }
1558
1559
1560 public void scaleRelative(TransformScope scope, double scale){
1561 if(scope==TransformScope.X) scaleXRelative(scale);
1562 if(scope==TransformScope.Y) scaleYRelative(scale);
1563 if(scope==TransformScope.Z) scaleZRelative(scale);
1564 if(scope==TransformScope.XYZ) setRelativeScale(scale,scale,scale);
1565 }
1566
1567
1568 /***
1569 * "Modern" translation method. It is more convenient to call this
1570 * from inside a translationManipulator
1571 */
1572 public void translate(Vector3d delta){
1573 //if(mode == TransformMode.ABSOLUTE){
1574 translate(delta.x, delta.y, delta.z);
1575 //}
1576 }
1577
1578 /*
1579 * Variant of method above
1580 */
1581 /*
1582 public void translate(double x, double y, double z, TransformMode mode){
1583 if(mode == TransformMode.ABSOLUTE){
1584 translate(x, y, z);
1585 }
1586 else if (mode == TransformMode.RELATIVE){
1587 translateLocal(x, y, z);
1588 }
1589 }*/
1590
1591
1592 /***
1593 * Returns a small Icon associated with the type of this object.
1594 */
1595 public abstract Icon getIcon();
1596
1597 /***
1598 * Sets the Icon associated with the type of this object.
1599 */
1600 public abstract void setIcon(Icon icon);
1601
1602 /***
1603 * Returns a string describing this object.
1604 * @return the tool tip
1605 */
1606 public String getTooltipText(){
1607 return this.tooltipText;
1608 }
1609
1610 /***
1611 * Returns the number of objects instatiated so far.
1612 */
1613 public static int getInstanceCounter(){
1614 return instanceCounter;
1615 }
1616
1617
1618
1619 /***
1620 * Sets a text string describing this object.
1621 * @param text the tool tip
1622 */
1623 public void setTooltipText(String text){
1624 this.tooltipText = text;
1625 }
1626
1627 /***
1628 * Calculates the normal and a point belonging to a plane.
1629 * Three points are given as input; the method calculates the vector normal
1630 * to the plane which contains the three input points.
1631 * @param planePoint point belonging to the plane (output parameter)
1632 * @param planeNormal vector normal to the plane (output parameter)
1633 * @param p1 input point 1
1634 * @param p2 input point 2
1635 * @param p3 input point 3
1636 */
1637 void buildPlanePointAndNormal(Point3d planePoint, Vector3d planeNormal, Point3d p1, Point3d p2, Point3d p3){
1638 planePoint.set(p1);
1639 planePoint.add(p2);
1640 planePoint.add(p3);
1641 // Planepoint averages other 3 points
1642 planePoint.x/=3;
1643 planePoint.y/=3;
1644 planePoint.z/=3;
1645 tempVec3d.sub(p1, p2);
1646 planeNormal.sub(p3, p2);
1647 planeNormal.cross(tempVec3d, planeNormal);
1648 planeNormal.normalize();
1649 }
1650
1651
1652 }
This page was automatically generated by Maven