Library of Assembled Shared Sources
transformation_3d.inl
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2025 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_TRANSFORMATION_3D_INL
44#define LASS_GUARDIAN_OF_INCLUSION_PRIM_TRANSFORMATION_3D_INL
45
46#include "transformation_3d.h"
47
48namespace lass
49{
50
51namespace prim
52{
53
54template <typename T> typename Transformation3D<T>::TImplPtr Transformation3D<T>::identity_ = Transformation3D<T>::makeIdentity();
55
56// --- public --------------------------------------------------------------------------------------
57
58/** construct an identity transformation.
59 * An identity transformation transforms every point to itself.
60 */
61template <typename T>
63 pimpl_(identity_),
64 isInversed_(false)
65{
66}
67
68
69
70/** construct an matrix from an origin and three base vectors
71 *
72 * @code
73 * TVector3D<T> i, j, k;
74 * TPoint3D<T> o, p;
75 * // ...
76 *
77 * Transformation3D<T> transformation(o, i, j, k);
78 * LASS_ASSERT(transform(p, transformation) == (o + i * p.x + j * p.y + k * p.z));
79 * @endcode
80 */
81template <typename T>
83 const TPoint& origin, const TVector& baseX, const TVector& baseY, const TVector& baseZ):
84 pimpl_(TImplPtr::allocate()),
85 isInversed_(false)
86{
87 TValue* mat = pimpl_->forward;
88 mat[ 0] = baseX.x; mat[ 1] = baseY.x; mat[ 2] = baseZ.x; mat[ 3] = origin.x;
89 mat[ 4] = baseX.y; mat[ 5] = baseY.y; mat[ 6] = baseZ.y; mat[ 7] = origin.y;
90 mat[ 8] = baseX.z; mat[ 9] = baseY.z; mat[10] = baseZ.z; mat[11] = origin.z;
91 mat[12] = 0; mat[13] = 0; mat[14] = 0; mat[15] = 1;
92}
93
94
95
96/** construct a transformation from a 4x4 tranformation matrix.
97 * The elements of the 4x4 matrix will represented in a row major way by an iterator
98 * range [first, last) of 16 elements.
99 */
100template <typename T>
101template <typename InputIterator>
102Transformation3D<T>::Transformation3D(InputIterator first, InputIterator last):
103 pimpl_(TImplPtr::allocate()),
104 isInversed_(false)
105{
106 LASS_ENFORCE(std::distance(first, last) == matrixSize_);
107 std::copy(first, last, pimpl_->forward);
108}
109
110
111
112/* construct a transformation fromo a 4x4 transformation matrix
113 The elements of the 4x4 matrix will be represented in a row major way by an
114 initializer_list of 16 elements
115 */
116template <typename T>
117Transformation3D<T>::Transformation3D(std::initializer_list<TValue> list):
118 pimpl_(TImplPtr::allocate()),
119 isInversed_(false)
120{
121 LASS_ENFORCE(list.size() == matrixSize_);
122 std::copy(list.begin(), list.end(), pimpl_->forward);
123}
124
125
126
127/** return the inverse transformation.
128 * The inverse is calculated on the first call, and then cached for later use.
129 * For the transformation, we've use the C version of Cramer's rule as described in
130 * the Intel (R) article "Streaming SIMD Extensions -Inverse of 4x4 Matrix" which
131 * can be found here: http://www.intel.com/design/pentiumiii/sml/245043.htm
132 */
133template <typename T>
137 computeInverse();
138 LASS_ASSERT(pimpl_->hasInverse);
139 return TSelf(pimpl_, !isInversed_);
140}
141
142
143
144/** Return pointer to row major matrix representation of transformation.
145 * This is for immediate use only, like @c std::basic_string::data().
146 */
147template <typename T> inline
148const typename Transformation3D<T>::TValue*
151 LASS_ASSERT(!(isInversed_ && !pimpl_->hasInverse));
152 return isInversed_ ? pimpl_->inverse : pimpl_->forward;
153}
154
155
156
157/** Return pointer to row major matrix representation of inverse transformation.
158 * This is for immediate use only, like @c std::basic_string::data().
159 */
160template <typename T> inline
161const typename Transformation3D<T>::TValue*
163{
164 computeInverse();
165 LASS_ASSERT(pimpl_->hasInverse);
166 return isInversed_ ? pimpl_->forward : pimpl_->inverse;
167}
168
169
170
171template <typename T>
172bool Transformation3D<T>::isIdentity() const
173{
174 if (pimpl_ == identity_)
175 {
176 return true;
177 }
178 const TValue* const forward = pimpl_->forward;
179 for (size_t i = 0; i < 4; ++i)
180 {
181 for (size_t j = 0; j < 4; ++j)
182 {
183 if (forward[i * 4 + j] != (i == j ? TNumTraits::one : TNumTraits::zero))
184 {
185 return false;
186 }
187 }
188 }
189 return true;
190}
191
192
193
194template <typename T>
195bool Transformation3D<T>::isTranslation() const
196{
197 if (pimpl_->isTranslation)
198 {
199 return true;
200 }
201 const TValue* const forward = pimpl_->forward;
202 for (size_t i = 0; i < 4; ++i)
203 {
204 for (size_t j = 0; j < 4; ++j)
205 {
206 if (j < 3 && forward[i * 4 + j] != (i == j ? TNumTraits::one : TNumTraits::zero))
207 {
208 return false;
209 }
210 }
211 }
212 return true;
213}
214
215
216
217template <typename T>
218void Transformation3D<T>::swap(TSelf& other)
219{
220 pimpl_.swap(other.pimpl_);
221 std::swap(isInversed_, other.isInversed_);
222}
223
224
225
226/** make a 3D identity transformation
227 */
228template <typename T>
230{
231 return TSelf();
232}
233
234
235
236/** make a 3D transformation representing a translation
237 */
238template <typename T>
240{
241 TImplPtr pimpl(TImplPtr::allocate());
242
243 TMatrix& forward = pimpl->forward;
244 identity(forward);
245 forward[ 3] = offset.x;
246 forward[ 7] = offset.y;
247 forward[11] = offset.z;
248
249 TMatrix& inverse = pimpl->inverse;
251 inverse[ 3] = -offset.x;
252 inverse[ 7] = -offset.y;
253 inverse[11] = -offset.z;
254
255 pimpl->hasInverse = true;
256 pimpl->isTranslation = true;
257
258 return TSelf(pimpl);
259}
260
261
262
263/** make a 3D transformation representing a uniform scaling
264 */
265template <typename T>
267{
268 TImplPtr pimpl(TImplPtr::allocate());
269
270 TMatrix& forward = pimpl->forward;
271 identity(forward);
272 forward[ 0] = forward[ 5] = forward[10] = scale;
273
274 TMatrix& inverse = pimpl->inverse;
276 inverse[ 0] = inverse[ 5] = inverse[10] = num::inv(scale);
277
278 pimpl->hasInverse = true;
279
280 return TSelf(pimpl);
281}
282
283
284
285/** make a 3D transformation representing a scaling with different factors per axis
286 */
287template <typename T>
289{
290 TImplPtr pimpl(TImplPtr::allocate());
291
292 TMatrix& forward = pimpl->forward;
293 identity(forward);
294 forward[ 0] = scale.x;
295 forward[ 5] = scale.y;
296 forward[10] = scale.z;
297
298 TMatrix& inverse = pimpl->inverse;
300 inverse[ 0] = num::inv(scale.x);
301 inverse[ 5] = num::inv(scale.y);
302 inverse[10] = num::inv(scale.z);
303
304 pimpl->hasInverse = true;
305
306 return TSelf(pimpl);
307}
308
309
310
311/** make a 3D transformation representing a rotation around a primary axis
312 */
313template <typename T>
315{
316 TImplPtr pimpl(TImplPtr::allocate());
317
318 const T c = num::cos(radians);
319 const T s = num::sin(radians);
320 const int a = (axis + 1);
321 const int b = (axis + 2);
322 LASS_ASSERT(a < 3 && b < 3);
323
324 TMatrix& forward = pimpl->forward;
325 identity(forward);
326 forward[5 * a] = c;
327 forward[5 * b] = c;
328 forward[4 * a + b] = -s;
329 forward[4 * b + a] = s;
330
331 TMatrix& inverse = pimpl->inverse;
333 inverse[5 * a] = c;
334 inverse[5 * b] = c;
335 inverse[4 * a + b] = s;
336 inverse[4 * b + a] = -s;
337
338 pimpl->hasInverse = true;
339
340 return TSelf(pimpl);
341}
342
343
344
345/** make a 3D transformation representing a rotation around an arbitrary axis
346 */
347template <typename T>
348const Transformation3D<T> Transformation3D<T>::rotation(const TVector& axis, TParam radians)
349{
350 TImplPtr pimpl(TImplPtr::allocate());
351
352 const TVector a = axis.normal();
353 const T c = num::cos(radians);
354 const T s = num::sin(radians);
355 const TValue oneMinusC = TNumTraits::one - c;
356
357 TMatrix& forward = pimpl->forward;
358 identity(forward);
359 forward[ 0] = a.x * a.x * oneMinusC + c;
360 forward[ 1] = a.x * a.y * oneMinusC - a.z * s;
361 forward[ 2] = a.x * a.z * oneMinusC + a.y * s;
362 forward[ 4] = a.y * a.x * oneMinusC + a.z * s;
363 forward[ 5] = a.y * a.y * oneMinusC + c;
364 forward[ 6] = a.y * a.z * oneMinusC - a.x * s;
365 forward[ 8] = a.z * a.x * oneMinusC - a.y * s;
366 forward[ 9] = a.z * a.y * oneMinusC + a.x * s;
367 forward[10] = a.z * a.z * oneMinusC + c;
368
369 translate(pimpl->forward, pimpl->inverse);
370
371 pimpl->hasInverse = true;
372
373 return TSelf(pimpl);
374}
375
376
377
378template <typename T>
379const Transformation3D<T> Transformation3D<T>::lookAt(const TPoint& eye, const TPoint& target, const TVector& sky)
380{
381 const TVector dir = target - eye;
382 const TVector right = cross(dir, sky);
383 const TVector up = cross(right, dir);
384 return Transformation3D<T>(eye, right.normal(), dir.normal(), up.normal());
385}
386
387
388
389// --- protected -----------------------------------------------------------------------------------
390
391
392
393// --- private -------------------------------------------------------------------------------------
394
395template <typename T> inline
396Transformation3D<T>::Transformation3D(const TImplPtr& impl, bool isInversed):
397 pimpl_(impl),
398 isInversed_(isInversed)
399{
400}
401
402
403
404template <typename T>
405void Transformation3D<T>::computeInverse() const
406{
407 if (pimpl_->hasInverse.load(std::memory_order_acquire))
408 {
409 return;
410 }
411
412 LASS_LOCK(pimpl_->sync)
413 {
414 if (pimpl_->hasInverse.load(std::memory_order_relaxed))
415 {
416 return;
417 }
418
419 const TConstMatrix& mat = pimpl_->forward;
420 TMatrix& inv = pimpl_->inverse;
421
422 const TValue v1015 = mat[10] * mat[15];
423 const TValue v1411 = mat[14] * mat[11];
424 const TValue v0615 = mat[ 6] * mat[15];
425 const TValue v1407 = mat[14] * mat[ 7];
426 const TValue v0611 = mat[ 6] * mat[11];
427 const TValue v1007 = mat[10] * mat[ 7];
428 const TValue v0215 = mat[ 2] * mat[15];
429 const TValue v1403 = mat[14] * mat[ 3];
430 const TValue v0211 = mat[ 2] * mat[11];
431 const TValue v1003 = mat[10] * mat[ 3];
432 const TValue v0207 = mat[ 2] * mat[ 7];
433 const TValue v0603 = mat[ 6] * mat[ 3];
434
435 inv[0] = v1015 * mat[ 5] + v1407 * mat[ 9] + v0611 * mat[13]
436 - v1411 * mat[ 5] - v0615 * mat[ 9] - v1007 * mat[13];
437 inv[1] = v1411 * mat[ 1] + v0215 * mat[ 9] + v1003 * mat[13]
438 - v1015 * mat[ 1] - v1403 * mat[ 9] - v0211 * mat[13];
439 inv[2] = v0615 * mat[ 1] + v1403 * mat[ 5] + v0207 * mat[13]
440 - v1407 * mat[ 1] - v0215 * mat[ 5] - v0603 * mat[13];
441 inv[3] = v1007 * mat[ 1] + v0211 * mat[ 5] + v0603 * mat[ 9]
442 - v0611 * mat[ 1] - v1003 * mat[ 5] - v0207 * mat[ 9];
443 inv[4] = v1411 * mat[ 4] + v0615 * mat[ 8] + v1007 * mat[12]
444 - v1015 * mat[ 4] - v1407 * mat[ 8] - v0611 * mat[12];
445 inv[5] = v1015 * mat[ 0] + v1403 * mat[ 8] + v0211 * mat[12]
446 - v1411 * mat[ 0] - v0215 * mat[ 8] - v1003 * mat[12];
447 inv[6] = v1407 * mat[ 0] + v0215 * mat[ 4] + v0603 * mat[12]
448 - v0615 * mat[ 0] - v1403 * mat[ 4] - v0207 * mat[12];
449 inv[7] = v0611 * mat[ 0] + v1003 * mat[ 4] + v0207 * mat[ 8]
450 - v1007 * mat[ 0] - v0211 * mat[ 4] - v0603 * mat[ 8];
451
452 const TValue v0813 = mat[ 8] * mat[13];
453 const TValue v1209 = mat[12] * mat[ 9];
454 const TValue v0413 = mat[ 4] * mat[13];
455 const TValue v1205 = mat[12] * mat[ 5];
456 const TValue v0409 = mat[ 4] * mat[ 9];
457 const TValue v0805 = mat[ 8] * mat[ 5];
458 const TValue v0013 = mat[ 0] * mat[13];
459 const TValue v1201 = mat[12] * mat[ 1];
460 const TValue v0009 = mat[ 0] * mat[ 9];
461 const TValue v0801 = mat[ 8] * mat[ 1];
462 const TValue v0005 = mat[ 0] * mat[ 5];
463 const TValue v0401 = mat[ 4] * mat[ 1];
464
465 inv[ 8] = v0813 * mat[ 7] + v1205 * mat[11] + v0409 * mat[15]
466 - v1209 * mat[ 7] - v0413 * mat[11] - v0805 * mat[15];
467 inv[ 9] = v1209 * mat[ 3] + v0013 * mat[11] + v0801 * mat[15]
468 - v0813 * mat[ 3] - v1201 * mat[11] - v0009 * mat[15];
469 inv[10] = v0413 * mat[ 3] + v1201 * mat[ 7] + v0005 * mat[15]
470 - v1205 * mat[ 3] - v0013 * mat[ 7] - v0401 * mat[15];
471 inv[11] = v0805 * mat[ 3] + v0009 * mat[ 7] + v0401 * mat[11]
472 - v0409 * mat[ 3] - v0801 * mat[ 7] - v0005 * mat[11];
473 inv[12] = v0413 * mat[10] + v0805 * mat[14] + v1209 * mat[ 6]
474 - v0409 * mat[14] - v0813 * mat[ 6] - v1205 * mat[10];
475 inv[13] = v0009 * mat[14] + v0813 * mat[ 2] + v1201 * mat[10]
476 - v0013 * mat[10] - v0801 * mat[14] - v1209 * mat[ 2];
477 inv[14] = v0013 * mat[ 6] + v0401 * mat[14] + v1205 * mat[ 2]
478 - v0005 * mat[14] - v0413 * mat[ 2] - v1201 * mat[ 6];
479 inv[15] = v0005 * mat[10] + v0409 * mat[ 2] + v0801 * mat[ 6]
480 - v0009 * mat[ 6] - v0401 * mat[10] - v0805 * mat[ 2];
481
482 const TValue det = mat[0] * inv[0] + mat[4] * inv[1] + mat[8] * inv[2] + mat[12] * inv[3];
483 if (det == TNumTraits::zero)
484 {
485 LASS_THROW_EX(util::SingularityError, "transformation not invertible");
486 }
487 const TValue invDet = num::inv(det);
488 for (size_t i = 0; i < matrixSize_; ++i)
489 {
490 inv[i] *= invDet;
491 }
492
493 pimpl_->hasInverse.store(true, std::memory_order_release);
494 }
495}
496
497
498
499template <typename T>
500void Transformation3D<T>::translate(const TConstMatrix& source, TMatrix& dest)
501{
502 for(size_t i = 0; i < 4; ++i)
503 {
504 for(size_t j = 0; j < 4; ++j)
505 {
506 dest[4 * i + j] = source[4 * j + i];
507 }
508 }
509}
510
511
512
513template <typename T>
514void Transformation3D<T>::identity(TMatrix& dest)
515{
516 static TConstMatrix mat =
517 {
518 1, 0, 0, 0,
519 0, 1, 0, 0,
520 0, 0, 1, 0,
521 0, 0, 0, 1,
522 };
523 std::copy(mat, mat + matrixSize_, dest);
524}
525
526
527
528template <typename T>
529typename Transformation3D<T>::TImplPtr Transformation3D<T>::makeIdentity()
530{
531 TImplPtr pimpl(TImplPtr::allocate());
532 identity(pimpl->forward);
533 identity(pimpl->inverse);
534 pimpl->hasInverse = true;
535 pimpl->isTranslation = true;
536 return pimpl;
537}
538
539
540
541// --- free ----------------------------------------------------------------------------------------
542
543/** concatenate two transformations @a first and @a second in one.
544 * @relates Transformation3D
545 * The result is one transformation that performs the same actions as first performing
546 * @a first and then @a second. Hence, the following lines of code are equivalent (ignoring
547 * numerical imprecions):
548 *
549 * @code
550 * y = transform(x, concatenate(first, second));
551 * y = transform(transform(x, first), second);
552 * @endcode
553 */
554template <typename T>
556{
557 // right-handed vector product, so it's @a second * @a first instead of @a first * @a second
558 const T* const a = second.matrix();
559 const T* const b = first.matrix();
560 T result[16];
561 for (size_t i = 0; i < 16; i += 4)
562 {
563 for (size_t j = 0; j < 4; ++j)
564 {
565 result[i + j] =
566 a[i ] * b[ j] +
567 a[i + 1] * b[ 4 + j] +
568 a[i + 2] * b[ 8 + j] +
569 a[i + 3] * b[12 + j];
570 }
571 }
572 return Transformation3D<T>(result, result + 16);
573}
574
575
576
577/** apply transformation to a vector
578 * @relates Transformation3D
579 */
580template <typename T>
581Vector3D<T> transform(const Vector3D<T>& subject, const Transformation3D<T>& transformation)
582{
583 const T* const mat = transformation.matrix();
584 return Vector3D<T>(
585 mat[ 0] * subject.x + mat[ 1] * subject.y + mat[ 2] * subject.z,
586 mat[ 4] * subject.x + mat[ 5] * subject.y + mat[ 6] * subject.z,
587 mat[ 8] * subject.x + mat[ 9] * subject.y + mat[10] * subject.z);
588}
589
590
591
592/** apply transformation to a point
593 * @relates Transformation3D
594 */
595template <typename T>
596Point3D<T> transform(const Point3D<T>& subject, const Transformation3D<T>& transformation)
597{
598 const T* const mat = transformation.matrix();
599 const T weight = num::inv(mat[12] * subject.x + mat[13] * subject.y + mat[14] * subject.z + mat[15]);
600 return Point3D<T>(
601 weight * (mat[ 0] * subject.x + mat[ 1] * subject.y + mat[ 2] * subject.z + mat[ 3]),
602 weight * (mat[ 4] * subject.x + mat[ 5] * subject.y + mat[ 6] * subject.z + mat[ 7]),
603 weight * (mat[ 8] * subject.x + mat[ 9] * subject.y + mat[10] * subject.z + mat[11]));
604
605}
606
607
608
609/** apply transformation to a normal vector.
610 * @relates Transformation3D
611 * Vectors that represent a normal vector should transform differentely than ordinary
612 * vectors. Use this transformation function for normals.
613 */
614template <typename T>
615Vector3D<T> normalTransform(const Vector3D<T>& subject, const Transformation3D<T>& transformation)
616{
617 const T* const invMat = transformation.inverseMatrix();
618 return Vector3D<T>(
619 invMat[ 0] * subject.x + invMat[ 4] * subject.y + invMat[ 8] * subject.z,
620 invMat[ 1] * subject.x + invMat[ 5] * subject.y + invMat[ 9] * subject.z,
621 invMat[ 2] * subject.x + invMat[ 6] * subject.y + invMat[10] * subject.z);
622}
623
624
625
626/** apply transformation to a 4D normal vector.
627 * @relates Transformation3D
628 * Vectors that represent a normal vector should transform differentely than ordinary
629 * vectors. Use this transformation function for normals.
630 *
631 * Cartesian planes have a 4D normal vector that must be transformed in 3D. Use this
632 * function to do it:
633 *
634 * @code
635 * // ax + by + cz + d == 0
636 * normalTransform(std::make_pair(Vector3D<float>(a, b, c), d), transformation);
637 * @endcode
638 */
639template <typename T>
640std::pair<Vector3D<T>, T> normalTransform(const std::pair<Vector3D<T>, T>& subject,
641 const Transformation3D<T>& transformation)
642{
643 const T* const invMat = transformation.inverseMatrix();
644 const Vector3D<T>& n = subject.first;
645 const T d = subject.second;
646 const Vector3D<T> transformedN(
647 invMat[ 0] * n.x + invMat[ 4] * n.y + invMat[ 8] * n.z + invMat[12] * d,
648 invMat[ 1] * n.x + invMat[ 5] * n.y + invMat[ 9] * n.z + invMat[13] * d,
649 invMat[ 2] * n.x + invMat[ 6] * n.y + invMat[10] * n.z + invMat[14] * d);
650 const T transformedD =
651 invMat[ 3] * n.x + invMat[ 7] * n.y + invMat[11] * n.z + invMat[15] * d;
652 return std::make_pair(transformedN, transformedD);
653}
654
655
656
657/** @relates Transformation3D
658 */
659template<typename T, typename Char, typename Traits>
660std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream,
661 const Transformation3D<T>& transformation)
662{
663 const T* const mat = transformation.matrix();
664 LASS_ENFORCE_STREAM(stream) << "(("
665 << mat[ 0] << ", " << mat[ 1] << ", " << mat[ 2] << ", " << mat[ 3] << "), ("
666 << mat[ 4] << ", " << mat[ 5] << ", " << mat[ 6] << ", " << mat[ 7] << "), ("
667 << mat[ 8] << ", " << mat[ 9] << ", " << mat[10] << ", " << mat[11] << "), ("
668 << mat[12] << ", " << mat[13] << ", " << mat[14] << ", " << mat[15] << "))";
669 return stream;
670}
671
672
673
674/** @relates Transformation3D
675 */
676template<typename T>
677io::XmlOStream& operator<<(io::XmlOStream& stream, const Transformation3D<T>& transformation)
678{
679 const T* const mat = transformation.matrix();
680 LASS_ENFORCE_STREAM(stream) << "<Transformation3D>"
681 << mat[ 0] << " " << mat[ 1] << " " << mat[ 2] << " " << mat[ 3] << " "
682 << mat[ 4] << " " << mat[ 5] << " " << mat[ 6] << " " << mat[ 7] << " "
683 << mat[ 8] << " " << mat[ 9] << " " << mat[10] << " " << mat[11] << " "
684 << mat[12] << " " << mat[13] << " " << mat[14] << " " << mat[15]
685 << "</Transformation3D>\n";
686 return stream;
687}
688
689
690
691}
692
693}
694
695#endif
Output stream for writing a selection of geometric primitives to XML files.
a linear 3D transformation
Transformation3D< T > concatenate(const Transformation3D< T > &first, const Transformation3D< T > &second)
concatenate two transformations first and second in one.
static const TSelf scaler(TParam scale)
make a 3D transformation representing a uniform scaling
Point3D< T > transform(const Point3D< T > &subject, const Transformation3D< T > &transformation)
apply transformation to a point
const TValue * inverseMatrix() const
Return pointer to row major matrix representation of inverse transformation.
Vector3D< T > transform(const Vector3D< T > &subject, const Transformation3D< T > &transformation)
apply transformation to a vector
static const TSelf translation(const TVector &offset)
make a 3D transformation representing a translation
const TSelf inverse() const
return the inverse transformation.
static const TSelf identity()
make a 3D identity transformation
const TValue * matrix() const
Return pointer to row major matrix representation of transformation.
static const TSelf rotation(XYZ axis, TParam radians)
make a 3D transformation representing a rotation around a primary axis
Transformation3D()
construct an identity transformation.
Vector3D< T > normalTransform(const Vector3D< T > &subject, const Transformation3D< T > &transformation)
apply transformation to a normal vector.
std::pair< Vector3D< T >, T > normalTransform(const std::pair< Vector3D< T >, T > &subject, const Transformation3D< T > &transformation)
apply transformation to a 4D normal vector.
cyclic iterator over xyz indices
Definition xyz.h:62
T inv(const T &x)
return x ^ -1
Definition basic_ops.h:178
T inv(const T &x)
return x ^ -1
#define LASS_LOCK(iLock)
Locks a iLock and starts a scope block in which it remains locked.
Definition thread.h:619
set of geometrical primitives
Definition aabb_2d.h:81
Library for Assembled Shared Sources.
Definition config.h:53
const Vector3D< T > normal() const
return a unit vector with same direction/sense as this vector.