Pioneer
Quaternion.h
Go to the documentation of this file.
1 // Copyright © 2008-2021 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 
12 template <typename T>
13 class Quaternion {
14  using other_float_t = typename std::conditional<std::is_same<T, float>::value, double, float>::type;
15 
16 public:
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
24  Quaternion(T ang, vector3<T> 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 cant 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  // conjugate (inverse)
65  friend Quaternion operator~(const Quaternion &a)
66  {
67  Quaternion r;
68  r.w = a.w;
69  r.x = -a.x;
70  r.y = -a.y;
71  r.z = -a.z;
72  return r;
73  }
74  friend Quaternion operator*(const Quaternion &a, const Quaternion &b)
75  {
76  Quaternion r;
77  r.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
78  r.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
79  r.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
80  r.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
81  return r;
82  }
83  friend Quaternion operator*(const T s, const Quaternion &a) { return a * s; }
84  friend Quaternion operator*(const Quaternion &a, const T s)
85  {
86  Quaternion r;
87  r.w = a.w * s;
88  r.x = a.x * s;
89  r.y = a.y * s;
90  r.z = a.z * s;
91  return r;
92  }
93  friend Quaternion operator+(const Quaternion &a, const Quaternion &b)
94  {
95  Quaternion r;
96  r.w = a.w + b.w;
97  r.x = a.x + b.x;
98  r.y = a.y + b.y;
99  r.z = a.z + b.z;
100  return r;
101  }
102  friend Quaternion operator-(const Quaternion &a, const Quaternion &b)
103  {
104  Quaternion r;
105  r.w = a.w - b.w;
106  r.x = a.x - b.x;
107  r.y = a.y - b.y;
108  r.z = a.z - b.z;
109  return r;
110  }
111 
113  {
114  T l = 1.0 / sqrt(w * w + x * x + y * y + z * z);
115  return Quaternion(w * l, x * l, y * l, z * l);
116  }
117  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; }
118 
119  template <typename U>
121  {
122  Quaternion r;
123  if (m[0] + m[4] + m[8] > 0.0f) {
124  U t = m[0] + m[4] + m[8] + 1.0;
125  U s = 0.5 / sqrt(t);
126  r.w = s * t;
127  r.z = (m[3] - m[1]) * s;
128  r.y = (m[2] - m[6]) * s;
129  r.x = (m[7] - m[5]) * s;
130  } else if ((m[0] > m[4]) && (m[0] > m[8])) {
131  U t = m[0] - m[4] - m[8] + 1.0;
132  U s = 0.5 / sqrt(t);
133  r.x = s * t;
134  r.y = (m[1] + m[3]) * s;
135  r.z = (m[2] + m[6]) * s;
136  r.w = (m[7] - m[5]) * s;
137  } else if (m[4] > m[8]) {
138  U t = -m[0] + m[4] - m[8] + 1.0;
139  U s = 0.5 / sqrt(t);
140  r.w = (m[2] - m[6]) * s;
141  r.x = (m[1] + m[3]) * s;
142  r.y = s * t;
143  r.z = (m[5] + m[7]) * s;
144  } else {
145  U t = -m[0] - m[4] + m[8] + 1.0;
146  U s = 0.5 / sqrt(t);
147  r.w = (m[3] - m[1]) * s;
148  r.x = (m[2] + m[6]) * s;
149  r.y = (m[7] + m[5]) * s;
150  r.z = s * t;
151  }
152  return r;
153  }
154 
155  template <typename U>
157  {
158  matrix3x3<U> m;
159  U xx = x * x;
160  U xy = x * y;
161  U xz = x * z;
162  U xw = x * w;
163 
164  U yy = y * y;
165  U yz = y * z;
166  U yw = y * w;
167 
168  U zz = z * z;
169  U zw = z * w;
170 
171  m[0] = 1.0 - 2.0 * (yy + zz);
172  m[1] = 2.0 * (xy - zw);
173  m[2] = 2.0 * (xz + yw);
174 
175  m[3] = 2.0 * (xy + zw);
176  m[4] = 1.0 - 2.0 * (xx + zz);
177  m[5] = 2.0 * (yz - xw);
178 
179  m[6] = 2.0 * (xz - yw);
180  m[7] = 2.0 * (yz + xw);
181  m[8] = 1.0 - 2.0 * (xx + yy);
182  return m;
183  }
184  /* normalized linear interpolation between 2 quaternions */
185  static Quaternion Nlerp(const Quaternion &a, const Quaternion &b, T t)
186  {
187  //printf("a: %f,%f,%f,%f\n", a.x, a.y, a.z, a.w);
188  //printf("b: %f,%f,%f,%f\n", b.x, b.y, b.z, b.w);
189  return (a + t * (b - a)).Normalized();
190  }
191 
192  // spherical linear interpolation between two quaternions
193  // taken from assimp via #2514
194  static Quaternion Slerp(const Quaternion &a, const Quaternion &b, T t)
195  {
196  // calc cosine theta
197  T cosom = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
198 
199  // adjust signs (if necessary)
200  Quaternion end = b;
201  if (cosom < T(0.0)) {
202  cosom = -cosom;
203  end.x = -end.x; // Reverse all signs
204  end.y = -end.y;
205  end.z = -end.z;
206  end.w = -end.w;
207  }
208 
209  // Calculate coefficients
210  T sclp, sclq;
211  if ((T(1.0) - cosom) > T(0.0001)) { // 0.0001 -> some epsillon
212  // Standard case (slerp)
213  T omega, sinom;
214  omega = acos(cosom); // extract theta from dot product's cos theta
215  sinom = sin(omega);
216  sclp = sin((T(1.0) - t) * omega) / sinom;
217  sclq = sin(t * omega) / sinom;
218  } else {
219  // Very close, do linear interp (because it's faster)
220  sclp = T(1.0) - t;
221  sclq = t;
222  }
223 
224  return Quaternion(
225  sclp * a.w + sclq * end.w,
226  sclp * a.x + sclq * end.x,
227  sclp * a.y + sclq * end.y,
228  sclp * a.z + sclq * end.z);
229  }
230 
231  //void Print() const {
232  // printf("%f,%f,%f,%f\n", w, x, y, z);
233  //}
234 };
235 
236 template <>
238 template <>
240 template <>
241 inline Quaternion<float>::Quaternion(float w_, float x_, float y_, float z_) :
242  w(w_),
243  x(x_),
244  y(y_),
245  z(z_) {}
246 template <>
247 inline Quaternion<double>::Quaternion(double w_, double x_, double y_, double z_) :
248  w(w_),
249  x(x_),
250  y(y_),
251  z(z_) {}
252 
255 
256 #endif /* _QUATERNION_H */
Quaternion< double > Quaterniond
Definition: Quaternion.h:254
Quaternion< float > Quaternionf
Definition: Quaternion.h:253
Definition: Quaternion.h:13
friend Quaternion operator-(const Quaternion &a, const Quaternion &b)
Definition: Quaternion.h:102
Quaternion Normalized() const
Definition: Quaternion.h:112
static Quaternion Slerp(const Quaternion &a, const Quaternion &b, T t)
Definition: Quaternion.h:194
T y
Definition: Quaternion.h:17
Quaternion(T w, T x, T y, T z)
friend Quaternion operator~(const Quaternion &a)
Definition: Quaternion.h:65
static Quaternion Nlerp(const Quaternion &a, const Quaternion &b, T t)
Definition: Quaternion.h:185
friend Quaternion operator*(const T s, const Quaternion &a)
Definition: Quaternion.h:83
Quaternion(T ang, vector3< T > axis)
Definition: Quaternion.h:24
friend Quaternion operator*(const Quaternion &a, const Quaternion &b)
Definition: Quaternion.h:74
void GetAxisAngle(T &angle, vector3< T > &axis)
Definition: Quaternion.h:48
static Quaternion FromMatrix3x3(const matrix3x3< U > &m)
Definition: Quaternion.h:120
matrix3x3< U > ToMatrix3x3() const
Definition: Quaternion.h:156
T x
Definition: Quaternion.h:17
friend Quaternion operator*(const Quaternion &a, const T s)
Definition: Quaternion.h:84
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:93
Quaternion(vector3< T > axis)
Definition: Quaternion.h:35
static T Dot(const Quaternion &a, const Quaternion &b)
Definition: Quaternion.h:117
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