1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif // HAVE_CONFIG_H
36 
37 #ifdef HAVE_VRML97
38 
39 /*!
40   \class SoVRMLTransform SoVRMLTransform.h Inventor/VRMLnodes/SoVRMLTransform.h
41   \brief The SoVRMLTransform class is a grouping node that defines a transformation for its children.
42 
43   \ingroup VRMLnodes
44 
45   \WEB3DCOPYRIGHT
46 
47   \verbatim
48   Transform {
49     eventIn      MFNode      addChildren
50     eventIn      MFNode      removeChildren
51     exposedField SFVec3f     center           0 0 0    # (-inf,inf)
52     exposedField MFNode      children         []
53     exposedField SFRotation  rotation         0 0 1 0  # [-1,1],(-inf,inf)
54     exposedField SFVec3f     scale            1 1 1    # (0,inf)
55     exposedField SFRotation  scaleOrientation 0 0 1 0  # [-1,1],(-inf,inf)
56     exposedField SFVec3f     translation      0 0 0    # (-inf,inf)
57     field        SFVec3f     bboxCenter       0 0 0    # (-inf,inf)
58     field        SFVec3f     bboxSize         -1 -1 -1 # (0,inf) or -1,-1,-1
59   }
60   \endverbatim
61 
62   The Transform node is a grouping node that defines a coordinate
63   system for its children that is relative to the coordinate systems
64   of its ancestors.  See 4.4.4, Transformation hierarchy
65   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.4.4>),
66   and 4.4.5, Standard units and coordinate system
67   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.4.5>),
68   for a description of coordinate systems and transformations.
69 
70   4.6.5, Grouping and children nodes
71   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.6.5>),
72   provides a description of the children, addChildren, and removeChildren
73   fields and eventIns.
74 
75   The bboxCenter and bboxSize fields specify a bounding box that
76   encloses the children of the Transform node. This is a hint that may
77   be used for optimization purposes. The results are undefined if the
78   specified bounding box is smaller than the actual bounding box of
79   the children at any time. A default bboxSize value, (-1, -1, -1),
80   implies that the bounding box is not specified and, if needed, shall
81   be calculated by the browser. The bounding box shall be large enough
82   at all times to enclose the union of the group's children's bounding
83   boxes; it shall not include any transformations performed by the
84   group itself (i.e., the bounding box is defined in the local
85   coordinate system of the children). The results are undefined if the
86   specified bounding box is smaller than the true bounding box of the
87   group. A description of the bboxCenter and bboxSize fields is
88   provided in 4.6.4, Bounding boxes
89   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.6.4>).
90 
91   The translation, rotation, scale, scaleOrientation and center fields
92   define a geometric 3D transformation consisting of (in order):
93 
94   - a (possibly) non-uniform scale about an arbitrary point;
95   - a rotation about an arbitrary point and axis;
96   - a translation.
97 
98   The \e center field specifies a translation offset from the origin
99   of the local coordinate system (0,0,0). The \e rotation field
100   specifies a rotation of the coordinate system. The \e scale field
101   specifies a non-uniform scale of the coordinate system. scale values
102   shall be greater than zero. The \e scaleOrientation specifies a
103   rotation of the coordinate system before the scale (to specify
104   scales in arbitrary orientations). The scaleOrientation applies only
105   to the scale operation.  The \e translation field specifies a
106   translation to the coordinate system.
107 
108   Given a 3-dimensional point
109   P and Transform node, P is transformed into point P' in its
110   parent's coordinate system by a series of intermediate
111   transformations. In matrix transformation notation, where C
112   (center), SR (scaleOrientation), T (translation), R (rotation), and
113   S (scale) are the equivalent transformation matrices,
114 
115   \verbatim
116   P' = T � C � R � SR � S � -SR � -C � P
117   \endverbatim
118 
119   The following Transform node:
120 
121   \verbatim
122   Transform {
123     center           C
124     rotation         R
125     scale            S
126     scaleOrientation SR
127     translation      T
128     children         [...]
129   }
130   \endverbatim
131 
132   is equivalent to the nested sequence of:
133 
134   \verbatim
135   Transform {
136     translation T
137     children Transform {
138       translation C
139       children Transform {
140         rotation R
141         children Transform {
142           rotation SR
143           children Transform {
144             scale S
145             children Transform {
146               rotation -SR
147               children Transform {
148                 translation -C
149                 children [...]
150               }
151             }
152           }
153         }
154       }
155     }
156   }
157   \endverbatim
158 
159 */
160 
161 /*!
162   \var SoSFVec3f SoVRMLTransform::translation
163   The translation vector. Default value is (0, 0, 0).
164 */
165 
166 /*!
167   \var SoSFRotation SoVRMLTransform::rotation
168   The rotation around the center point. Default value is null-rotation.
169 */
170 
171 /*!
172   \var SoSFVec3f SoVRMLTransform::scale
173   The scale vector about the center point. Default value is (1, 1, 1).
174 */
175 
176 /*!
177   \var SoSFRotation SoVRMLTransform::scaleOrientation
178   The scale orientation. Default value is a null-rotation.
179 */
180 
181 /*!
182   \var SoSFVec3f SoVRMLTransform::center
183   The center point. Default value is (0, 0, 0).
184 */
185 
186 
187 #include <Inventor/VRMLnodes/SoVRMLTransform.h>
188 
189 #include <Inventor/VRMLnodes/SoVRMLMacros.h>
190 #include <Inventor/actions/SoActions.h>
191 #include <Inventor/elements/SoModelMatrixElement.h>
192 #include <Inventor/misc/SoState.h>
193 #include <Inventor/misc/SoChildList.h>
194 
195 #include "nodes/SoSubNodeP.h"
196 
197 SO_NODE_SOURCE(SoVRMLTransform);
198 
199 // Doc in parent
200 void
initClass(void)201 SoVRMLTransform::initClass(void)
202 {
203   SO_NODE_INTERNAL_INIT_CLASS(SoVRMLTransform, SO_VRML97_NODE_TYPE);
204 }
205 
206 /*!
207   Constructor.
208 */
SoVRMLTransform(void)209 SoVRMLTransform::SoVRMLTransform(void)
210 {
211   this->commonConstructor();
212 }
213 
214 /*!
215   Constructor. \a numchildren is the expected number of children.
216 */
SoVRMLTransform(int numchildren)217 SoVRMLTransform::SoVRMLTransform(int numchildren)
218   : inherited(numchildren)
219 
220 {
221   this->commonConstructor();
222 }
223 
224 void
commonConstructor(void)225 SoVRMLTransform::commonConstructor(void)
226 {
227   SO_VRMLNODE_INTERNAL_CONSTRUCTOR(SoVRMLTransform);
228 
229   SO_VRMLNODE_ADD_EXPOSED_FIELD(translation, (0.0f, 0.0f, 0.0f));
230   SO_VRMLNODE_ADD_EXPOSED_FIELD(rotation, (SbRotation::identity()));
231   SO_VRMLNODE_ADD_EXPOSED_FIELD(scale, (1.0f, 1.0f, 1.0f));
232   SO_VRMLNODE_ADD_EXPOSED_FIELD(scaleOrientation, (SbRotation::identity()));
233   SO_VRMLNODE_ADD_EXPOSED_FIELD(center, (0.0f, 0.0f, 0.0f));
234 }
235 
236 /*!
237   Destructor
238 */
~SoVRMLTransform()239 SoVRMLTransform::~SoVRMLTransform()
240 {
241 }
242 
243 /*!
244   Sets the transformation to translate to \a frompoint, with a rotation
245   so that the (0,0,-1) vector is rotated into the vector from \a frompoint
246   to \a topoint.
247 */
248 void
pointAt(const SbVec3f & from,const SbVec3f & to)249 SoVRMLTransform::pointAt(const SbVec3f & from,
250                          const SbVec3f & to)
251 {
252   this->scale = SbVec3f(1.0f, 1.0f, 1.0f);
253   this->center = SbVec3f(0.0f, 0.0f, 0.0f);
254   this->scaleOrientation = SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f);
255 
256   this->translation = from;
257   SbVec3f dir = to - from;
258   dir.normalize();
259 
260   SbRotation rot(SbVec3f(0.0f, 0.0f, -1.0f), dir);
261   this->rotation = rot;
262 }
263 
264 /*!
265   Calculates the matrices to/from scale space.
266 */
267 void
getScaleSpaceMatrix(SbMatrix & matrix,SbMatrix & inverse) const268 SoVRMLTransform::getScaleSpaceMatrix(SbMatrix & matrix,
269                                      SbMatrix & inverse) const
270 {
271   SbMatrix tmp;
272   matrix.setTranslate(-center.getValue());
273   tmp.setRotate(scaleOrientation.getValue().inverse());
274   matrix.multRight(tmp);
275   tmp.setScale(scale.getValue());
276   matrix.multRight(tmp);
277   inverse = matrix.inverse();
278 }
279 
280 /*!
281   Calculates the matrices to/from rotation space.
282 */
283 void
getRotationSpaceMatrix(SbMatrix & matrix,SbMatrix & inverse) const284 SoVRMLTransform::getRotationSpaceMatrix(SbMatrix & matrix,
285                                         SbMatrix & inverse) const
286 {
287   SbMatrix tmp;
288   matrix.setTranslate(-this->center.getValue());
289   tmp.setRotate(this->scaleOrientation.getValue().inverse());
290   matrix.multRight(tmp);
291   tmp.setScale(this->scale.getValue());
292   matrix.multRight(tmp);
293   tmp.setRotate(this->scaleOrientation.getValue());
294   matrix.multRight(tmp);
295   tmp.setRotate(this->rotation.getValue());
296   matrix.multRight(tmp);
297   inverse = matrix.inverse();
298 }
299 
300 /*!
301   Calculates the matrices to/from translation space.
302 */
303 void
getTranslationSpaceMatrix(SbMatrix & matrix,SbMatrix & inverse) const304 SoVRMLTransform::getTranslationSpaceMatrix(SbMatrix & matrix,
305                                            SbMatrix & inverse) const
306 {
307   SbMatrix tmp;
308   matrix.setTranslate(-this->center.getValue());
309   tmp.setRotate(this->scaleOrientation.getValue().inverse());
310   matrix.multRight(tmp);
311   tmp.setScale(this->scale.getValue());
312   matrix.multRight(tmp);
313   tmp.setRotate(this->scaleOrientation.getValue());
314   matrix.multRight(tmp);
315   tmp.setRotate(this->rotation.getValue());
316   matrix.multRight(tmp);
317   tmp.setTranslate(this->center.getValue());
318   matrix.multRight(tmp);
319   tmp.setTranslate(this->translation.getValue());
320   matrix.multRight(tmp);
321   inverse = matrix.inverse();
322 }
323 
324 /*!
325   Premultiplies this transformation by \a mat.
326 */
327 void
multLeft(const SbMatrix & matrix)328 SoVRMLTransform::multLeft(const SbMatrix & matrix)
329 {
330   SbMatrix tmp;
331   tmp.setTransform(this->translation.getValue(),
332                    this->rotation.getValue(),
333                    this->scale.getValue(),
334                    this->scaleOrientation.getValue(),
335                    this->center.getValue());
336 
337   tmp.multLeft(matrix);
338   this->setMatrix(tmp);
339 }
340 
341 /*!
342   Postmultiplies this transformation by \a mat.
343 */
344 void
multRight(const SbMatrix & matrix)345 SoVRMLTransform::multRight(const SbMatrix & matrix)
346 {
347   SbMatrix tmp;
348   tmp.setTransform(this->translation.getValue(),
349                    this->rotation.getValue(),
350                    this->scale.getValue(),
351                    this->scaleOrientation.getValue(),
352                    this->center.getValue());
353   tmp.multRight(matrix);
354   this->setMatrix(tmp);
355 }
356 
357 void
358 /*!
359   Premultiplies this transformation by the transformation in \a leftnode.
360 */
combineLeft(SoVRMLTransform * leftnode)361 SoVRMLTransform::combineLeft(SoVRMLTransform * leftnode)
362 {
363   SoGetMatrixAction ma(SbViewportRegion(100,100));
364   ma.apply(leftnode);
365   this->multLeft(ma.getMatrix());
366 }
367 
368 /*!
369   Postmultiplies this transformation by the transformation in \a rightnode.
370 */
371 void
combineRight(SoVRMLTransform * rightnode)372 SoVRMLTransform::combineRight(SoVRMLTransform * rightnode)
373 {
374   SoGetMatrixAction ma(SbViewportRegion(100,100));
375   ma.apply(rightnode);
376   this->multRight(ma.getMatrix());
377 }
378 
379 /*!
380   Sets the fields to create a transformation equal to \a mat.
381 */
382 void
setMatrix(const SbMatrix & matrix)383 SoVRMLTransform::setMatrix(const SbMatrix & matrix)
384 {
385   SbVec3f t, s, c = this->center.getValue();
386   SbRotation r, so;
387   matrix.getTransform(t,r,s,so,c);
388 
389   this->translation = t;
390   this->rotation = r;
391   this->scale = s;
392   this->scaleOrientation = so;
393 }
394 
395 /*!
396   Sets the \e center field to \a newcenter. This might affect one
397   or more of the other fields.
398 */
399 void
recenter(const SbVec3f & newcenter)400 SoVRMLTransform::recenter(const SbVec3f & newcenter)
401 {
402   SbMatrix matrix;
403   matrix.setTransform(this->translation.getValue(),
404                       this->rotation.getValue(),
405                       this->scale.getValue(),
406                       this->scaleOrientation.getValue(),
407                       this->center.getValue());
408   SbVec3f t, s;
409   SbRotation r, so;
410   matrix.getTransform(t, r, s, so, newcenter);
411   this->translation = t;
412   this->rotation = r;
413   this->scale = s;
414   this->scaleOrientation = so;
415   this->center = newcenter;
416 }
417 
418 // Doc in parent
419 void
doAction(SoAction * action)420 SoVRMLTransform::doAction(SoAction * action)
421 {
422   SoState * state = action->getState();
423   state->push();
424   this->applyMatrix(state);
425   SoGroup::doAction(action);
426   state->pop();
427 }
428 
429 // Doc in parent
430 void
callback(SoCallbackAction * action)431 SoVRMLTransform::callback(SoCallbackAction * action)
432 {
433   SoState * state = action->getState();
434   state->push();
435   this->applyMatrix(state);
436   inherited::callback(action);
437   state->pop();
438 }
439 
440 // Doc in parent
441 void
getBoundingBox(SoGetBoundingBoxAction * action)442 SoVRMLTransform::getBoundingBox(SoGetBoundingBoxAction * action)
443 {
444   SoState * state = action->getState();
445   state->push();
446   this->applyMatrix(state);
447   inherited::getBoundingBox(action);
448   state->pop();
449 }
450 
451 // Doc in parent
452 void
getMatrix(SoGetMatrixAction * action)453 SoVRMLTransform::getMatrix(SoGetMatrixAction * action)
454 {
455   // need to push/pop to handle SoUnitsElement correctly
456   action->getState()->push();
457 
458   SbMatrix m;
459   m.setTransform(this->translation.getValue(),
460                  this->rotation.getValue(),
461                  this->scale.getValue(),
462                  this->scaleOrientation.getValue(),
463                  this->center.getValue());
464   action->getMatrix().multLeft(m);
465   SbMatrix mi = m.inverse();
466   action->getInverse().multRight(mi);
467 
468   SoGroup::getMatrix(action);
469   action->getState()->pop();
470 }
471 
472 // Doc in parent
473 void
rayPick(SoRayPickAction * action)474 SoVRMLTransform::rayPick(SoRayPickAction * action)
475 {
476   SoState * state = action->getState();
477   state->push();
478   this->applyMatrix(state);
479   inherited::rayPick(action);
480   state->pop();
481 }
482 
483 // Doc in parent
484 void
audioRender(SoAudioRenderAction * action)485 SoVRMLTransform::audioRender(SoAudioRenderAction * action)
486 {
487   SoVRMLTransform::doAction((SoAction*)action);
488 }
489 
490 // Doc in parent
491 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)492 SoVRMLTransform::getPrimitiveCount(SoGetPrimitiveCountAction * action)
493 {
494   SoState * state = action->getState();
495   state->push();
496   this->applyMatrix(state);
497   SoGroup::getPrimitiveCount(action);
498   state->pop();
499 }
500 
501 // Doc in parent
502 void
GLRenderBelowPath(SoGLRenderAction * action)503 SoVRMLTransform::GLRenderBelowPath(SoGLRenderAction * action)
504 {
505   SoState * state = action->getState();
506   state->push();
507   this->applyMatrix(state);
508   inherited::GLRenderBelowPath(action);
509   state->pop();
510 }
511 
512 // Doc in parent
513 void
GLRenderInPath(SoGLRenderAction * action)514 SoVRMLTransform::GLRenderInPath(SoGLRenderAction * action)
515 {
516   if (action->getCurPathCode() == SoAction::IN_PATH) {
517     SoState * state = action->getState();
518     state->push();
519     this->applyMatrix(state);
520     inherited::GLRenderInPath(action);
521     state->pop();
522   }
523   else {
524     // we got to the end of the path
525     this->GLRenderBelowPath(action);
526   }
527 }
528 
529 // Doc in parent
530 void
notify(SoNotList * list)531 SoVRMLTransform::notify(SoNotList * list)
532 {
533   inherited::notify(list);
534 }
535 
536 //
537 // applies transformation to state.
538 //
539 void
applyMatrix(SoState * state)540 SoVRMLTransform::applyMatrix(SoState * state)
541 {
542   SbMatrix matrix;
543   matrix.setTransform(this->translation.getValue(),
544                       this->rotation.getValue(),
545                       this->scale.getValue(),
546                       this->scaleOrientation.getValue(),
547                       this->center.getValue());
548   if (matrix != SbMatrix::identity()) {
549     SoModelMatrixElement::mult(state, this, matrix);
550   }
551 }
552 
553 #endif // HAVE_VRML97
554