Sen API
Sen Libraries
Loading...
Searching...
No Matches
quat.h
Go to the documentation of this file.
1// === quat.h ==========================================================================================================
2// Sen Infrastructure
3// Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
4// See the LICENSE.txt file for more information.
5// © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
6// =====================================================================================================================
7
8#ifndef SEN_LIBS_UTIL_SRC_DR_QUAT_H
9#define SEN_LIBS_UTIL_SRC_DR_QUAT_H
10
11#include "constants.h"
12#include "vec3.h"
13
14// sen
17
18// std
19#include <algorithm>
20#include <cmath>
21
22namespace sen::util
23{
24
26template <typename T>
27class Quat
28{
29public:
30 SEN_COPY_MOVE(Quat)
31
32public: // set of builders
33 Quat() noexcept = default;
34
35 Quat(T x, T y, T z, T w) noexcept;
36
37 Quat(T angle, const Vec3<T>& axis) noexcept;
38
39 Quat(T yaw, T pitch, T bank) noexcept;
40
41 explicit Quat(const Vec3<T>& eulerAngles) noexcept;
42
43 ~Quat() = default;
44
45public: // custom operators
46 bool operator==(const Quat& v) const noexcept;
47
48 bool operator!=(const Quat& v) const noexcept;
49
50 bool operator<(const Quat& v) const noexcept;
51
52 Quat operator*(T rhs) const;
53
54 Quat& operator*=(T rhs) noexcept;
55
56 Quat operator*(const Quat& rhs) const noexcept;
57
58 Vec3<T> operator*(const Vec3<T>& v) const noexcept;
59
60 Quat& operator*=(const Quat& rhs) noexcept;
61
62 Quat operator/(const Quat& denom) const noexcept;
63
64 Quat& operator/=(const Quat& denom) noexcept;
65
66 Quat operator+(const Quat& rhs) const noexcept;
67
68 Quat operator/(const T rhs) const noexcept;
69
70 Quat& operator/=(T rhs) noexcept;
71
72 Quat& operator+=(const Quat& rhs) noexcept;
73
74 Quat operator-(const Quat& rhs) const noexcept;
75
76 Quat& operator-=(const Quat& rhs) noexcept;
77
78 Quat operator-() const noexcept;
79
80 // Dot product operator
81 [[nodiscard]] T dot(const Quat<T>& other) const noexcept;
82
83public: // operations to get stored values
84 [[nodiscard]] Vec3<T> asVec3() const noexcept;
85
86 void set(T x, T y, T z, T w) noexcept;
87
88 [[nodiscard]] T getX() const noexcept;
89 [[nodiscard]] T getY() const noexcept;
90 [[nodiscard]] T getZ() const noexcept;
91 [[nodiscard]] T getW() const noexcept;
92
93 void setX(T x) noexcept;
94
95 void setY(T y) noexcept;
96
97 void setZ(T z) noexcept;
98
99 void setW(T w) noexcept;
100
101 [[nodiscard]] bool zeroRotation() const noexcept;
102
103public: // quaternion information
104 [[nodiscard]] T length() const noexcept;
105
106 [[nodiscard]] T length2() const noexcept;
107
110 [[nodiscard]] Quat conj() const;
111
114 [[nodiscard]] Quat inverse() const;
115
116public: // quaternion rotations
117 void makeRotate(T angle, T x, T y, T z) noexcept;
118
119 void makeRotate(T angle, const Vec3<T>& vec) noexcept;
120
121 void makeRotate(const Vec3<T>& from, const Vec3<T>& to) noexcept;
122
124 [[nodiscard]] static Quat makeAxisRotation(T angle, const Vec3<T>& axis) noexcept;
125
126 void makeRotate(T angle1,
127 const Vec3<T>& axis1,
128 T angle2,
129 const Vec3<T>& axis2,
130 T angle3,
131 const Vec3<T>& axis3) noexcept;
132
133 void makeRotateFromEulerYPB(T yaw, T pitch, T bank) noexcept;
134
135 void makeRotateFromEulerYPB(const Vec3<T>& eulerAngles) noexcept;
136
137 void getRotate(T& angle, T& x, T& y, T& z) const noexcept;
138
139 void getRotate(T& angle, Vec3<T>& vec) const noexcept;
140
141 [[nodiscard]] Vec3<T> getRotateInEulerYPB() const noexcept;
142
143public: // interpolations
149 void slerp(T t, const Quat& from, const Quat& to) noexcept;
150
151private:
152 T v_[4] {0, 0, 0, 1};
153};
154
157
158//-------------------------------------------------------------------------------------------------------------------
159// Inline implementation
160//-------------------------------------------------------------------------------------------------------------------
161
162template <typename T>
163inline Quat<T>::Quat(T x, T y, T z, T w) noexcept
164{
165 v_[0] = x;
166 v_[1] = y;
167 v_[2] = z;
168 v_[3] = w;
169}
170
171template <typename T>
172inline Quat<T>::Quat(T angle, const Vec3<T>& axis) noexcept
173{
174 *this = makeAxisRotation(angle, axis);
175}
176
177template <typename T>
178inline Quat<T>::Quat(T yaw, T pitch, T bank) noexcept
179{
180 makeRotateFromEulerYPB(yaw, pitch, bank);
181}
182
183template <typename T>
184inline Quat<T>::Quat(const Vec3<T>& eulerAngles) noexcept
185{
186 makeRotateFromEulerYPB(eulerAngles.getX(), eulerAngles.getY(), eulerAngles.getZ());
187}
188
189template <typename T>
190inline bool Quat<T>::operator==(const Quat& v) const noexcept
191{
192 return v_[0] == v.v_[0] && v_[1] == v.v_[1] && v_[2] == v.v_[2] && v_[3] == v.v_[3];
193}
194
195template <typename T>
196inline bool Quat<T>::operator!=(const Quat& v) const noexcept
197{
198 return v_[0] != v.v_[0] || v_[1] != v.v_[1] || v_[2] != v.v_[2] || v_[3] != v.v_[3];
199}
200
201template <typename T>
202inline bool Quat<T>::operator<(const Quat& v) const noexcept
203{
204 if (v_[0] < v.v_[0])
205 {
206 return true;
207 }
208
209 if (v_[0] > v.v_[0])
210 {
211 return false;
212 }
213
214 if (v_[1] < v.v_[1])
215 {
216 return true;
217 }
218
219 if (v_[1] > v.v_[1])
220 {
221 return false;
222 }
223
224 if (v_[2] < v.v_[2])
225 {
226 return true;
227 }
228
229 if (v_[2] > v.v_[2])
230 {
231 return false;
232 }
233
234 return (v_[3] < v.v_[3]);
235}
236
237template <typename T>
238inline Vec3<T> Quat<T>::asVec3() const noexcept
239{
240 return Vec3<T> {v_[0], v_[1], v_[2]};
241}
242
243template <typename T>
244inline void Quat<T>::set(T x, T y, T z, T w) noexcept
245{
246 v_[0] = x;
247 v_[1] = y;
248 v_[2] = z;
249 v_[3] = w;
250}
251
252template <typename T>
253inline T Quat<T>::getX() const noexcept
254{
255 return v_[0];
256}
257
258template <typename T>
259inline T Quat<T>::getY() const noexcept
260{
261 return v_[1];
262}
263
264template <typename T>
265inline T Quat<T>::getZ() const noexcept
266{
267 return v_[2];
268}
269
270template <typename T>
271inline T Quat<T>::getW() const noexcept
272{
273 return v_[3];
274}
275
276template <typename T>
277inline void Quat<T>::setX(T x) noexcept
278{
279 v_[0] = x;
280}
281
282template <typename T>
283inline void Quat<T>::setY(T y) noexcept
284{
285 v_[1] = y;
286}
287
288template <typename T>
289inline void Quat<T>::setZ(T z) noexcept
290{
291 v_[2] = z;
292}
293
294template <typename T>
295inline void Quat<T>::setW(T w) noexcept
296{
297 v_[3] = w;
298}
299
300template <typename T>
301inline bool Quat<T>::zeroRotation() const noexcept
302{
303 return v_[0] == 0.0 && v_[1] == 0.0 && v_[2] == 0.0 && v_[3] == 1.0;
304}
305
306template <typename T>
307inline Quat<T> Quat<T>::operator*(T rhs) const
308{
309 return {v_[0] * rhs, v_[1] * rhs, v_[2] * rhs, v_[3] * rhs};
310}
311
312template <typename T>
313inline Quat<T>& Quat<T>::operator*=(T rhs) noexcept
314{
315 v_[0] *= rhs;
316 v_[1] *= rhs;
317 v_[2] *= rhs;
318 v_[3] *= rhs;
319 return *this;
320}
321
322template <typename T>
323inline Quat<T> Quat<T>::operator*(const Quat& rhs) const noexcept
324{
325 return {rhs.v_[3] * v_[0] + rhs.v_[0] * v_[3] + rhs.v_[1] * v_[2] - rhs.v_[2] * v_[1],
326 rhs.v_[3] * v_[1] - rhs.v_[0] * v_[2] + rhs.v_[1] * v_[3] + rhs.v_[2] * v_[0],
327 rhs.v_[3] * v_[2] + rhs.v_[0] * v_[1] - rhs.v_[1] * v_[0] + rhs.v_[2] * v_[3],
328 rhs.v_[3] * v_[3] - rhs.v_[0] * v_[0] - rhs.v_[1] * v_[1] - rhs.v_[2] * v_[2]};
329}
330
331template <typename T>
332inline Quat<T>& Quat<T>::operator*=(const Quat& rhs) noexcept
333{
334 T x = rhs.v_[3] * v_[0] + rhs.v_[0] * v_[3] + rhs.v_[1] * v_[2] - rhs.v_[2] * v_[1];
335 T y = rhs.v_[3] * v_[1] - rhs.v_[0] * v_[2] + rhs.v_[1] * v_[3] + rhs.v_[2] * v_[0];
336 T z = rhs.v_[3] * v_[2] + rhs.v_[0] * v_[1] - rhs.v_[1] * v_[0] + rhs.v_[2] * v_[3];
337 v_[3] = rhs.v_[3] * v_[3] - rhs.v_[0] * v_[0] - rhs.v_[1] * v_[1] - rhs.v_[2] * v_[2];
338
339 v_[2] = z;
340 v_[1] = y;
341 v_[0] = x;
342
343 return (*this);
344}
345
346template <typename T>
347inline Quat<T> Quat<T>::operator/(T rhs) const noexcept
348{
349 T div = 1.0 / rhs;
350 return {v_[0] * div, v_[1] * div, v_[2] * div, v_[3] * div};
351}
352
353template <typename T>
354inline Quat<T>& Quat<T>::operator/=(T rhs) noexcept
355{
356 T div = 1.0 / rhs;
357 v_[0] *= div;
358 v_[1] *= div;
359 v_[2] *= div;
360 v_[3] *= div;
361 return *this;
362}
363
364template <typename T>
365inline Quat<T> Quat<T>::operator/(const Quat& denom) const noexcept
366{
367 return ((*this) * denom.inverse());
368}
369
370template <typename T>
371inline Quat<T>& Quat<T>::operator/=(const Quat& denom) noexcept
372{
373 (*this) = (*this) * denom.inverse();
374 return (*this);
375}
376
377template <typename T>
378inline Quat<T> Quat<T>::operator+(const Quat& rhs) const noexcept
379{
380 return {v_[0] + rhs.v_[0], v_[1] + rhs.v_[1], v_[2] + rhs.v_[2], v_[3] + rhs.v_[3]};
381}
382
383template <typename T>
384inline Quat<T>& Quat<T>::operator+=(const Quat& rhs) noexcept
385{
386 v_[0] += rhs.v_[0];
387 v_[1] += rhs.v_[1];
388 v_[2] += rhs.v_[2];
389 v_[3] += rhs.v_[3];
390 return *this;
391}
392
393template <typename T>
394inline Quat<T> Quat<T>::operator-(const Quat& rhs) const noexcept
395{
396 return {v_[0] - rhs.v_[0], v_[1] - rhs.v_[1], v_[2] - rhs.v_[2], v_[3] - rhs.v_[3]};
397}
398
399template <typename T>
400inline Quat<T>& Quat<T>::operator-=(const Quat& rhs) noexcept
401{
402 v_[0] -= rhs.v_[0];
403 v_[1] -= rhs.v_[1];
404 v_[2] -= rhs.v_[2];
405 v_[3] -= rhs.v_[3];
406 return *this;
407}
408
409template <typename T>
410inline Quat<T> Quat<T>::operator-() const noexcept
411{
412 return {-v_[0], -v_[1], -v_[2], -v_[3]};
413}
414
415template <typename T>
416T Quat<T>::dot(const Quat<T>& other) const noexcept
417{
418 return v_[0] * other.v_[0] + v_[1] * other.v_[1] + v_[2] * other.v_[2] + v_[3] * other.v_[3];
419}
420
421template <typename T>
422inline T Quat<T>::length() const noexcept
423{
424 return sqrt(length2());
425}
426
427template <typename T>
428inline T Quat<T>::length2() const noexcept
429{
430 return v_[0] * v_[0] + v_[1] * v_[1] + v_[2] * v_[2] + v_[3] * v_[3];
431}
432
433template <typename T>
434inline Quat<T> Quat<T>::conj() const
435{
436 return {-v_[0], -v_[1], -v_[2], v_[3]};
437}
438
439template <typename T>
441{
442 return conj() / length2();
443}
444
445template <typename T>
446inline void Quat<T>::makeRotate(T angle, T x, T y, T z) noexcept
447{
448 constexpr T epsilon = 0.0000001;
449
450 T length = std::sqrt(x * x + y * y + z * z);
451 if (length < epsilon)
452 {
453 return;
454 }
455
456 T cosHalfAngle = cos(0.5 * angle);
457 T sinHalfAngle = sin(0.5 * angle);
458
459 T quatX = x * sinHalfAngle / length;
460 T quatY = y * sinHalfAngle / length;
461 T quatZ = z * sinHalfAngle / length;
462 T quatW = cosHalfAngle;
463
464 Quat rotationQuat {quatX, quatY, quatZ, quatW};
465
466 *this = *this * rotationQuat;
467}
468
469template <typename T>
470inline void Quat<T>::makeRotate(T angle, const Vec3<T>& vec) noexcept
471{
472 makeRotate(angle, vec.getX(), vec.getY(), vec.getZ());
473}
474
475template <typename T>
476inline void Quat<T>::makeRotate(const Vec3<T>& from, const Vec3<T>& to) noexcept
477{
478 auto sourceVector = from;
479 auto targetVector = to;
480
481 T fromLen2 = from.length2();
482 T fromLen;
483
484 if ((fromLen2 < 1.0 - 1e-7) || (fromLen2 > 1.0 + 1e-7))
485 {
486 fromLen = sqrt(fromLen2);
487 sourceVector /= fromLen;
488 }
489 else
490 {
491 fromLen = 1.0;
492 }
493
494 T toLen2 = to.length2();
495 if ((toLen2 < 1.0 - 1e-7) || (toLen2 > 1.0 + 1e-7))
496 {
497 T toLen;
498 if ((toLen2 > fromLen2 - 1e-7) && (toLen2 < fromLen2 + 1e-7))
499 {
500 toLen = fromLen;
501 }
502 else
503 {
504 toLen = sqrt(toLen2);
505 }
506 targetVector /= toLen;
507 }
508
509 T dotProdPlus1 = 1.0 + sourceVector * targetVector;
510
511 if (dotProdPlus1 < 1e-7)
512 {
513 if (fabs(sourceVector.getX()) < 0.6)
514 {
515 const auto norm = sqrt(1.0 - sourceVector.getX() * sourceVector.getX());
516 v_[0] = 0.0;
517 v_[1] = sourceVector.getZ() / norm;
518 v_[2] = -sourceVector.getY() / norm;
519 v_[3] = 0.0;
520 }
521 else if (fabs(sourceVector.getY()) < 0.6)
522 {
523 const auto norm = sqrt(1.0 - sourceVector.getY() * sourceVector.getY());
524 v_[0] = -sourceVector.getZ() / norm;
525 v_[1] = 0.0;
526 v_[2] = sourceVector.getX() / norm;
527 v_[3] = 0.0;
528 }
529 else
530 {
531 const auto norm = sqrt(1.0 - sourceVector.getZ() * sourceVector.getZ());
532 v_[0] = sourceVector.getY() / norm;
533 v_[1] = -sourceVector.getX() / norm;
534 v_[2] = 0.0;
535 v_[3] = 0.0;
536 }
537 }
538 else
539 {
540 const auto s = sqrt(0.5 * dotProdPlus1);
541 const auto tmp = sourceVector ^ targetVector / (2.0 * s);
542 v_[0] = tmp.getX();
543 v_[1] = tmp.getY();
544 v_[2] = tmp.getZ();
545 v_[3] = s;
546 }
547}
548
549template <typename T>
550inline void Quat<T>::makeRotate(T angle1,
551 const Vec3<T>& axis1,
552 T angle2,
553 const Vec3<T>& axis2,
554 T angle3,
555 const Vec3<T>& axis3) noexcept
556{
557 *this = makeAxisRotation(angle1, axis1) * makeAxisRotation(angle2, axis2) * makeAxisRotation(angle3, axis3);
558}
559
560template <typename T>
561inline Quat<T> Quat<T>::makeAxisRotation(T angle, const Vec3<T>& axis) noexcept
562{
563 constexpr T epsilon = 0.0000001;
564
565 const T length2 = axis.getX() * axis.getX() + axis.getY() * axis.getY() + axis.getZ() * axis.getZ();
566
567 if (length2 < epsilon * epsilon)
568 {
569 return {};
570 }
571
572 const T cosHalfAngle = cos(0.5 * angle);
573 const T sinHalfAngle = sin(0.5 * angle);
574
575 // Unit axes need no normalisation, so the square root and the divisions are skipped.
576 if (length2 == T {1})
577 {
578 return {axis.getX() * sinHalfAngle, axis.getY() * sinHalfAngle, axis.getZ() * sinHalfAngle, cosHalfAngle};
579 }
580
581 const T length = std::sqrt(length2);
582
583 return {axis.getX() * sinHalfAngle / length,
584 axis.getY() * sinHalfAngle / length,
585 axis.getZ() * sinHalfAngle / length,
586 cosHalfAngle};
587}
588
589template <typename T>
590inline void Quat<T>::makeRotateFromEulerYPB(T yaw, T pitch, T bank) noexcept
591{
592 makeRotate(bank, {1.0, 0.0, 0.0}, pitch, {0.0, 1.0, 0.0}, yaw, {0.0, 0.0, 1.0});
593}
594
595template <typename T>
596inline void Quat<T>::makeRotateFromEulerYPB(const Vec3<T>& eulerAngles) noexcept
597{
598 makeRotate(eulerAngles.z(), {1.0, 0.0, 0.0}, eulerAngles.y(), {0.0, 1.0, 0.0}, eulerAngles.x(), {0.0, 0.0, 1.0});
599}
600
601template <typename T>
602inline void Quat<T>::getRotate(T& angle, Vec3<T>& vec) const noexcept
603{
604 T x;
605 T y;
606 T z;
607 getRotate(angle, x, y, z);
608 vec.setX(x);
609 vec.setY(y);
610 vec.setZ(z);
611}
612
613template <typename T>
614inline void Quat<T>::getRotate(T& angle, T& x, T& y, T& z) const noexcept
615{
616 T sinhalfangle = std::sqrt(v_[0] * v_[0] + v_[1] * v_[1] + v_[2] * v_[2]);
617
618 angle = 2.0 * std::atan2(sinhalfangle, v_[3]);
619
620 if constexpr (std::is_same_v<f32, T>)
621 {
622 angle = angle > pif ? angle - 2.0f * pif : angle < -pif ? angle + 2.0f * pif : angle;
623 }
624 else
625 {
626 angle = angle > pi ? angle - 2.0 * pi : angle < -pi ? angle + 2.0 * pi : angle;
627 }
628
629 if (sinhalfangle != 0.0)
630 {
631 x = v_[0] / sinhalfangle;
632 y = v_[1] / sinhalfangle;
633 z = v_[2] / sinhalfangle;
634 }
635 else
636 {
637 x = 0.0;
638 y = 0.0;
639 z = 1.0;
640 }
641}
642
643template <typename T>
645{
646 const T sqw = v_[3] * v_[3];
647 const T sqx = v_[0] * v_[0];
648 const T sqy = v_[1] * v_[1];
649 const T sqz = v_[2] * v_[2];
650
651 const T sine = -2.0 * (v_[0] * v_[2] - v_[1] * v_[3]) / (sqx + sqy + sqz + sqw);
652
653 // At a right-angle pitch, yaw and bank turn about one axis and both arcs below lose all
654 // precision. The whole turn is reported as yaw. Folding a bank of up to pi costs about
655 // bank * cos(pitch), so this bound holds the error under 1e-6 rad. The pitch is not rounded.
656 constexpr T gimbalLimit = static_cast<T>(1) - static_cast<T>(1e-14);
657
658 if (std::abs(sine) > gimbalLimit)
659 {
660 return {static_cast<T>(2) * atan2(v_[2], v_[3]),
661 asin(std::clamp(sine, static_cast<T>(-1), static_cast<T>(1))),
662 static_cast<T>(0)};
663 }
664
665 const T yaw = atan2(2.0 * (v_[0] * v_[1] + v_[2] * v_[3]), (sqx - sqy - sqz + sqw));
666 const T pitch = asin(std::clamp(sine, static_cast<T>(-1), static_cast<T>(1)));
667 const T bank = atan2(2.0 * (v_[1] * v_[2] + v_[0] * v_[3]), (-sqx - sqy + sqz + sqw));
668
669 return {yaw, pitch, bank};
670}
671
672template <typename T>
673inline Vec3<T> Quat<T>::operator*(const Vec3<T>& v) const noexcept
674{
675 Vec3<T> uv;
676 Vec3<T> uuv;
677 Vec3<T> qvec(v_[0], v_[1], v_[2]);
678 uv = qvec ^ v;
679 uuv = qvec ^ uv;
680 uv *= 2.0 * v_[3];
681 uuv *= 2.0;
682 return v + uv + uuv;
683}
684
685template <typename T>
686inline void Quat<T>::slerp(T t, const Quat& from, const Quat& to) noexcept
687{
688 const double epsilon = 0.00001;
689 double omega;
690 double cosOmega;
691 double sinOmega;
692 double scaleFrom;
693 double scaleTo;
694
695 Quat quatTo(to);
696
697 cosOmega = from.v_[0] * to.v_[0] + from.v_[1] * to.v_[1] + from.v_[2] * to.v_[2] + from.v_[3] * to.v_[3];
698
699 if ((1.0 - cosOmega) > epsilon)
700 {
701 omega = acos(cosOmega);
702 sinOmega = sin(omega);
703 scaleFrom = sin((1.0 - t) * omega) / sinOmega;
704 scaleTo = sin(t * omega) / sinOmega;
705 }
706 else
707 {
708 scaleFrom = 1.0 - t;
709 scaleTo = t;
710 }
711
712 *this = (from * scaleFrom) + (quatTo * scaleTo);
713}
714
715} // namespace sen::util
716
717#endif // SEN_LIBS_UTIL_SRC_DR_QUAT_H
Quaternion. Represents the orientation of an object in space.
Definition quat.h:28
Quat & operator*=(T rhs) noexcept
Definition quat.h:313
f32 length() const noexcept
void slerp(f32 t, const Quat &from, const Quat &to) noexcept
bool operator==(const Quat &v) const noexcept
Definition quat.h:190
Quat operator/(const Quat &denom) const noexcept
Definition quat.h:365
f32 getX() const noexcept
void setX(f32 x) noexcept
Quat & operator-=(const Quat &rhs) noexcept
Definition quat.h:400
Vec3< f32 > asVec3() const noexcept
Quat operator+(const Quat &rhs) const noexcept
Definition quat.h:378
bool operator<(const Quat &v) const noexcept
Definition quat.h:202
void setW(f32 w) noexcept
Quat & operator/=(const Quat &denom) noexcept
Definition quat.h:371
bool operator!=(const Quat &v) const noexcept
Definition quat.h:196
Vec3< f32 > getRotateInEulerYPB() const noexcept
void getRotate(f32 &angle, f32 &x, f32 &y, f32 &z) const noexcept
f32 length2() const noexcept
f32 getZ() const noexcept
Quat operator-() const noexcept
Definition quat.h:410
void set(f32 x, f32 y, f32 z, f32 w) noexcept
void makeRotate(f32 angle, f32 x, f32 y, f32 z) noexcept
Quat() noexcept=default
void makeRotateFromEulerYPB(f32 yaw, f32 pitch, f32 bank) noexcept
f32 dot(const Quat< f32 > &other) const noexcept
void setY(f32 y) noexcept
f32 getY() const noexcept
void setZ(f32 z) noexcept
static Quat makeAxisRotation(f32 angle, const Vec3< f32 > &axis) noexcept
f32 getW() const noexcept
Quat & operator+=(const Quat &rhs) noexcept
Definition quat.h:384
Quat operator*(T rhs) const
Definition quat.h:307
bool zeroRotation() const noexcept
Handles all mathematical ops involving 3D Vectors.
Definition vec3.h:24
@ angle
Definition unit.h:35
Definition iterator_adapters.h:16
Quat< f64 > Quatd
Definition quat.h:156
constexpr f32 epsilon
Min value used to determine that an entity is not moving/accelerating.
Definition util/src/dr/constants.h:37
constexpr f32 pif
Definition util/src/dr/constants.h:19
Quat< f32 > Quatf
Definition quat.h:155
constexpr f64 pi
PI constant.
Definition util/src/dr/constants.h:18