Quaternion-Impl.h
Go to the documentation of this file.
1 /*************************************************************************
2 > File Name: Quaternion-Impl.h
3 > Project Name: CubbyFlow
4 > Author: Dongmin Kim
5 > Purpose: Quaternion class defined as q = w + xi + yj + zk.
6 > Created Time: 2017/03/21
7 > Copyright (c) 2018, Dongmin Kim
8 *************************************************************************/
9 #ifndef CUBBYFLOW_QUATERNION_IMPL_H
10 #define CUBBYFLOW_QUATERNION_IMPL_H
11 
12 namespace CubbyFlow
13 {
14  template <typename T>
16  {
17  SetIdentity();
18  }
19 
20  template <typename T>
21  Quaternion<T>::Quaternion(T newW, T newX, T newY, T newZ)
22  {
23  Set(newW, newX, newY, newZ);
24  }
25 
26  template <typename T>
27  Quaternion<T>::Quaternion(const std::initializer_list<T>& list)
28  {
29  Set(list);
30  }
31 
32  template <typename T>
33  Quaternion<T>::Quaternion(const Vector3<T>& axis, T angle)
34  {
35  Set(axis, angle);
36  }
37 
38  template <typename T>
40  {
41  Set(from, to);
42  }
43 
44  template <typename T>
45  Quaternion<T>::Quaternion(const Vector3<T>& axis0, const Vector3<T>& axis1, const Vector3<T>& axis2)
46  {
47  Set(axis0, axis1, axis2);
48  }
49 
50  template <typename T>
52  {
53  Set(m33);
54  }
55 
56  template <typename T>
58  {
59  Set(other);
60  }
61 
62  template <typename T>
63  void Quaternion<T>::Set(const Quaternion& other)
64  {
65  Set(other.w, other.x, other.y, other.z);
66  }
67 
68  template <typename T>
69  void Quaternion<T>::Set(T newW, T newX, T newY, T newZ)
70  {
71  w = newW;
72  x = newX;
73  y = newY;
74  z = newZ;
75  }
76 
77  template <typename T>
78  void Quaternion<T>::Set(const std::initializer_list<T>& list)
79  {
80  assert(list.size() == 4);
81 
82  auto inputElem = list.begin();
83  w = *inputElem;
84  x = *(++inputElem);
85  y = *(++inputElem);
86  z = *(++inputElem);
87  }
88 
89  template <typename T>
90  void Quaternion<T>::Set(const Vector3<T>& axis, T angle)
91  {
92  static const T eps = std::numeric_limits<T>::epsilon();
93 
94  T axisLengthSquared = axis.LengthSquared();
95 
96  if (axisLengthSquared < eps)
97  {
98  SetIdentity();
99  }
100  else
101  {
102  Vector3<T> normalizedAxis = axis.Normalized();
103  T s = std::sin(angle / 2);
104 
105  x = normalizedAxis.x * s;
106  y = normalizedAxis.y * s;
107  z = normalizedAxis.z * s;
108  w = std::cos(angle / 2);
109  }
110  }
111 
112  template <typename T>
113  void Quaternion<T>::Set(const Vector3<T>& from, const Vector3<T>& to)
114  {
115  static const T eps = std::numeric_limits<T>::epsilon();
116 
117  Vector3<T> axis = from.Cross(to);
118 
119  T fromLengthSquared = from.LengthSquared();
120  T toLengthSquared = to.LengthSquared();
121 
122  if (fromLengthSquared < eps || toLengthSquared < eps)
123  {
124  SetIdentity();
125  }
126  else
127  {
128  T axisLengthSquared = axis.LengthSquared();
129 
130  // In case two vectors are exactly the opposite, pick orthogonal vector for axis.
131  if (axisLengthSquared < eps)
132  {
133  axis = std::get<0>(from.Tangential());
134  }
135 
136  Set(from.Dot(to), axis.x, axis.y, axis.z);
137  w += L2Norm();
138 
139  Normalize();
140  }
141  }
142 
143  template <typename T>
144  void Quaternion<T>::Set(const Vector3<T>& rotationBasis0, const Vector3<T>& rotationBasis1, const Vector3<T>& rotationBasis2)
145  {
146  Matrix3x3<T> matrix3;
147 
148  matrix3.SetColumn(0, rotationBasis0.Normalized());
149  matrix3.SetColumn(1, rotationBasis1.Normalized());
150  matrix3.SetColumn(2, rotationBasis2.Normalized());
151 
152  Set(matrix3);
153  }
154 
155  template <typename T>
157  {
158  static const T eps = std::numeric_limits<T>::epsilon();
159  static const T quarter = static_cast<T>(0.25);
160 
161  T onePlusTrace = m.Trace() + 1;
162 
163  if (onePlusTrace > eps)
164  {
165  T S = std::sqrt(onePlusTrace) * 2;
166  w = quarter * S;
167  x = (m(2, 1) - m(1, 2)) / S;
168  y = (m(0, 2) - m(2, 0)) / S;
169  z = (m(1, 0) - m(0, 1)) / S;
170  }
171  else if (m(0, 0) > m(1, 1) && m(0, 0) > m(2, 2))
172  {
173  T S = std::sqrt(1 + m(0, 0) - m(1, 1) - m(2, 2)) * 2;
174  w = (m(2, 1) - m(1, 2)) / S;
175  x = quarter * S;
176  y = (m(0, 1) + m(1, 0)) / S;
177  z = (m(0, 2) + m(2, 0)) / S;
178  }
179  else if (m(1, 1) > m(2, 2))
180  {
181  T S = std::sqrt(1 + m(1, 1) - m(0, 0) - m(2, 2)) * 2;
182  w = (m(0, 2) - m(2, 0)) / S;
183  x = (m(0, 1) + m(1, 0)) / S;
184  y = quarter * S;
185  z = (m(1, 2) + m(2, 1)) / S;
186  }
187  else
188  {
189  T S = std::sqrt(1 + m(2, 2) - m(0, 0) - m(1, 1)) * 2;
190  w = (m(1, 0) - m(0, 1)) / S;
191  x = (m(0, 2) + m(2, 0)) / S;
192  y = (m(1, 2) + m(2, 1)) / S;
193  z = quarter * S;
194  }
195  }
196 
197  template <typename T>
198  template <typename U>
200  {
201  return Quaternion<U>(static_cast<U>(w), static_cast<U>(x), static_cast<U>(y), static_cast<U>(z));
202  }
203 
204  template <typename T>
206  {
207  Quaternion q(*this);
208  q.Normalize();
209  return q;
210  }
211 
212  template <typename T>
214  {
215  T _2xx = 2 * x * x;
216  T _2yy = 2 * y * y;
217  T _2zz = 2 * z * z;
218  T _2xy = 2 * x * y;
219  T _2xz = 2 * x * z;
220  T _2xw = 2 * x * w;
221  T _2yz = 2 * y * z;
222  T _2yw = 2 * y * w;
223  T _2zw = 2 * z * w;
224 
225  return Vector3<T>(
226  (1 - _2yy - _2zz) * v.x + (_2xy - _2zw) * v.y + (_2xz + _2yw) * v.z,
227  (_2xy + _2zw) * v.x + (1 - _2zz - _2xx) * v.y + (_2yz - _2xw) * v.z,
228  (_2xz - _2yw) * v.x + (_2yz + _2xw) * v.y + (1 - _2yy - _2xx) * v.z);
229  }
230 
231  template <typename T>
233  {
234  return Quaternion(
235  w * other.w - x * other.x - y * other.y - z * other.z,
236  w * other.x + x * other.w + y * other.z - z * other.y,
237  w * other.y - x * other.z + y * other.w + z * other.x,
238  w * other.z + x * other.y - y * other.x + z * other.w);
239  }
240 
241  template <typename T>
243  {
244  return w * other.w + x * other.x + y * other.y + z * other.z;
245  }
246 
247  template <typename T>
249  {
250  return Quaternion(
251  other.w * w - other.x * x - other.y * y - other.z * z,
252  other.w * x + other.x * w + other.y * z - other.z * y,
253  other.w * y - other.x * z + other.y * w + other.z * x,
254  other.w * z + other.x * y - other.y * x + other.z * w);
255  }
256 
257  template <typename T>
258  void Quaternion<T>::IMul(const Quaternion& other)
259  {
260  *this = Mul(other);
261  }
262 
263  template <typename T>
265  {
266  Set(1, 0, 0, 0);
267  }
268 
269  template <typename T>
270  void Quaternion<T>::Rotate(T angleInRadians)
271  {
272  Vector3<T> axis;
273  T currentAngle;
274 
275  GetAxisAngle(&axis, &currentAngle);
276 
277  currentAngle += angleInRadians;
278 
279  Set(axis, currentAngle);
280  }
281 
282  template <typename T>
284  {
285  T norm = L2Norm();
286 
287  if (norm > 0)
288  {
289  w /= norm;
290  x /= norm;
291  y /= norm;
292  z /= norm;
293  }
294  }
295 
296  template <typename T>
298  {
299  Vector3<T> result(x, y, z);
300  result.Normalize();
301 
302  if (2 * std::acos(w) < PI<T>())
303  {
304  return result;
305  }
306 
307  return -result;
308  }
309 
310  template <typename T>
312  {
313  T result = 2 * std::acos(w);
314 
315  if (result < PI<T>())
316  {
317  return result;
318  }
319 
320  // Wrap around
321  return 2 * PI<T>() - result;
322  }
323 
324  template <typename T>
325  void Quaternion<T>::GetAxisAngle(Vector3<T>* axis, T* angle) const
326  {
327  axis->Set(x, y, z);
328  axis->Normalize();
329  *angle = 2 * std::acos(w);
330 
331  if (*angle > PI<T>())
332  {
333  // Wrap around
334  (*axis) = -(*axis);
335  *angle = 2 * PI<T>() - (*angle);
336  }
337  }
338 
339  template <typename T>
341  {
342  T denom = w * w + x * x + y * y + z * z;
343  return Quaternion(w / denom, -x / denom, -y / denom, -z / denom);
344  }
345 
346  template <typename T>
348  {
349  T _2xx = 2 * x * x;
350  T _2yy = 2 * y * y;
351  T _2zz = 2 * z * z;
352  T _2xy = 2 * x * y;
353  T _2xz = 2 * x * z;
354  T _2xw = 2 * x * w;
355  T _2yz = 2 * y * z;
356  T _2yw = 2 * y * w;
357  T _2zw = 2 * z * w;
358 
359  Matrix3x3<T> m(
360  1 - _2yy - _2zz, _2xy - _2zw, _2xz + _2yw,
361  _2xy + _2zw, 1 - _2zz - _2xx, _2yz - _2xw,
362  _2xz - _2yw, _2yz + _2xw, 1 - _2yy - _2xx);
363 
364  return m;
365  }
366 
367  template <typename T>
369  {
370  T _2xx = 2 * x * x;
371  T _2yy = 2 * y * y;
372  T _2zz = 2 * z * z;
373  T _2xy = 2 * x * y;
374  T _2xz = 2 * x * z;
375  T _2xw = 2 * x * w;
376  T _2yz = 2 * y * z;
377  T _2yw = 2 * y * w;
378  T _2zw = 2 * z * w;
379 
380  Matrix4x4<T> m(
381  1 - _2yy - _2zz, _2xy - _2zw, _2xz + _2yw, 0,
382  _2xy + _2zw, 1 - _2zz - _2xx, _2yz - _2xw, 0,
383  _2xz - _2yw, _2yz + _2xw, 1 - _2yy - _2xx, 0,
384  0, 0, 0, 1);
385 
386  return m;
387  }
388 
389  template <typename T>
391  {
392  return std::sqrt(w * w + x * x + y * y + z * z);
393  }
394 
395  template <typename T>
397  {
398  Set(other);
399  return *this;
400  }
401 
402  template <typename T>
404  {
405  IMul(other);
406  return *this;
407  }
408 
409  template <typename T>
411  {
412  return (&w)[i];
413  }
414 
415  template <typename T>
416  const T& Quaternion<T>::operator[](size_t i) const
417  {
418  return (&w)[i];
419  }
420 
421  template <typename T>
422  bool Quaternion<T>::operator==(const Quaternion& other) const
423  {
424  return (w == other.w && x == other.x && y == other.y && z == other.z);
425  }
426 
427  template <typename T>
428  bool Quaternion<T>::operator!=(const Quaternion& other) const
429  {
430  return (w != other.w || x != other.x || y != other.y || z != other.z);
431  }
432 
433  template <typename T>
435  {
436  return Quaternion();
437  }
438 
439  template <typename T>
441  {
442  static const double threshold = 0.01;
443  static const T eps = std::numeric_limits<T>::epsilon();
444 
445  T cosHalfAngle = dot(a, b);
446  T weightA, weightB;
447 
448  // For better accuracy, return lerp result when a and b are close enough.
449  if (1.0 - std::fabs(cosHalfAngle) < threshold)
450  {
451  weightA = 1.0 - t;
452  weightB = t;
453  }
454  else
455  {
456  T halfAngle = std::acos(cosHalfAngle);
457  T sinHalfAngle = std::sqrt(1 - cosHalfAngle * cosHalfAngle);
458 
459  // In case of angle ~ 180, pick middle value.
460  // If not, perform slerp.
461  if (std::fabs(sinHalfAngle) < eps)
462  {
463  weightA = static_cast<T>(0.5);
464  weightB = static_cast<T>(0.5);
465  }
466  else
467  {
468  weightA = std::sin((1 - t) * halfAngle) / sinHalfAngle;
469  weightB = std::sin(t * halfAngle) / sinHalfAngle;
470  }
471  }
472 
473  return Quaternion<T>(
474  weightA * a.w + weightB * b.w,
475  weightA * a.x + weightB * b.x,
476  weightA * a.y + weightB * b.y,
477  weightA * a.z + weightB * b.z);
478  }
479 
480  template <typename T>
482  {
483  return q.Mul(v);
484  }
485 
486  template <typename T>
488  {
489  return a.Mul(b);
490  }
491 }
492 
493 #endif
T z
Definition: Quaternion.h:35
3-D vector class.
Definition: Vector3.h:26
T L2Norm() const
Returns L2 norm of this quaternion.
Definition: Quaternion-Impl.h:390
Quaternion RMul(const Quaternion &other) const
Returns other quaternion * this quaternion.
Definition: Quaternion-Impl.h:248
void Set(T s)
Set all x, y, and z components to s.
Definition: Vector3-Impl.h:27
T Trace() const
Returns sum of all diagonal elements.
Definition: Matrix3x3-Impl.h:515
static Quaternion MakeIdentity()
Returns identity matrix.
Definition: Quaternion-Impl.h:434
Quaternion< T > Slerp(const Quaternion< T > &a, const Quaternion< T > &b, T t)
Computes spherical linear interpolation.
Definition: Quaternion-Impl.h:440
T z
Z (or the third) component of the vector.
Definition: Vector3.h:38
T w
Real part.
Definition: Quaternion.h:23
Vector Normalized() const
Returns normalized vector.
Definition: Vector3-Impl.h:308
T Dot(const Vector &v) const
Computes dot product.
Definition: Vector3-Impl.h:136
Matrix4x4< T > Matrix4() const
Converts to the 4x4 rotation matrix.
Definition: Quaternion-Impl.h:368
T LengthSquared() const
Returns the squared length of the vector.
Definition: Vector3-Impl.h:320
Quaternion Normalized() const
Returns normalized quaternion.
Definition: Quaternion-Impl.h:205
Matrix3x3< T > Matrix3() const
Converts to the 3x3 rotation matrix.
Definition: Quaternion-Impl.h:347
T Angle() const
Returns the rotational angle.
Definition: Quaternion-Impl.h:311
void Rotate(T angleInRadians)
Rotate this quaternion with given angle in radians.
Definition: Quaternion-Impl.h:270
Quaternion()
Make an identity quaternion.
Definition: Quaternion-Impl.h:15
void SetColumn(size_t i, const Vector3< T > &col)
Sets i-th column with input vector.
Definition: Matrix3x3-Impl.h:161
bool operator==(const Quaternion &other) const
Returns true if equal.
Definition: Quaternion-Impl.h:422
T x
X (or the first) component of the vector.
Definition: Vector3.h:29
Quaternion Inverse() const
Returns the inverse quaternion.
Definition: Quaternion-Impl.h:340
Definition: pybind11Utils.h:24
3-D matrix class.
Definition: Matrix3x3.h:30
4-D matrix class.
Definition: Matrix4x4.h:29
void Normalize()
Normalizes the quaternion.
Definition: Quaternion-Impl.h:283
Quaternion & operator*=(const Quaternion &other)
Returns this quaternion *= other quaternion.
Definition: Quaternion-Impl.h:403
Quaternion< U > CastTo() const
Returns quaternion with other base type.
Definition: Quaternion-Impl.h:199
void Normalize()
Normalizes this vector.
Definition: Vector3-Impl.h:79
T y
Imaginary part (k).
Definition: Quaternion.h:32
T & operator[](size_t i)
Returns the reference to the i-th element.
Definition: Quaternion-Impl.h:410
Vector3< T > Mul(const Vector3< T > &v) const
Returns this quaternion * vector.
Definition: Quaternion-Impl.h:213
void IMul(const Quaternion &other)
Returns this quaternion *= other quaternion.
Definition: Quaternion-Impl.h:258
std::tuple< Vector< T, 3 >, Vector< T, 3 > > Tangential() const
Returns the tangential vector for this vector.
Definition: Vector3-Impl.h:352
Vector3< T > Axis() const
Returns the rotational axis.
Definition: Quaternion-Impl.h:297
void Set(const Quaternion &other)
Sets the quaternion with other quaternion.
Definition: Quaternion-Impl.h:63
bool operator!=(const Quaternion &other) const
Returns true if not equal.
Definition: Quaternion-Impl.h:428
Vector< T, 3 > operator*(const Quaternion< T > &q, const Vector< T, 3 > &v)
Returns quaternion q * vector v.
Definition: Quaternion-Impl.h:481
T Dot(const Quaternion< T > &other)
Computes the dot product with other quaternion.
Definition: Quaternion-Impl.h:242
void GetAxisAngle(Vector3< T > *axis, T *angle) const
Returns the axis and angle.
Definition: Quaternion-Impl.h:325
T y
Y (or the second) component of the vector.
Definition: Vector3.h:35
Quaternion & operator=(const Quaternion &other)
Assigns other quaternion.
Definition: Quaternion-Impl.h:396
void SetIdentity()
Makes this quaternion identity.
Definition: Quaternion-Impl.h:264
Quaternion class defined as q = w + xi + yj + zk.
Definition: Quaternion.h:20
Vector Cross(const Vector &v) const
Computes cross product.
Definition: Vector3-Impl.h:142
T x
Imaginary part (j).
Definition: Quaternion.h:29