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