1 | // tQuaternion.h  |
2 | //  |
3 | // A quaternion class for representing rotations along with expected functionality such as spherical and  |
4 | // normalized linear interpolation. Ability to construct unit quaternions (rotations) from axis-angle as  |
5 | // well as from rotation matrices.  |
6 | //  |
7 | // Copyright (c) 2004-2006, 2015, 2017 Tristan Grimmer.  |
8 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
9 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
10 | //  |
11 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
12 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
13 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
14 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
15 | // PERFORMANCE OF THIS SOFTWARE.  |
16 |   |
17 | #pragma once  |
18 | #include "Math/tLinearAlgebra.h"  |
19 | namespace tMath  |
20 | {  |
21 |   |
22 |   |
23 | struct tQuaternion : public tQuat  |
24 | {  |
25 | tQuaternion() { }  |
26 | tQuaternion(const tQuat& s) { tSet(*this, s); }  |
27 | tQuaternion(float x, float y, float z, float w) { tSet(*this, x, y, z, w); }  |
28 | tQuaternion(const float* a) { tSet(*this, a); }  |
29 | tQuaternion(const tMat4& orientation) /* Unit quaternion from a 4x4 rotation matrix. */ { tSet(*this, orientation); }  |
30 | tQuaternion(float r, tVec3 v) /* r,v is used in textbooks. This is not axis-angle. */ { tSet(*this, r, v); }  |
31 | tQuaternion(const tVec3& axis, float angle) /* Assumes axis vector is normalized. */ { tSet(*this, axis, angle); }  |
32 | tQuaternion(const tVec3& v) /* r (w) gets set to 0.0f. */ { tSet(*this, v); }  |
33 | const tQuat& Pod() const { return *this; }  |
34 |   |
35 | void Set(const tQuat& s) { tSet(*this, s); }  |
36 | void Set(float x, float y, float z, float w) { tSet(*this, x, y, z, w); }  |
37 | void Set(const float* a) { tSet(*this, a); }  |
38 | void Set(const tMat4& orientation) { tSet(*this, orientation); }  |
39 | void Set(float r, tVec3 v) { tSet(*this, r, v); }  |
40 | void Set(const tVec3& axis, float angle) { tSet(*this, axis, angle); }  |
41 | void Set(const tVec3& v) { tSet(*this, v); }  |
42 | void Get(float& x, float& y, float& z, float& w) const { tGet(x, y, z, w, *this); }  |
43 | void Get(float* a) const { tGet(a, *this); }  |
44 | void Get(tVec3& axis, float& angle) const { tGet(axis, angle, *this); }  |
45 |   |
46 | void Zero() { tZero(*this); }  |
47 | void Zero(tComponents c) { tZero(*this, c); }  |
48 | bool IsZero() const { return tIsZero(*this); }  |
49 | bool IsZero(tComponents c) const { return tIsZero(*this, c); }  |
50 | bool ApproxEqual(const tQuat& q, float e = Epsilon) const { return tApproxEqual(*this, q, e); }  |
51 | bool ApproxEqual(const tQuat& q, tComponents c, float e = Epsilon) const { return tApproxEqual(*this, q, c, e); }  |
52 |   |
53 | float LengthSq() const { return tLengthSq(*this); }  |
54 | float Length() const { return tLength(*this); }  |
55 | float LengthFast() const { return tLengthFast(*this); }  |
56 | float NormSq() const /* Returns the norm (length) squared. */ { return tLengthSq(*this); }  |
57 | float Norm() const /* Returns the norm (length). */ { return tLength(*this); }  |
58 | float NormFast() const /* Less accurate but faster. */ { return tLengthFast(*this); }  |
59 |   |
60 | void Normalize() { tNormalize(*this); }  |
61 | float NormalizeGetLength() /* Returns pre-normalized length. */ { return tNormalizeGetLength(*this); }  |
62 | bool NormalizeSafe() /* Returns success. */ { return tNormalizeSafe(*this); }  |
63 | float NormalizeSafeGetLength() /* Returns pre-normalized length. 0.0f if no go. */ { return tNormalizeSafeGetLength(*this); }  |
64 | void NormalizeFast() { tNormalizeFast(*this); }  |
65 | bool NormalizeSafeFast() { return tNormalizeSafeFast(*this); }  |
66 |   |
67 | // The lack of invert functions is intentional. For unit quaternion just use the conjugate functions.  |
68 | tQuat Conjugate() const { tQuat d; tConjugate(d, *this); return d; }  |
69 | tQuat& MakeConjugate() { tConjugate(*this); return *this; }  |
70 | void Slerp(const tQuat& a, const tQuat& b, float t) /* Spherical linear interpolation between a and b. */ { tSlerp(*this, a, b, t); }  |
71 | void Nlerp(const tQuat& a, const tQuat& b, float t) /* Normalized linear interpolation between a and b. */ { tNlerp(*this, a, b, t); }  |
72 | float RotationAngle() const { return tRotationAngle(*this); }  |
73 | void Rotate(tVec3& v) const /* Rotates the vector. */ { tRotate(v, *this); }  |
74 | void Rotate(tVec4& v) const /* Rotates the vector. Needs testing. */ { tRotate(v, *this); }  |
75 | inline static int GetNumComponents() { return 4; }  |
76 |   |
77 | // Don't add extra operators without first checking the math.  |
78 | tQuaternion& operator=(const tQuat& q) { tSet(*this, q); return *this; }  |
79 |   |
80 | tQuaternion& operator+=(const tQuat& a) { tAdd(*this, a); return *this; }  |
81 | const tQuaternion operator+(const tQuat& a) const { tQuaternion d; tAdd(d, *this, a); return d; }  |
82 |   |
83 | tQuaternion& operator-=(const tQuat& a) { tSub(*this, a); return *this; }  |
84 | const tQuaternion operator-(const tQuat& a) const { tQuaternion d; tSub(d, *this, a); return d; }  |
85 | const tQuaternion operator-() const { tQuaternion d; tNeg(d, *this); return d; }  |
86 |   |
87 | tQuaternion& operator*=(float a) { tMul(*this, a); return *this; }  |
88 | tQuaternion& operator*=(const tQuat& a) { tMul(*this, a); return *this; }  |
89 | tQuaternion& operator*=(const tVec3& a) /* Treats 'a' as an augmented (pure) quaternion. w = 0. */ { tMul(*this, a); return *this; }  |
90 | const tQuaternion operator*(const tQuat& a) const { tQuaternion d; tMul(d, *this, a); return d; }  |
91 | const tQuaternion operator*(const tVec3& a) const /* Treats 'a' as an augmented (pure) quaternion. w = 0. */ { tQuaternion d; tMul(d, *this, a); return d; }  |
92 | friend const tQuaternion operator*(const tQuat& a, float b) { tQuaternion d; tMul(d, a, b); return d; }  |
93 | friend const tQuaternion operator*(float a, const tQuat& b) { tQuaternion d; tMul(d, a, b); return d; }  |
94 |   |
95 | tQuaternion& operator/=(float a) { tDiv(*this, a); return *this; }  |
96 | const tQuaternion operator/(float a) const { tQuaternion d; tDiv(d, *this, a); return d; }  |
97 |   |
98 | bool operator==(const tQuat& a) const { return tEqual(*this, a); }  |
99 | bool operator!=(const tQuat& a) const { return tNotEqual(*this, a); }  |
100 | operator const float*() { return E; }  |
101 | operator const float*() const { return E; }  |
102 | float& operator[](int i) { return E[i]; }  |
103 | float operator[](int i) const { return E[i]; }  |
104 |   |
105 | const static tQuaternion zero; // Zero quaternion (0, 0, 0, 0).  |
106 | const static tQuaternion unit; // Unit quaternion (0, 0, 0, 1).  |
107 | };  |
108 |   |
109 |   |
110 | }  |
111 | |