Pioneer
Loading...
Searching...
No Matches
Quaternion.h
Go to the documentation of this file.
1// Copyright © 2008-2023 Pioneer Developers. See AUTHORS.txt for details
2// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3
4#ifndef _QUATERNION_H
5#define _QUATERNION_H
6
7#include "matrix4x4.h"
8#include "vector3.h"
9#include <math.h>
10#include <type_traits>
11
12template <typename T>
14 using other_float_t = typename std::conditional<std::is_same<T, float>::value, double, float>::type;
15
16public:
17 T w, x, y, z;
18
19 // Constructor definitions are outside class declaration to enforce that
20 // only float and double versions are possible.
22 Quaternion(T w, T x, T y, T z);
23 // from angle and axis
25 {
26 const T halfAng = ang * T(0.5);
27 const T sinHalfAng = sin(halfAng);
28 w = cos(halfAng);
29 x = axis.x * sinHalfAng;
30 y = axis.y * sinHalfAng;
31 z = axis.z * sinHalfAng;
32 }
33 // from axis, assume angle == PI
34 // optimized fast path using sin(PI/2) = 1
36 {
37 w = 0;
38 x = axis.x;
39 y = axis.y;
40 z = axis.z;
41 }
43 w(o.w),
44 x(o.x),
45 y(o.y),
46 z(o.z) {}
47
48 void GetAxisAngle(T &angle, vector3<T> &axis)
49 {
50 if (w > 1.0) *this = Normalized(); // if w>1 acos and sqrt will produce errors, this can't happen if quaternion is normalised
51 angle = 2.0 * acos(w);
52 double s = sqrt(1.0 - w * w); // assuming quaternion normalised then w is less than 1, so term always positive.
53 if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt
54 // if s close to zero then direction of axis not important
55 axis.x = x; // if it is important that axis is normalised then replace with x=1; y=z=0;
56 axis.y = y;
57 axis.z = z;
58 } else {
59 axis.x = x / s; // normalise axis
60 axis.y = y / s;
61 axis.z = z / s;
62 }
63 }
64 bool operator==(const Quaternion &a) const
65 {
66 return is_equal_exact(a.w, w) && is_equal_exact(a.x, x) && is_equal_exact(a.y, y) && is_equal_exact(a.z, z);
67 }
68 bool ExactlyEqual(const Quaternion &a) const
69 {
70 return is_equal_exact(a.w, w) && is_equal_exact(a.x, x) && is_equal_exact(a.y, y) && is_equal_exact(a.z, z);
71 }
72
73 // conjugate (inverse)
75 {
76 Quaternion r;
77 r.w = a.w;
78 r.x = -a.x;
79 r.y = -a.y;
80 r.z = -a.z;
81 return r;
82 }
83 friend Quaternion operator*(const Quaternion &a, const Quaternion &b)
84 {
85 Quaternion r;
86 r.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
87 r.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
88 r.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
89 r.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
90 return r;
91 }
92 friend Quaternion operator*(const T s, const Quaternion &a) { return a * s; }
93 friend Quaternion operator*(const Quaternion &a, const T s)
94 {
95 Quaternion r;
96 r.w = a.w * s;
97 r.x = a.x * s;
98 r.y = a.y * s;
99 r.z = a.z * s;
100 return r;
101 }
102 // vector transform with quaternion
103 // (see https://community.khronos.org/t/quaternion-functions-for-glsl/50140/3)
104 friend vector3<T> operator*(const Quaternion &a, const vector3<T> &vec)
105 {
106 vector3<T> xyz = vector3<T>(a.x, a.y, a.z);
107 return vec + 2.0 * (vec.Cross(xyz) + a.w * vec).Cross(xyz);
108 }
109 friend Quaternion operator+(const Quaternion &a, const Quaternion &b)
110 {
111 Quaternion r;
112 r.w = a.w + b.w;
113 r.x = a.x + b.x;
114 r.y = a.y + b.y;
115 r.z = a.z + b.z;
116 return r;
117 }
118 friend Quaternion operator-(const Quaternion &a, const Quaternion &b)
119 {
120 Quaternion r;
121 r.w = a.w - b.w;
122 r.x = a.x - b.x;
123 r.y = a.y - b.y;
124 r.z = a.z - b.z;
125 return r;
126 }
127
129 {
130 T l = 1.0 / sqrt(w * w + x * x + y * y + z * z);
131 return Quaternion(w * l, x * l, y * l, z * l);
132 }
133 static T Dot(const Quaternion &a, const Quaternion &b) { return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z; }
134
135 template <typename U>
137 {
138 Quaternion r;
139 if (m[0] + m[4] + m[8] > 0.0f) {
140 U t = m[0] + m[4] + m[8] + 1.0;
141 U s = 0.5 / sqrt(t);
142 r.w = s * t;
143 r.z = (m[3] - m[1]) * s;
144 r.y = (m[2] - m[6]) * s;
145 r.x = (m[7] - m[5]) * s;
146 } else if ((m[0] > m[4]) && (m[0] > m[8])) {
147 U t = m[0] - m[4] - m[8] + 1.0;
148 U s = 0.5 / sqrt(t);
149 r.x = s * t;
150 r.y = (m[1] + m[3]) * s;
151 r.z = (m[2] + m[6]) * s;
152 r.w = (m[7] - m[5]) * s;
153 } else if (m[4] > m[8]) {
154 U t = -m[0] + m[4] - m[8] + 1.0;
155 U s = 0.5 / sqrt(t);
156 r.w = (m[2] - m[6]) * s;
157 r.x = (m[1] + m[3]) * s;
158 r.y = s * t;
159 r.z = (m[5] + m[7]) * s;
160 } else {
161 U t = -m[0] - m[4] + m[8] + 1.0;
162 U s = 0.5 / sqrt(t);
163 r.w = (m[3] - m[1]) * s;
164 r.x = (m[2] + m[6]) * s;
165 r.y = (m[7] + m[5]) * s;
166 r.z = s * t;
167 }
168 return r;
169 }
170
171 template <typename U>
173 {
174 matrix3x3<U> m;
175 U xx = x * x;
176 U xy = x * y;
177 U xz = x * z;
178 U xw = x * w;
179
180 U yy = y * y;
181 U yz = y * z;
182 U yw = y * w;
183
184 U zz = z * z;
185 U zw = z * w;
186
187 m[0] = 1.0 - 2.0 * (yy + zz);
188 m[1] = 2.0 * (xy - zw);
189 m[2] = 2.0 * (xz + yw);
190
191 m[3] = 2.0 * (xy + zw);
192 m[4] = 1.0 - 2.0 * (xx + zz);
193 m[5] = 2.0 * (yz - xw);
194
195 m[6] = 2.0 * (xz - yw);
196 m[7] = 2.0 * (yz + xw);
197 m[8] = 1.0 - 2.0 * (xx + yy);
198 return m;
199 }
200 /* normalized linear interpolation between 2 quaternions */
201 static Quaternion Nlerp(const Quaternion &a, const Quaternion &b, T t)
202 {
203 //printf("a: %f,%f,%f,%f\n", a.x, a.y, a.z, a.w);
204 //printf("b: %f,%f,%f,%f\n", b.x, b.y, b.z, b.w);
205 return (a + t * (b - a)).Normalized();
206 }
207
208 // spherical linear interpolation between two quaternions
209 // taken from assimp via #2514
210 static Quaternion Slerp(const Quaternion &a, const Quaternion &b, T t)
211 {
212 // calc cosine theta
213 T cosom = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
214
215 // adjust signs (if necessary)
216 Quaternion end = b;
217 if (cosom < T(0.0)) {
218 cosom = -cosom;
219 end.x = -end.x; // Reverse all signs
220 end.y = -end.y;
221 end.z = -end.z;
222 end.w = -end.w;
223 }
224
225 // Calculate coefficients
226 T sclp, sclq;
227 if ((T(1.0) - cosom) > T(0.0001)) { // 0.0001 -> some epsillon
228 // Standard case (slerp)
229 T omega, sinom;
230 omega = acos(cosom); // extract theta from dot product's cos theta
231 sinom = sin(omega);
232 sclp = sin((T(1.0) - t) * omega) / sinom;
233 sclq = sin(t * omega) / sinom;
234 } else {
235 // Very close, do linear interp (because it's faster)
236 sclp = T(1.0) - t;
237 sclq = t;
238 }
239
240 return Quaternion(
241 sclp * a.w + sclq * end.w,
242 sclp * a.x + sclq * end.x,
243 sclp * a.y + sclq * end.y,
244 sclp * a.z + sclq * end.z);
245 }
246
247 //void Print() const {
248 // printf("%f,%f,%f,%f\n", w, x, y, z);
249 //}
250};
251
252template <>
254 w(1.f),
255 x(0.f),
256 y(0.f),
257 z(0.f) {}
258template <>
260 w(1.),
261 x(0.),
262 y(0.),
263 z(0.) {}
264template <>
265inline Quaternion<float>::Quaternion(float w_, float x_, float y_, float z_) :
266 w(w_),
267 x(x_),
268 y(y_),
269 z(z_) {}
270template <>
271inline Quaternion<double>::Quaternion(double w_, double x_, double y_, double z_) :
272 w(w_),
273 x(x_),
274 y(y_),
275 z(z_) {}
276
279
280#endif /* _QUATERNION_H */
bool is_equal_exact(float a, float b)
Definition FloatComparison.h:112
Quaternion< double > Quaterniond
Definition Quaternion.h:278
Quaternion< float > Quaternionf
Definition Quaternion.h:277
Definition Quaternion.h:13
friend Quaternion operator-(const Quaternion &a, const Quaternion &b)
Definition Quaternion.h:118
Quaternion Normalized() const
Definition Quaternion.h:128
static Quaternion Slerp(const Quaternion &a, const Quaternion &b, T t)
Definition Quaternion.h:210
T y
Definition Quaternion.h:17
Quaternion(T w, T x, T y, T z)
matrix3x3< U > ToMatrix3x3() const
Definition Quaternion.h:172
friend Quaternion operator~(const Quaternion &a)
Definition Quaternion.h:74
static Quaternion Nlerp(const Quaternion &a, const Quaternion &b, T t)
Definition Quaternion.h:201
friend Quaternion operator*(const T s, const Quaternion &a)
Definition Quaternion.h:92
Quaternion(T ang, vector3< T > axis)
Definition Quaternion.h:24
friend Quaternion operator*(const Quaternion &a, const Quaternion &b)
Definition Quaternion.h:83
void GetAxisAngle(T &angle, vector3< T > &axis)
Definition Quaternion.h:48
static Quaternion FromMatrix3x3(const matrix3x3< U > &m)
Definition Quaternion.h:136
friend vector3< T > operator*(const Quaternion &a, const vector3< T > &vec)
Definition Quaternion.h:104
T x
Definition Quaternion.h:17
friend Quaternion operator*(const Quaternion &a, const T s)
Definition Quaternion.h:93
T w
Definition Quaternion.h:17
Quaternion(const Quaternion< other_float_t > &o)
Definition Quaternion.h:42
friend Quaternion operator+(const Quaternion &a, const Quaternion &b)
Definition Quaternion.h:109
Quaternion(vector3< T > axis)
Definition Quaternion.h:35
bool ExactlyEqual(const Quaternion &a) const
Definition Quaternion.h:68
bool operator==(const Quaternion &a) const
Definition Quaternion.h:64
static T Dot(const Quaternion &a, const Quaternion &b)
Definition Quaternion.h:133
T z
Definition Quaternion.h:17
Definition matrix3x3.h:13
Definition vector3.h:16
T y
Definition vector3.h:18
T x
Definition vector3.h:18
T z
Definition vector3.h:18
vector3 Cross(const vector3 &b) const
Definition vector3.h:117