Nirtcpp 2.1.0
Nirtcpp is a high-performance c++ graphics engine.
Loading...
Searching...
No Matches
quaternion.hpp
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in nirtcpp/nirtcpp.hpp
4
5#ifndef NIRT_QUATERNION_HPP_INCLUDED
6#define NIRT_QUATERNION_HPP_INCLUDED
7
8#include <nirtcpp/core/engine/nirt_types.hpp>
9#include <nirtcpp/core/engine/irrMath.hpp>
10#include <nirtcpp/core/engine/matrix4.hpp>
11#include <nirtcpp/core/engine/vector3d.hpp>
12
13// NOTE: You *only* need this when updating an application from Nirtcpp before 1.8 to Nirtcpp 1.8 or later.
14// Between Nirtcpp 1.7 and Nirtcpp 1.8 the quaternion-matrix conversions changed.
15// Before the fix they had mixed left- and right-handed rotations.
16// To test if your code was affected by the change enable NIRT_TEST_BROKEN_QUATERNION_USE and try to compile your application.
17// This defines removes those functions so you get compile errors anywhere you use them in your code.
18// For every line with a compile-errors you have to change the corresponding lines like that:
19// - When you pass the matrix to the quaternion constructor then replace the matrix by the transposed matrix.
20// - For uses of getMatrix() you have to use quaternion::getMatrix_transposed instead.
21// #define NIRT_TEST_BROKEN_QUATERNION_USE
22
23namespace nirt
24{
25namespace core
26{
27
29
32{
33 public:
34
36 quaternion() : X(0.0f), Y(0.0f), Z(0.0f), W(1.0f) {}
37
39 quaternion(f32 x, f32 y, f32 z, f32 w) : X(x), Y(y), Z(z), W(w) { }
40
42 quaternion(f32 x, f32 y, f32 z);
43
45 quaternion(const vector3df& vec);
46
47#ifndef NIRT_TEST_BROKEN_QUATERNION_USE
49 quaternion(const matrix4& mat);
50#endif
51
53 bool operator==(const quaternion& other) const;
54
56 bool operator!=(const quaternion& other) const;
57
58#ifndef NIRT_TEST_BROKEN_QUATERNION_USE
60 inline quaternion& operator=(const matrix4& other);
61#endif
62
65
69
71 quaternion operator*(f32 s) const;
72
75
77 vector3df operator*(const vector3df& v) const;
78
81
83 inline f32 dotProduct(const quaternion& other) const;
84
86 inline quaternion& set(f32 x, f32 y, f32 z, f32 w);
87
89 inline quaternion& set(f32 x, f32 y, f32 z);
90
92 inline quaternion& set(const core::vector3df& vec);
93
95 inline quaternion& set(const core::quaternion& quat);
96
98 inline bool equals(const quaternion& other,
99 const f32 tolerance = ROUNDING_ERROR_f32 ) const;
100
102 inline quaternion& normalize();
103
104#ifndef NIRT_TEST_BROKEN_QUATERNION_USE
106 matrix4 getMatrix() const;
107#endif
109 void getMatrixFast(matrix4 &dest) const;
110
113
132
134 inline void getMatrix_transposed( matrix4 &dest ) const;
135
138
140
150
152
160
162
174 f32 time, f32 threshold=.05f);
175
177
183
185 void toAngleAxis (f32 &angle, core::vector3df& axis) const;
186
188 void toEuler(vector3df& euler) const;
189
192
195
196 public:
198 f32 X; // vectorial (imaginary) part
199 f32 Y;
200 f32 Z;
201 f32 W; // real part
202};
203
204
205// Constructor which converts Euler angles to a quaternion
207{
208 set(x,y,z);
209}
210
211
212// Constructor which converts Euler angles to a quaternion
214{
215 set(vec.X,vec.Y,vec.Z);
216}
217
218#ifndef NIRT_TEST_BROKEN_QUATERNION_USE
219// Constructor which converts a matrix to a quaternion
221{
222 (*this) = mat;
223}
224#endif
225
226// equal operator
227inline bool quaternion::operator==(const quaternion& other) const
228{
229 return ((X == other.X) &&
230 (Y == other.Y) &&
231 (Z == other.Z) &&
232 (W == other.W));
233}
234
235// inequality operator
236inline bool quaternion::operator!=(const quaternion& other) const
237{
238 return !(*this == other);
239}
240
241
242#ifndef NIRT_TEST_BROKEN_QUATERNION_USE
243// matrix assignment operator
245{
246 const f32 diag = m[0] + m[5] + m[10] + 1;
247
248 if( diag > 0.0f )
249 {
250 const f32 scale = sqrtf(diag) * 2.0f; // get scale from diagonal
251
252 // TODO: speed this up
253 X = (m[6] - m[9]) / scale;
254 Y = (m[8] - m[2]) / scale;
255 Z = (m[1] - m[4]) / scale;
256 W = 0.25f * scale;
257 }
258 else
259 {
260 if (m[0]>m[5] && m[0]>m[10])
261 {
262 // 1st element of diag is greatest value
263 // find scale according to 1st element, and double it
264 const f32 scale = sqrtf(1.0f + m[0] - m[5] - m[10]) * 2.0f;
265
266 // TODO: speed this up
267 X = 0.25f * scale;
268 Y = (m[4] + m[1]) / scale;
269 Z = (m[2] + m[8]) / scale;
270 W = (m[6] - m[9]) / scale;
271 }
272 else if (m[5]>m[10])
273 {
274 // 2nd element of diag is greatest value
275 // find scale according to 2nd element, and double it
276 const f32 scale = sqrtf(1.0f + m[5] - m[0] - m[10]) * 2.0f;
277
278 // TODO: speed this up
279 X = (m[4] + m[1]) / scale;
280 Y = 0.25f * scale;
281 Z = (m[9] + m[6]) / scale;
282 W = (m[8] - m[2]) / scale;
283 }
284 else
285 {
286 // 3rd element of diag is greatest value
287 // find scale according to 3rd element, and double it
288 const f32 scale = sqrtf(1.0f + m[10] - m[0] - m[5]) * 2.0f;
289
290 // TODO: speed this up
291 X = (m[8] + m[2]) / scale;
292 Y = (m[9] + m[6]) / scale;
293 Z = 0.25f * scale;
294 W = (m[1] - m[4]) / scale;
295 }
296 }
297
298 return normalize();
299}
300#endif
301
302
303// multiplication operator
305{
307
308 tmp.W = (other.W * W) - (other.X * X) - (other.Y * Y) - (other.Z * Z);
309 tmp.X = (other.W * X) + (other.X * W) + (other.Y * Z) - (other.Z * Y);
310 tmp.Y = (other.W * Y) + (other.Y * W) + (other.Z * X) - (other.X * Z);
311 tmp.Z = (other.W * Z) + (other.Z * W) + (other.X * Y) - (other.Y * X);
312
313 return tmp;
314}
315
316
317// multiplication operator
319{
320 return quaternion(s*X, s*Y, s*Z, s*W);
321}
322
323
324// multiplication operator
326{
327 X*=s;
328 Y*=s;
329 Z*=s;
330 W*=s;
331 return *this;
332}
333
334// multiplication operator
336{
337 return (*this = other * (*this));
338}
339
340// add operator
342{
343 return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W);
344}
345
346#ifndef NIRT_TEST_BROKEN_QUATERNION_USE
347// Creates a matrix from this quaternion
349{
351 getMatrix(m);
352 return m;
353}
354#endif
355
358{
359 // TODO:
360 // gpu quaternion skinning => fast Bones transform chain O_O YEAH!
361 // http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf
362 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
363 dest[1] = 2.0f*X*Y + 2.0f*Z*W;
364 dest[2] = 2.0f*X*Z - 2.0f*Y*W;
365 dest[3] = 0.0f;
366
367 dest[4] = 2.0f*X*Y - 2.0f*Z*W;
368 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
369 dest[6] = 2.0f*Z*Y + 2.0f*X*W;
370 dest[7] = 0.0f;
371
372 dest[8] = 2.0f*X*Z + 2.0f*Y*W;
373 dest[9] = 2.0f*Z*Y - 2.0f*X*W;
374 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
375 dest[11] = 0.0f;
376
377 dest[12] = 0.f;
378 dest[13] = 0.f;
379 dest[14] = 0.f;
380 dest[15] = 1.f;
381
382 dest.setDefinitelyIdentityMatrix(false);
383}
384
389 const core::vector3df &center) const
390{
391 // ok creating a copy may be slower, but at least avoid internal
392 // state chance (also because otherwise we cannot keep this method "const").
393
394 quaternion q( *this);
395 q.normalize();
396 f32 X = q.X;
397 f32 Y = q.Y;
398 f32 Z = q.Z;
399 f32 W = q.W;
400
401 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
402 dest[1] = 2.0f*X*Y + 2.0f*Z*W;
403 dest[2] = 2.0f*X*Z - 2.0f*Y*W;
404 dest[3] = 0.0f;
405
406 dest[4] = 2.0f*X*Y - 2.0f*Z*W;
407 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
408 dest[6] = 2.0f*Z*Y + 2.0f*X*W;
409 dest[7] = 0.0f;
410
411 dest[8] = 2.0f*X*Z + 2.0f*Y*W;
412 dest[9] = 2.0f*Z*Y - 2.0f*X*W;
413 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
414 dest[11] = 0.0f;
415
416 dest[12] = center.X;
417 dest[13] = center.Y;
418 dest[14] = center.Z;
419 dest[15] = 1.f;
420
421 dest.setDefinitelyIdentityMatrix ( false );
422}
423
424
438 const core::vector3df &center,
439 const core::vector3df &translation) const
440{
441 quaternion q(*this);
442 q.normalize();
443 f32 X = q.X;
444 f32 Y = q.Y;
445 f32 Z = q.Z;
446 f32 W = q.W;
447
448 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
449 dest[1] = 2.0f*X*Y + 2.0f*Z*W;
450 dest[2] = 2.0f*X*Z - 2.0f*Y*W;
451 dest[3] = 0.0f;
452
453 dest[4] = 2.0f*X*Y - 2.0f*Z*W;
454 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
455 dest[6] = 2.0f*Z*Y + 2.0f*X*W;
456 dest[7] = 0.0f;
457
458 dest[8] = 2.0f*X*Z + 2.0f*Y*W;
459 dest[9] = 2.0f*Z*Y - 2.0f*X*W;
460 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
461 dest[11] = 0.0f;
462
463 dest.setRotationCenter ( center, translation );
464}
465
466// Creates a matrix from this quaternion
468{
469 quaternion q(*this);
470 q.normalize();
471 f32 X = q.X;
472 f32 Y = q.Y;
473 f32 Z = q.Z;
474 f32 W = q.W;
475
476 dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z;
477 dest[4] = 2.0f*X*Y + 2.0f*Z*W;
478 dest[8] = 2.0f*X*Z - 2.0f*Y*W;
479 dest[12] = 0.0f;
480
481 dest[1] = 2.0f*X*Y - 2.0f*Z*W;
482 dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z;
483 dest[9] = 2.0f*Z*Y + 2.0f*X*W;
484 dest[13] = 0.0f;
485
486 dest[2] = 2.0f*X*Z + 2.0f*Y*W;
487 dest[6] = 2.0f*Z*Y - 2.0f*X*W;
488 dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y;
489 dest[14] = 0.0f;
490
491 dest[3] = 0.f;
492 dest[7] = 0.f;
493 dest[11] = 0.f;
494 dest[15] = 1.f;
495
496 dest.setDefinitelyIdentityMatrix(false);
497}
498
499
500// Inverts this quaternion
502{
503 X = -X; Y = -Y; Z = -Z;
504 return *this;
505}
506
507
508// sets new quaternion
510{
511 X = x;
512 Y = y;
513 Z = z;
514 W = w;
515 return *this;
516}
517
518
519// sets new quaternion based on Euler angles
521{
522 f64 angle;
523
524 angle = x * 0.5;
525 const f64 sr = sin(angle);
526 const f64 cr = cos(angle);
527
528 angle = y * 0.5;
529 const f64 sp = sin(angle);
530 const f64 cp = cos(angle);
531
532 angle = z * 0.5;
533 const f64 sy = sin(angle);
534 const f64 cy = cos(angle);
535
536 const f64 cpcy = cp * cy;
537 const f64 spcy = sp * cy;
538 const f64 cpsy = cp * sy;
539 const f64 spsy = sp * sy;
540
541 X = (f32)(sr * cpcy - cr * spsy);
542 Y = (f32)(cr * spcy + sr * cpsy);
543 Z = (f32)(cr * cpsy - sr * spcy);
544 W = (f32)(cr * cpcy + sr * spsy);
545
546 return normalize();
547}
548
549// sets new quaternion based on Euler angles
551{
552 return set( vec.X, vec.Y, vec.Z);
553}
554
555// sets new quaternion based on other quaternion
557{
558 return (*this=quat);
559}
560
561
563inline bool quaternion::equals(const quaternion& other, const f32 tolerance) const
564{
565 return core::equals( X, other.X, tolerance) &&
566 core::equals( Y, other.Y, tolerance) &&
567 core::equals( Z, other.Z, tolerance) &&
569}
570
571
572// normalizes the quaternion
574{
575 // removed conditional branch since it may slow down and anyway the condition was
576 // false even after normalization in some cases.
577 return (*this *= (f32)reciprocal_squareroot ( (f64)(X*X + Y*Y + Z*Z + W*W) ));
578}
579
580// Set this quaternion to the result of the linear interpolation between two quaternions
582{
583 const f32 scale = 1.0f - time;
584 return (*this = (q1*scale) + (q2*time));
585}
586
587// Set this quaternion to the result of the linear interpolation between two quaternions and normalize the result
589{
590 const f32 scale = 1.0f - time;
591 return (*this = ((q1*scale) + (q2*time)).normalize() );
592}
593
594// set this quaternion to the result of the interpolation between two quaternions
596{
597 f32 angle = q1.dotProduct(q2);
598
599 // make sure we use the short rotation
600 if (angle < 0.0f)
601 {
602 q1 *= -1.0f;
603 angle *= -1.0f;
604 }
605
606 if (angle <= (1-threshold)) // spherical interpolation
607 {
608 const f32 theta = acosf(angle);
609 const f32 invsintheta = reciprocal(sinf(theta));
610 const f32 scale = sinf(theta * (1.0f-time)) * invsintheta;
611 const f32 invscale = sinf(theta * time) * invsintheta;
612 return (*this = (q1*scale) + (q2*invscale));
613 }
614 else // linear interpolation
615 return lerpN(q1,q2,time);
616}
617
618
619// calculates the dot product
621{
622 return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W);
623}
624
625
628{
629 const f32 fHalfAngle = 0.5f*angle;
630 const f32 fSin = sinf(fHalfAngle);
631 W = cosf(fHalfAngle);
632 X = fSin*axis.X;
633 Y = fSin*axis.Y;
634 Z = fSin*axis.Z;
635 return *this;
636}
637
638
640{
641 const f32 scale = sqrtf(X*X + Y*Y + Z*Z);
642
643 if (core::iszero(scale) || W > 1.0f || W < -1.0f)
644 {
645 angle = 0.0f;
646 axis.X = 0.0f;
647 axis.Y = 1.0f;
648 axis.Z = 0.0f;
649 }
650 else
651 {
652 const f32 invscale = reciprocal(scale);
653 angle = 2.0f * acosf(W);
654 axis.X = X * invscale;
655 axis.Y = Y * invscale;
656 axis.Z = Z * invscale;
657 }
658}
659
661{
662 const f64 sqw = W*W;
663 const f64 sqx = X*X;
664 const f64 sqy = Y*Y;
665 const f64 sqz = Z*Z;
666 const f64 test = 2.0 * (Y*W - X*Z);
667
668 if (core::equals(test, 1.0, 0.000001))
669 {
670 // heading = rotation about z-axis
671 euler.Z = (f32) (-2.0*atan2(X, W));
672 // bank = rotation about x-axis
673 euler.X = 0;
674 // attitude = rotation about y-axis
675 euler.Y = (f32) (core::PI64/2.0);
676 }
677 else if (core::equals(test, -1.0, 0.000001))
678 {
679 // heading = rotation about z-axis
680 euler.Z = (f32) (2.0*atan2(X, W));
681 // bank = rotation about x-axis
682 euler.X = 0;
683 // attitude = rotation about y-axis
684 euler.Y = (f32) (core::PI64/-2.0);
685 }
686 else
687 {
688 // heading = rotation about z-axis
689 euler.Z = (f32) atan2(2.0 * (X*Y +Z*W),(sqx - sqy - sqz + sqw));
690 // bank = rotation about x-axis
691 euler.X = (f32) atan2(2.0 * (Y*Z +X*W),(-sqx - sqy + sqz + sqw));
692 // attitude = rotation about y-axis
693 euler.Y = (f32) asin( clamp(test, -1.0, 1.0) );
694 }
695}
696
697
699{
700 // nVidia SDK implementation
701
703 const vector3df qvec(X, Y, Z);
704 uv = qvec.crossProduct(v);
705 uuv = qvec.crossProduct(uv);
706 uv *= (2.0f * W);
707 uuv *= 2.0f;
708
709 return v + uv + uuv;
710}
711
712// set quaternion to identity
714{
715 W = 1.f;
716 X = 0.f;
717 Y = 0.f;
718 Z = 0.f;
719 return *this;
720}
721
723{
724 // Based on Stan Melax's article in Game Programming Gems
725 // Copy, since cannot modify local
726 vector3df v0 = from;
727 vector3df v1 = to;
728 v0.normalize();
729 v1.normalize();
730
731 const f32 d = v0.dotProduct(v1);
732 if (d >= 1.0f) // If dot == 1, vectors are the same
733 {
734 return makeIdentity();
735 }
736 else if (d <= -1.0f) // exactly opposite
737 {
738 core::vector3df axis(1.0f, 0.f, 0.f);
739 axis = axis.crossProduct(v0);
740 if (axis.getLength()==0)
741 {
742 axis.set(0.f,1.f,0.f);
743 axis = axis.crossProduct(v0);
744 }
745 // same as fromAngleAxis(core::PI, axis).normalize();
746 return set(axis.X, axis.Y, axis.Z, 0).normalize();
747 }
748
749 const f32 s = sqrtf( (1+d)*2 ); // optimize inv_sqrt
750 const f32 invs = 1.f / s;
751 const vector3df c = v0.crossProduct(v1)*invs;
752 return set(c.X, c.Y, c.Z, s * 0.5f).normalize();
753}
754
755
756} // end namespace core
757} // end namespace nirt
758
759#endif
4x4 matrix. Mostly used as transformation matrix for 3d calculations.
Definition matrix4.hpp:49
Axis aligned bounding box in 3d dimensional space.
Definition aabbox3d.hpp:22
Quaternion class for representing rotations.
Definition quaternion.hpp:32
void toAngleAxis(f32 &angle, core::vector3df &axis) const
Fills an angle (radians) around an axis (unit vector)
Definition quaternion.hpp:639
quaternion & set(f32 x, f32 y, f32 z, f32 w)
Sets new quaternion.
Definition quaternion.hpp:509
quaternion & fromAngleAxis(f32 angle, const vector3df &axis)
Set this quaternion to represent a rotation from angle and axis.
Definition quaternion.hpp:627
quaternion & operator*=(f32 s)
Multiplication operator with scalar.
Definition quaternion.hpp:325
quaternion & rotationFromTo(const vector3df &from, const vector3df &to)
Set quaternion to represent a rotation from one vector to another.
Definition quaternion.hpp:722
bool equals(const quaternion &other, const f32 tolerance=ROUNDING_ERROR_f32) const
returns if this quaternion equals the other one, taking floating point rounding errors into account
Definition quaternion.hpp:563
quaternion(f32 x, f32 y, f32 z, f32 w)
Constructor.
Definition quaternion.hpp:39
quaternion operator+(const quaternion &other) const
Add operator.
Definition quaternion.hpp:341
quaternion & slerp(quaternion q1, quaternion q2, f32 time, f32 threshold=.05f)
Set this quaternion to the result of the spherical interpolation between two quaternions.
Definition quaternion.hpp:595
void getMatrix_transposed(matrix4 &dest) const
Creates a matrix from this quaternion.
Definition quaternion.hpp:467
quaternion & makeInverse()
Inverts this quaternion.
Definition quaternion.hpp:501
quaternion operator*(const quaternion &other) const
Definition quaternion.hpp:304
void getMatrixFast(matrix4 &dest) const
Faster method to create a rotation matrix, you should normalize the quaternion before!
Definition quaternion.hpp:357
bool operator==(const quaternion &other) const
Equality operator.
Definition quaternion.hpp:227
matrix4 getMatrix() const
Creates a matrix from this quaternion.
Definition quaternion.hpp:348
quaternion & operator=(const matrix4 &other)
Matrix assignment operator.
Definition quaternion.hpp:244
quaternion & lerpN(quaternion q1, quaternion q2, f32 time)
Set this quaternion to the linear interpolation between two quaternions and normalize the result.
Definition quaternion.hpp:588
quaternion & lerp(quaternion q1, quaternion q2, f32 time)
Set this quaternion to the linear interpolation between two quaternions.
Definition quaternion.hpp:581
void getMatrixCenter(matrix4 &dest, const core::vector3df &center, const core::vector3df &translation) const
Definition quaternion.hpp:437
f32 dotProduct(const quaternion &other) const
Calculates the dot product.
Definition quaternion.hpp:620
quaternion()
Default Constructor.
Definition quaternion.hpp:36
void toEuler(vector3df &euler) const
Output this quaternion to an Euler angle (radians)
Definition quaternion.hpp:660
bool operator!=(const quaternion &other) const
inequality operator
Definition quaternion.hpp:236
f32 X
Quaternion elements.
Definition quaternion.hpp:198
quaternion & makeIdentity()
Set quaternion to identity.
Definition quaternion.hpp:713
quaternion & normalize()
Normalizes the quaternion.
Definition quaternion.hpp:573
T Y
Y coordinate of the vector.
Definition vector3d.hpp:453
T X
X coordinate of the vector.
Definition vector3d.hpp:450
T Z
Z coordinate of the vector.
Definition vector3d.hpp:456
bool iszero(const f64 a, const f64 tolerance=ROUNDING_ERROR_f64)
returns if a equals zero, taking rounding errors into account
Definition irrMath.hpp:304
const T clamp(const T &value, const T &low, const T &high)
clamps a value between low and high
Definition irrMath.hpp:164
bool equals(const T a, const T b, const T tolerance=roundingError< T >())
returns if a equals b, taking possible rounding errors into account
Definition irrMath.hpp:243
const f64 PI64
Constant for 64bit PI.
Definition irrMath.hpp:66
As of Nirtcpp 1.6, position2d is a synonym for vector2d.
Definition vector3d.hpp:11
double f64
64 bit floating point variable.
Definition irrTypes.hpp:114
float f32
32 bit floating point variable.
Definition irrTypes.hpp:110

Nirtcpp    @cppfx.xyz

Utxcpp    utx::print