Loading...
Searching...
No Matches
Quaternion-Impl.hpp
Go to the documentation of this file.
1// This code is based on Jet framework.
2// Copyright (c) 2018 Doyub Kim
3// CubbyFlow is voxel-based fluid simulation engine for computer games.
4// Copyright (c) 2020 CubbyFlow Team
5// Core Part: Chris Ohk, Junwoo Hwang, Jihong Sin, Seungwoo Yoo
6// AI Part: Dongheon Cho, Minseo Kim
7// We are making my contributions/submissions to this project solely in our
8// personal capacity and are not conveying any rights to any intellectual
9// property of any third parties.
10
11#ifndef CUBBYFLOW_QUATERNION_IMPL_HPP
12#define CUBBYFLOW_QUATERNION_IMPL_HPP
13
14namespace CubbyFlow
15{
16template <typename T>
18{
19 SetIdentity();
20}
21
22template <typename T>
27
28template <typename T>
29Quaternion<T>::Quaternion(const std::initializer_list<T>& list)
31 Set(list);
32}
34template <typename T>
37 Set(axis, angle);
38}
40template <typename T>
46template <typename T>
48 const Vector3<T>& axis2)
50 Set(axis0, axis1, axis2);
51}
53template <typename T>
56 Set(m33);
57}
58
59template <typename T>
62 Set(other);
63}
65template <typename T>
68 Set(other);
69}
71template <typename T>
74 Set(other);
75 return *this;
77
78template <typename T>
80{
81 Set(other);
82 return *this;
83}
84
85template <typename T>
87{
88 Set(other.w, other.x, other.y, other.z);
89}
91template <typename T>
94 w = newW;
95 x = newX;
96 y = newY;
97 z = newZ;
98}
100template <typename T>
101void Quaternion<T>::Set(const std::initializer_list<T>& list)
103 assert(list.size() == 4);
104
106 w = *inputElem;
107 x = *(++inputElem);
108 y = *(++inputElem);
109 z = *(++inputElem);
110}
112template <typename T>
115 static const T eps = std::numeric_limits<T>::epsilon();
116
118
121 SetIdentity();
122 }
123 else
124 {
126 T s = std::sin(angle / 2);
127
128 x = normalizedAxis.x * s;
130 z = normalizedAxis.z * s;
131 w = std::cos(angle / 2);
133}
134
135template <typename T>
137{
138 static const T eps = std::numeric_limits<T>::epsilon();
139
146 {
147 SetIdentity();
148 }
149 else
152
153 // In case two vectors are exactly the opposite, pick orthogonal vector
154 // for axis.
157 axis = std::get<0>(from.Tangentials());
158 }
159
160 Set(from.Dot(to), axis.x, axis.y, axis.z);
161 w += L2Norm();
162
163 Normalize();
164 }
165}
166
167template <typename T>
180
181template <typename T>
183{
184 static const T eps = std::numeric_limits<T>::epsilon();
185 static const T quarter = static_cast<T>(0.25);
186
187 T onePlusTrace = m.Trace() + 1;
188
189 if (onePlusTrace > eps)
190 {
191 T S = std::sqrt(onePlusTrace) * 2;
192 w = quarter * S;
193 x = (m(2, 1) - m(1, 2)) / S;
194 y = (m(0, 2) - m(2, 0)) / S;
195 z = (m(1, 0) - m(0, 1)) / S;
196 }
197 else if (m(0, 0) > m(1, 1) && m(0, 0) > m(2, 2))
198 {
199 T S = std::sqrt(1 + m(0, 0) - m(1, 1) - m(2, 2)) * 2;
200 w = (m(2, 1) - m(1, 2)) / S;
201 x = quarter * S;
202 y = (m(0, 1) + m(1, 0)) / S;
203 z = (m(0, 2) + m(2, 0)) / S;
204 }
205 else if (m(1, 1) > m(2, 2))
206 {
207 T S = std::sqrt(1 + m(1, 1) - m(0, 0) - m(2, 2)) * 2;
208 w = (m(0, 2) - m(2, 0)) / S;
209 x = (m(0, 1) + m(1, 0)) / S;
210 y = quarter * S;
211 z = (m(1, 2) + m(2, 1)) / S;
212 }
213 else
214 {
215 T S = std::sqrt(1 + m(2, 2) - m(0, 0) - m(1, 1)) * 2;
216 w = (m(1, 0) - m(0, 1)) / S;
217 x = (m(0, 2) + m(2, 0)) / S;
218 y = (m(1, 2) + m(2, 1)) / S;
219 z = quarter * S;
220 }
221}
222
223template <typename T>
224template <typename U>
226{
227 return Quaternion<U>{ static_cast<U>(w), static_cast<U>(x),
228 static_cast<U>(y), static_cast<U>(z) };
229}
230
231template <typename T>
233{
234 Quaternion q{ *this };
235 q.Normalize();
236 return q;
237}
238
239template <typename T>
241{
242 T _2xx = 2 * x * x;
243 T _2yy = 2 * y * y;
244 T _2zz = 2 * z * z;
245 T _2xy = 2 * x * y;
246 T _2xz = 2 * x * z;
247 T _2xw = 2 * x * w;
248 T _2yz = 2 * y * z;
249 T _2yw = 2 * y * w;
250 T _2zw = 2 * z * w;
251
252 return Vector3<T>{
253 (1 - _2yy - _2zz) * v.x + (_2xy - _2zw) * v.y + (_2xz + _2yw) * v.z,
254 (_2xy + _2zw) * v.x + (1 - _2zz - _2xx) * v.y + (_2yz - _2xw) * v.z,
255 (_2xz - _2yw) * v.x + (_2yz + _2xw) * v.y + (1 - _2yy - _2xx) * v.z
256 };
257}
258
259template <typename T>
261{
262 return Quaternion{ w * other.w - x * other.x - y * other.y - z * other.z,
263 w * other.x + x * other.w + y * other.z - z * other.y,
264 w * other.y - x * other.z + y * other.w + z * other.x,
265 w * other.z + x * other.y - y * other.x + z * other.w };
266}
267
268template <typename T>
270{
271 return w * other.w + x * other.x + y * other.y + z * other.z;
272}
273
274template <typename T>
276{
277 return Quaternion{ other.w * w - other.x * x - other.y * y - other.z * z,
278 other.w * x + other.x * w + other.y * z - other.z * y,
279 other.w * y - other.x * z + other.y * w + other.z * x,
280 other.w * z + other.x * y - other.y * x + other.z * w };
281}
282
283template <typename T>
285{
286 *this = Mul(other);
287}
288
289template <typename T>
291{
292 Set(1, 0, 0, 0);
293}
294
295template <typename T>
297{
300
301 GetAxisAngle(&axis, &currentAngle);
302
304
305 Set(axis, currentAngle);
306}
307
308template <typename T>
310{
311 T norm = L2Norm();
312
313 if (norm > 0)
314 {
315 w /= norm;
316 x /= norm;
317 y /= norm;
318 z /= norm;
319 }
320}
321
322template <typename T>
324{
325 Vector3<T> result{ x, y, z };
327
328 if (2 * std::acos(w) < PI<T>())
329 {
330 return result;
331 }
332
333 return -result;
334}
335
336template <typename T>
338{
339 T result = 2 * std::acos(w);
340
341 if (result < PI<T>())
342 {
343 return result;
344 }
345
346 // Wrap around
347 return 2 * PI<T>() - result;
348}
349
350template <typename T>
352{
353 *axis = Vector3<T>(x, y, z);
354 axis->Normalize();
355 *angle = 2 * std::acos(w);
356
357 if (*angle > PI<T>())
358 {
359 // Wrap around
360 (*axis) = -(*axis);
361 *angle = 2 * PI<T>() - (*angle);
362 }
363}
364
365template <typename T>
367{
368 const T denom = w * w + x * x + y * y + z * z;
369 return Quaternion{ w / denom, -x / denom, -y / denom, -z / denom };
370}
371
372template <typename T>
374{
375 T _2xx = 2 * x * x;
376 T _2yy = 2 * y * y;
377 T _2zz = 2 * z * z;
378 T _2xy = 2 * x * y;
379 T _2xz = 2 * x * z;
380 T _2xw = 2 * x * w;
381 T _2yz = 2 * y * z;
382 T _2yw = 2 * y * w;
383 T _2zw = 2 * z * w;
384
385 Matrix3x3<T> m{ 1 - _2yy - _2zz, _2xy - _2zw, _2xz + _2yw,
386 _2xy + _2zw, 1 - _2zz - _2xx, _2yz - _2xw,
387 _2xz - _2yw, _2yz + _2xw, 1 - _2yy - _2xx };
388
389 return m;
390}
391
392template <typename T>
394{
395 T _2xx = 2 * x * x;
396 T _2yy = 2 * y * y;
397 T _2zz = 2 * z * z;
398 T _2xy = 2 * x * y;
399 T _2xz = 2 * x * z;
400 T _2xw = 2 * x * w;
401 T _2yz = 2 * y * z;
402 T _2yw = 2 * y * w;
403 T _2zw = 2 * z * w;
404
405 Matrix4x4<T> m{ 1 - _2yy - _2zz,
406 _2xy - _2zw,
407 _2xz + _2yw,
408 0,
409 _2xy + _2zw,
410 1 - _2zz - _2xx,
411 _2yz - _2xw,
412 0,
413 _2xz - _2yw,
414 _2yz + _2xw,
415 1 - _2yy - _2xx,
416 0,
417 0,
418 0,
419 0,
420 1 };
421
422 return m;
423}
424
425template <typename T>
427{
428 return std::sqrt(w * w + x * x + y * y + z * z);
429}
430
431template <typename T>
433{
434 IMul(other);
435 return *this;
436}
437
438template <typename T>
440{
441 assert(i >= 0 && i < 4);
442
443 if (i == 0)
444 {
445 return w;
446 }
447
448 if (i == 1)
449 {
450 return x;
451 }
452
453 if (i == 2)
454 {
455 return y;
456 }
457
458 return z;
459}
460
461template <typename T>
462const T& Quaternion<T>::operator[](size_t i) const
463{
464 assert(i >= 0 && i < 4);
465
466 if (i == 0)
467 {
468 return w;
469 }
470
471 if (i == 1)
472 {
473 return x;
474 }
475
476 if (i == 2)
477 {
478 return y;
479 }
480
481 return z;
482}
483
484template <typename T>
486{
487 return (w == other.w && x == other.x && y == other.y && z == other.z);
488}
489
490template <typename T>
492{
493 return (w != other.w || x != other.x || y != other.y || z != other.z);
494}
495
496template <typename T>
501
502template <typename T>
504{
505 static const double threshold = 0.01;
506 static const T eps = std::numeric_limits<T>::epsilon();
507
508 T cosHalfAngle = a.Dot(b);
510
511 // For better accuracy, return lerp result when a and b are close enough.
512 if (1.0 - std::fabs(cosHalfAngle) < threshold)
513 {
514 weightA = 1.0 - t;
515 weightB = t;
516 }
517 else
518 {
519 T halfAngle = std::acos(cosHalfAngle);
520 T sinHalfAngle = std::sqrt(1 - cosHalfAngle * cosHalfAngle);
521
522 // In case of angle ~ 180, pick middle value.
523 // If not, perform slerp.
524 if (std::fabs(sinHalfAngle) < eps)
525 {
526 weightA = static_cast<T>(0.5);
527 weightB = static_cast<T>(0.5);
528 }
529 else
530 {
531 weightA = std::sin((1 - t) * halfAngle) / sinHalfAngle;
532 weightB = std::sin(t * halfAngle) / sinHalfAngle;
533 }
534 }
535
536 return Quaternion<T>{ weightA * a.w + weightB * b.w,
537 weightA * a.x + weightB * b.x,
538 weightA * a.y + weightB * b.y,
539 weightA * a.z + weightB * b.z };
540}
541
542template <typename T>
544{
545 return q.Mul(v);
546}
547
548template <typename T>
550{
551 return a.Mul(b);
552}
553} // namespace CubbyFlow
554
555#endif
void Normalize()
Definition MatrixDenseBase-Impl.hpp:86
void SetColumn(size_t j, const MatrixExpression< T, R, C, E > &col)
Sets j-th column with input vector.
Definition MatrixDenseBase-Impl.hpp:74
std::enable_if_t<(IsMatrixSizeDynamic< Rows, Cols >()||(Rows==2 &&Cols==1)) &&(IsMatrixSizeDynamic< R, C >()||(R==2 &&C==1)), U > Cross(const MatrixExpression< T, R, C, E > &expression) const
Definition MatrixExpression-Impl.hpp:412
std::enable_if_t<(IsMatrixSizeDynamic< Rows, Cols >()||(Rows==3 &&Cols==1)), std::tuple< Matrix< U, 3, 1 >, Matrix< U, 3, 1 > > Tangentials() const
Returns the tangential vectors for this vector.
ValueType LengthSquared() const
Definition MatrixExpression-Impl.hpp:286
std::enable_if_t<(IsMatrixSizeDynamic< Rows, Cols >()||Cols==1) &&(IsMatrixSizeDynamic< R, C >()||C==1), U > Dot(const MatrixExpression< T, R, C, E > &expression) const
Definition MatrixExpression-Impl.hpp:391
MatrixScalarElemWiseBinaryOp< T, Rows, Cols, const Derived &, std::divides< T > > Normalized() const
Definition MatrixExpression-Impl.hpp:315
ValueType Trace() const
Definition MatrixExpression-Impl.hpp:183
Definition Matrix.hpp:30
Iterator begin()
Definition Matrix-Impl.hpp:272
Quaternion class defined as q = w + xi + yj + zk.
Definition Quaternion.hpp:23
Quaternion & operator*=(const Quaternion &other)
Returns this quaternion *= other quaternion.
Definition Quaternion-Impl.hpp:432
Quaternion & operator=(const Quaternion &other)
Copy assignment operator.
Definition Quaternion-Impl.hpp:72
void GetAxisAngle(Vector3< T > *axis, T *angle) const
Returns the axis and angle.
Definition Quaternion-Impl.hpp:351
bool operator==(const Quaternion &other) const
Returns true if equal.
Definition Quaternion-Impl.hpp:485
Vector3< T > Axis() const
Returns the rotational axis.
Definition Quaternion-Impl.hpp:323
void IMul(const Quaternion &other)
Returns this quaternion *= other quaternion.
Definition Quaternion-Impl.hpp:284
void Set(const Quaternion &other)
Sets the quaternion with other quaternion.
Definition Quaternion-Impl.hpp:86
void Rotate(T angleInRadians)
Rotate this quaternion with given angle in radians.
Definition Quaternion-Impl.hpp:296
void SetIdentity()
Makes this quaternion identity.
Definition Quaternion-Impl.hpp:290
Quaternion()
Make an identity quaternion.
Definition Quaternion-Impl.hpp:17
Quaternion Normalized() const
Returns normalized quaternion.
Definition Quaternion-Impl.hpp:232
T L2Norm() const
Returns L2 norm of this quaternion.
Definition Quaternion-Impl.hpp:426
T Dot(const Quaternion< T > &other) const
Computes the dot product with other quaternion.
Definition Quaternion-Impl.hpp:269
Quaternion< U > CastTo() const
Returns quaternion with other base type.
Definition Quaternion-Impl.hpp:225
Matrix4x4< T > Matrix4() const
Converts to the 4x4 rotation matrix.
Definition Quaternion-Impl.hpp:393
Quaternion RMul(const Quaternion &other) const
Returns other quaternion * this quaternion.
Definition Quaternion-Impl.hpp:275
void Normalize()
Normalizes the quaternion.
Definition Quaternion-Impl.hpp:309
Matrix3x3< T > Matrix3() const
Converts to the 3x3 rotation matrix.
Definition Quaternion-Impl.hpp:373
Vector3< T > Mul(const Vector3< T > &v) const
Returns this quaternion * vector.
Definition Quaternion-Impl.hpp:240
Quaternion Inverse() const
Returns the inverse quaternion.
Definition Quaternion-Impl.hpp:366
static Quaternion MakeIdentity()
Returns identity matrix.
Definition Quaternion-Impl.hpp:497
T & operator[](size_t i)
Returns the reference to the i-th element.
Definition Quaternion-Impl.hpp:439
bool operator!=(const Quaternion &other) const
Returns true if not equal.
Definition Quaternion-Impl.hpp:491
T Angle() const
Returns the rotational angle.
Definition Quaternion-Impl.hpp:337
Definition pybind11Utils.hpp:21
Quaternion< T > Slerp(const Quaternion< T > &a, const Quaternion< T > &b, T t)
Computes spherical linear interpolation.
Definition Quaternion-Impl.hpp:503
Matrix< T, Rows, 1 > Vector
Definition Matrix.hpp:738
Vector< T, 3 > operator*(const Quaternion< T > &q, const Vector< T, 3 > &v)
Returns quaternion q * vector v.
Definition Quaternion-Impl.hpp:543