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}
52
53template <typename T>
58
59template <typename T>
61
62template <typename T>
63Quaternion<T>::Quaternion(Quaternion&& other) noexcept = default;
64
65template <typename T>
68template <typename T>
71template <typename T>
74 Set(other.w, other.x, other.y, other.z);
75}
77template <typename T>
80 w = newW;
81 x = newX;
82 y = newY;
83 z = newZ;
84}
85
86template <typename T>
87void Quaternion<T>::Set(const std::initializer_list<T>& list)
88{
89 assert(list.size() == 4);
91 auto inputElem = list.begin();
92 w = *inputElem;
93 x = *(++inputElem);
94 y = *(++inputElem);
95 z = *(++inputElem);
97
98template <typename T>
100{
101 static const T eps = std::numeric_limits<T>::epsilon();
104
106 {
107 SetIdentity();
109 else
110 {
112 T s = std::sin(angle / 2);
113
115 y = normalizedAxis.y * s;
116 z = normalizedAxis.z * s;
117 w = std::cos(angle / 2);
118 }
119}
121template <typename T>
124 static const T eps = std::numeric_limits<T>::epsilon();
125
127
130
133 SetIdentity();
134 }
135 else
136 {
139 // In case two vectors are exactly the opposite, pick orthogonal vector
140 // for axis.
142 {
143 axis = std::get<0>(from.Tangentials());
145
146 Set(from.Dot(to), axis.x, axis.y, axis.z);
147 w += L2Norm();
148
149 Normalize();
151}
152
153template <typename T>
157{
159
163
164 Set(matrix3);
165}
166
167template <typename T>
169{
170 static const T eps = std::numeric_limits<T>::epsilon();
171 static const T quarter = static_cast<T>(0.25);
172
173 T onePlusTrace = m.Trace() + 1;
174
175 if (onePlusTrace > eps)
176 {
177 T S = std::sqrt(onePlusTrace) * 2;
178 w = quarter * S;
179 x = (m(2, 1) - m(1, 2)) / S;
180 y = (m(0, 2) - m(2, 0)) / S;
181 z = (m(1, 0) - m(0, 1)) / S;
182 }
183 else if (m(0, 0) > m(1, 1) && m(0, 0) > m(2, 2))
184 {
185 T S = std::sqrt(1 + m(0, 0) - m(1, 1) - m(2, 2)) * 2;
186 w = (m(2, 1) - m(1, 2)) / S;
187 x = quarter * S;
188 y = (m(0, 1) + m(1, 0)) / S;
189 z = (m(0, 2) + m(2, 0)) / S;
190 }
191 else if (m(1, 1) > m(2, 2))
192 {
193 T S = std::sqrt(1 + m(1, 1) - m(0, 0) - m(2, 2)) * 2;
194 w = (m(0, 2) - m(2, 0)) / S;
195 x = (m(0, 1) + m(1, 0)) / S;
196 y = quarter * S;
197 z = (m(1, 2) + m(2, 1)) / S;
198 }
199 else
200 {
201 T S = std::sqrt(1 + m(2, 2) - m(0, 0) - m(1, 1)) * 2;
202 w = (m(1, 0) - m(0, 1)) / S;
203 x = (m(0, 2) + m(2, 0)) / S;
204 y = (m(1, 2) + m(2, 1)) / S;
205 z = quarter * S;
206 }
207}
208
209template <typename T>
210template <typename U>
212{
213 return Quaternion<U>{ static_cast<U>(w), static_cast<U>(x),
214 static_cast<U>(y), static_cast<U>(z) };
215}
216
217template <typename T>
219{
220 Quaternion q{ *this };
221 q.Normalize();
222 return q;
223}
224
225template <typename T>
227{
228 T _2xx = 2 * x * x;
229 T _2yy = 2 * y * y;
230 T _2zz = 2 * z * z;
231 T _2xy = 2 * x * y;
232 T _2xz = 2 * x * z;
233 T _2xw = 2 * x * w;
234 T _2yz = 2 * y * z;
235 T _2yw = 2 * y * w;
236 T _2zw = 2 * z * w;
237
238 return Vector3<T>{
239 (1 - _2yy - _2zz) * v.x + (_2xy - _2zw) * v.y + (_2xz + _2yw) * v.z,
240 (_2xy + _2zw) * v.x + (1 - _2zz - _2xx) * v.y + (_2yz - _2xw) * v.z,
241 (_2xz - _2yw) * v.x + (_2yz + _2xw) * v.y + (1 - _2yy - _2xx) * v.z
242 };
243}
244
245template <typename T>
247{
248 return Quaternion{ w * other.w - x * other.x - y * other.y - z * other.z,
249 w * other.x + x * other.w + y * other.z - z * other.y,
250 w * other.y - x * other.z + y * other.w + z * other.x,
251 w * other.z + x * other.y - y * other.x + z * other.w };
252}
253
254template <typename T>
256{
257 return w * other.w + x * other.x + y * other.y + z * other.z;
258}
259
260template <typename T>
262{
263 return Quaternion{ other.w * w - other.x * x - other.y * y - other.z * z,
264 other.w * x + other.x * w + other.y * z - other.z * y,
265 other.w * y - other.x * z + other.y * w + other.z * x,
266 other.w * z + other.x * y - other.y * x + other.z * w };
267}
268
269template <typename T>
271{
272 *this = Mul(other);
273}
274
275template <typename T>
277{
278 Set(1, 0, 0, 0);
279}
280
281template <typename T>
283{
286
287 GetAxisAngle(&axis, &currentAngle);
288
290
291 Set(axis, currentAngle);
292}
293
294template <typename T>
296{
297 T norm = L2Norm();
298
299 if (norm > 0)
300 {
301 w /= norm;
302 x /= norm;
303 y /= norm;
304 z /= norm;
305 }
306}
307
308template <typename T>
310{
311 Vector3<T> result{ x, y, z };
313
314 if (2 * std::acos(w) < PI<T>())
315 {
316 return result;
317 }
318
319 return -result;
320}
321
322template <typename T>
324{
325 T result = 2 * std::acos(w);
326
327 if (result < PI<T>())
328 {
329 return result;
330 }
331
332 // Wrap around
333 return 2 * PI<T>() - result;
334}
335
336template <typename T>
338{
339 *axis = Vector3<T>(x, y, z);
340 axis->Normalize();
341 *angle = 2 * std::acos(w);
342
343 if (*angle > PI<T>())
344 {
345 // Wrap around
346 (*axis) = -(*axis);
347 *angle = 2 * PI<T>() - (*angle);
348 }
349}
350
351template <typename T>
353{
354 const T denom = w * w + x * x + y * y + z * z;
355 return Quaternion{ w / denom, -x / denom, -y / denom, -z / denom };
356}
357
358template <typename T>
360{
361 T _2xx = 2 * x * x;
362 T _2yy = 2 * y * y;
363 T _2zz = 2 * z * z;
364 T _2xy = 2 * x * y;
365 T _2xz = 2 * x * z;
366 T _2xw = 2 * x * w;
367 T _2yz = 2 * y * z;
368 T _2yw = 2 * y * w;
369 T _2zw = 2 * z * w;
370
371 Matrix3x3<T> m{ 1 - _2yy - _2zz, _2xy - _2zw, _2xz + _2yw,
372 _2xy + _2zw, 1 - _2zz - _2xx, _2yz - _2xw,
373 _2xz - _2yw, _2yz + _2xw, 1 - _2yy - _2xx };
374
375 return m;
376}
377
378template <typename T>
380{
381 T _2xx = 2 * x * x;
382 T _2yy = 2 * y * y;
383 T _2zz = 2 * z * z;
384 T _2xy = 2 * x * y;
385 T _2xz = 2 * x * z;
386 T _2xw = 2 * x * w;
387 T _2yz = 2 * y * z;
388 T _2yw = 2 * y * w;
389 T _2zw = 2 * z * w;
390
391 Matrix4x4<T> m{ 1 - _2yy - _2zz,
392 _2xy - _2zw,
393 _2xz + _2yw,
394 0,
395 _2xy + _2zw,
396 1 - _2zz - _2xx,
397 _2yz - _2xw,
398 0,
399 _2xz - _2yw,
400 _2yz + _2xw,
401 1 - _2yy - _2xx,
402 0,
403 0,
404 0,
405 0,
406 1 };
407
408 return m;
409}
410
411template <typename T>
413{
414 return std::sqrt(w * w + x * x + y * y + z * z);
415}
416
417template <typename T>
419{
420 IMul(other);
421 return *this;
422}
423
424template <typename T>
426{
427 assert(i >= 0 && i < 4);
428
429 if (i == 0)
430 {
431 return w;
432 }
433
434 if (i == 1)
435 {
436 return x;
437 }
438
439 if (i == 2)
440 {
441 return y;
442 }
443
444 return z;
445}
446
447template <typename T>
448const T& Quaternion<T>::operator[](size_t i) const
449{
450 assert(i >= 0 && i < 4);
451
452 if (i == 0)
453 {
454 return w;
455 }
456
457 if (i == 1)
458 {
459 return x;
460 }
461
462 if (i == 2)
463 {
464 return y;
465 }
466
467 return z;
468}
469
470template <typename T>
472{
473 return (w == other.w && x == other.x && y == other.y && z == other.z);
474}
475
476template <typename T>
478{
479 return (w != other.w || x != other.x || y != other.y || z != other.z);
480}
481
482template <typename T>
487
488template <typename T>
490{
491 static const double threshold = 0.01;
492 static const T eps = std::numeric_limits<T>::epsilon();
493
494 T cosHalfAngle = a.Dot(b);
496
497 // For better accuracy, return lerp result when a and b are close enough.
498 if (1.0 - std::fabs(cosHalfAngle) < threshold)
499 {
500 weightA = 1.0 - t;
501 weightB = t;
502 }
503 else
504 {
505 T halfAngle = std::acos(cosHalfAngle);
506 T sinHalfAngle = std::sqrt(1 - cosHalfAngle * cosHalfAngle);
507
508 // In case of angle ~ 180, pick middle value.
509 // If not, perform slerp.
510 if (std::fabs(sinHalfAngle) < eps)
511 {
512 weightA = static_cast<T>(0.5);
513 weightB = static_cast<T>(0.5);
514 }
515 else
516 {
517 weightA = std::sin((1 - t) * halfAngle) / sinHalfAngle;
518 weightB = std::sin(t * halfAngle) / sinHalfAngle;
519 }
520 }
521
522 return Quaternion<T>{ weightA * a.w + weightB * b.w,
523 weightA * a.x + weightB * b.x,
524 weightA * a.y + weightB * b.y,
525 weightA * a.z + weightB * b.z };
526}
527
528template <typename T>
530{
531 return q.Mul(v);
532}
533
534template <typename T>
536{
537 return a.Mul(b);
538}
539} // namespace CubbyFlow
540
541#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:418
Quaternion & operator=(const Quaternion &other)
Copy assignment operator.
void GetAxisAngle(Vector3< T > *axis, T *angle) const
Returns the axis and angle.
Definition Quaternion-Impl.hpp:337
bool operator==(const Quaternion &other) const
Returns true if equal.
Definition Quaternion-Impl.hpp:471
Vector3< T > Axis() const
Returns the rotational axis.
Definition Quaternion-Impl.hpp:309
void IMul(const Quaternion &other)
Returns this quaternion *= other quaternion.
Definition Quaternion-Impl.hpp:270
void Set(const Quaternion &other)
Sets the quaternion with other quaternion.
Definition Quaternion-Impl.hpp:72
void Rotate(T angleInRadians)
Rotate this quaternion with given angle in radians.
Definition Quaternion-Impl.hpp:282
void SetIdentity()
Makes this quaternion identity.
Definition Quaternion-Impl.hpp:276
Quaternion()
Make an identity quaternion.
Definition Quaternion-Impl.hpp:17
Quaternion Normalized() const
Returns normalized quaternion.
Definition Quaternion-Impl.hpp:218
T L2Norm() const
Returns L2 norm of this quaternion.
Definition Quaternion-Impl.hpp:412
T Dot(const Quaternion< T > &other) const
Computes the dot product with other quaternion.
Definition Quaternion-Impl.hpp:255
Quaternion< U > CastTo() const
Returns quaternion with other base type.
Definition Quaternion-Impl.hpp:211
Matrix4x4< T > Matrix4() const
Converts to the 4x4 rotation matrix.
Definition Quaternion-Impl.hpp:379
Quaternion RMul(const Quaternion &other) const
Returns other quaternion * this quaternion.
Definition Quaternion-Impl.hpp:261
void Normalize()
Normalizes the quaternion.
Definition Quaternion-Impl.hpp:295
Matrix3x3< T > Matrix3() const
Converts to the 3x3 rotation matrix.
Definition Quaternion-Impl.hpp:359
Vector3< T > Mul(const Vector3< T > &v) const
Returns this quaternion * vector.
Definition Quaternion-Impl.hpp:226
Quaternion Inverse() const
Returns the inverse quaternion.
Definition Quaternion-Impl.hpp:352
static Quaternion MakeIdentity()
Returns identity matrix.
Definition Quaternion-Impl.hpp:483
T & operator[](size_t i)
Returns the reference to the i-th element.
Definition Quaternion-Impl.hpp:425
bool operator!=(const Quaternion &other) const
Returns true if not equal.
Definition Quaternion-Impl.hpp:477
T Angle() const
Returns the rotational angle.
Definition Quaternion-Impl.hpp:323
Definition pybind11Utils.hpp:22
Quaternion< T > Slerp(const Quaternion< T > &a, const Quaternion< T > &b, T t)
Computes spherical linear interpolation.
Definition Quaternion-Impl.hpp:489
Matrix< T, Rows, 1 > Vector
Definition Matrix.hpp:648
Vector< T, 3 > operator*(const Quaternion< T > &q, const Vector< T, 3 > &v)
Returns quaternion q * vector v.
Definition Quaternion-Impl.hpp:529