Phyth v0.1.0
A dimensional safe C++ header-only mechanics and electromagnetics simulation library.
Loading...
Searching...
No Matches
Quaternion.hpp
Go to the documentation of this file.
1#ifndef PHYTH_QUATERNION_HPP
2#define PHYTH_QUATERNION_HPP
3
6#include "QuantityFuncs.hpp"
7#include "Vector3.hpp"
8
9#include <ostream>
10
11namespace Phyth {
32 template<typename T>
33 struct Quaternion {
34 static_assert(is_quantity_v<T>,
35 "Quaternion only supports Quantity types");
36
45
49 constexpr Quaternion() : w(1), x(0), y(0), z(0) {
50 }
51
60 constexpr Quaternion(T w_, T x_, T y_, T z_) : w(w_), x(x_), y(y_), z(z_) {
61 }
62
69 constexpr Quaternion(T w_, const Vector3<T> &v_) : w(w_), x(v_.x), y(v_.y), z(v_.z) {
70 }
71
80 constexpr explicit Quaternion(const Vector3<T> &v_) : w(0), x(v_.x), y(v_.y), z(v_.z) {
81 }
82
95 const auto half_theta = theta / 2;
96 const auto s = Utils::sin(half_theta);
97 const auto c = Utils::cos(half_theta);
98 return Quaternion(c, axis * s);
99 }
100
112 static Quaternion FromEuler(const Scalar yaw, const Scalar pitch, const Scalar roll) {
113 const auto cy = Utils::cos(yaw / 2);
114 const auto sy = Utils::sin(yaw / 2);
115 const auto cp = Utils::cos(pitch / 2);
116 const auto sp = Utils::sin(pitch / 2);
117 const auto cr = Utils::cos(roll / 2);
118 const auto sr = Utils::sin(roll / 2);
119
120 return Quaternion(
121 cr * cp * cy + sr * sp * sy,
122 sr * cp * cy - cr * sp * sy,
123 cr * sp * cy + sr * cp * sy,
124 cr * cp * sy - sr * sp * cy
125 );
126 }
127
129 [[nodiscard]] constexpr Vector3<T> ToVector() const {
130 return Vector3<T>(x, y, z);
131 }
132
134 [[nodiscard]] constexpr T ToQuantity() const {
135 return w;
136 }
137
143 [[nodiscard]] auto LengthSquared() const {
144 return w * w + x * x + y * y + z * z;
145 }
146
148 [[nodiscard]] auto Length() const {
149 return Utils::sqrt(LengthSquared());
150 }
151
157 [[nodiscard]] constexpr Quaternion Conjugated() const {
158 return Quaternion(w, -x, -y, -z);
159 }
160
166 [[nodiscard]] auto Inversed() const {
167 const auto length_sq = LengthSquared();
168 const auto conj = Conjugated();
169 return Quaternion<decltype(w / length_sq)>(
170 conj.w / length_sq,
171 conj.x / length_sq,
172 conj.y / length_sq,
173 conj.z / length_sq
174 );
175 }
176
178 [[nodiscard]] auto Normalized() const {
179 const auto length = Length();
180 return Quaternion<decltype(w / length)>(
181 w / length,
182 x / length,
183 y / length,
184 z / length
185 );
186 }
187
193 [[nodiscard]] bool IsUnit() const {
195 }
196
210 [[nodiscard]] auto Rotated(const Vector3<T> &v) const {
211 const auto qv = *this * Quaternion(v);
212 const auto result = qv * Inversed();
213 return result.ToVector();
214 }
215
222 template<typename U>
223 constexpr auto operator*(const Quaternion<U> &other) const {
224 using R = decltype(w * other.w);
225 return Quaternion<R>(
226 w * other.w - x * other.x - y * other.y - z * other.z,
227 w * other.x + x * other.w + y * other.z - z * other.y,
228 w * other.y - x * other.z + y * other.w + z * other.x,
229 w * other.z + x * other.y - y * other.x + z * other.w
230 );
231 }
232
234 template<typename U>
235 constexpr auto operator+(const Quaternion<U> &other) const {
236 return Quaternion<decltype(w + other.w)>(
237 w + other.w,
238 x + other.x,
239 y + other.y,
240 z + other.z
241 );
242 }
243
245 template<typename U>
246 constexpr auto operator-(const Quaternion<U> &other) const {
247 return Quaternion<decltype(w - other.w)>(
248 w - other.w,
249 x - other.x,
250 y - other.y,
251 z - other.z
252 );
253 }
254
256 constexpr auto operator-() const {
257 return Quaternion(-w, -x, -y, -z);
258 }
259
266 template<typename U>
267 constexpr auto operator*(Quantity<U> scalar) const {
269 w * scalar,
270 x * scalar,
271 y * scalar,
272 z * scalar
273 );
274 }
275
282 template<typename U>
283 constexpr auto operator/(U scalar) const {
284 return Quaternion<decltype(w / scalar)>(
285 w / scalar,
286 x / scalar,
287 y / scalar,
288 z / scalar
289 );
290 }
291
293 template<typename U>
295 w += other.w;
296 x += other.x;
297 y += other.y;
298 z += other.z;
299 return *this;
300 }
301
303 template<typename U>
305 w -= other.w;
306 x -= other.x;
307 y -= other.y;
308 z -= other.z;
309 return *this;
310 }
311
313 template<typename U>
315 w *= scalar;
316 x *= scalar;
317 y *= scalar;
318 z *= scalar;
319 return *this;
320 }
321
323 template<typename U>
325 w /= scalar;
326 x /= scalar;
327 y /= scalar;
328 z /= scalar;
329 return *this;
330 }
331
333 template<typename U>
334 constexpr bool operator==(const Quaternion<U> &other) const {
335 return w == other.w && x == other.x && y == other.y && z == other.z;
336 }
337
339 template<typename U>
340 constexpr bool operator!=(const Quaternion<U> &other) const {
341 return !(*this == other);
342 }
343
350 template<typename UnitT>
352 return {
353 w.template As<UnitT>(),
354 x.template As<UnitT>(),
355 y.template As<UnitT>(),
356 z.template As<UnitT>()
357 };
358 }
359
377 template<typename U>
378 static auto Slerp(const Quaternion &q1, const Quaternion<U> &q2, const Scalar t) {
379 auto cos_angle = q1.Dot(q2);
380 auto q2_adjusted = q2;
381 if (cos_angle < 0) {
384 }
385
386 const auto cos_angle_clamped = Utils::clamp(cos_angle, -1_, 1_);
387 const auto angle = Utils::acos(cos_angle_clamped);
388
389 if (angle < 1e-6_rad) {
390 return (q1 * (1_ - t) + q2_adjusted * t).Normalized();
391 }
392
393 const auto sin_angle = Utils::sin(angle);
394 const auto a = Utils::sin((1_ - t) * angle) / sin_angle;
395 const auto b = Utils::sin(t * angle) / sin_angle;
396
397 return (q1 * a + q2_adjusted * b).Normalized();
398 }
399
407 template<typename U>
408 [[nodiscard]] constexpr auto Dot(const Quaternion<U> &other) const {
409 return w * other.w + x * other.x + y * other.y + z * other.z;
410 }
411
418 constexpr T &operator[](int i) {
419 return (&w)[i];
420 }
421
428 constexpr const T &operator[](int i) const {
429 return (&w)[i];
430 }
431
438 friend std::ostream &operator<<(std::ostream &os, const Quaternion &q) {
439 os << "(" << q.w << " + " << q.x << "i + " << q.y << "j + " << q.z << "k)";
440 return os;
441 }
442 };
443
447 template<typename>
448 struct is_quaternion : std::false_type {
449 };
450
451 template<typename T>
452 struct is_quaternion<Quaternion<T> > : std::true_type {
453 };
454
458 template<typename T>
460
470 template<typename T, typename U>
471 constexpr auto operator*(const Quantity<T> scalar, const Quaternion<U> &q) {
472 return Quaternion<decltype(scalar * q.w)>(
473 scalar * q.w,
474 scalar * q.x,
475 scalar * q.y,
476 scalar * q.z
477 );
478 }
479}
480
481#endif // PHYTH_QUATERNION_HPP
double tolerance
Definition Config.hpp:15
Scalar cos(const Scalar q)
Cosine of a dimensionless quantity.
auto sqrt(Quantity< UnitT > q)
Square root of a quantity.
auto abs(Quantity< UnitT > q)
Absolute value of a quantity.
Quantity< UnitT > clamp(Quantity< UnitT > x, Quantity< UnitT > min, Quantity< UnitT > max)
Clamp a quantity between min and max bounds.
Scalar acos(const Scalar q)
Arc cosine (inverse cosine)
Scalar sin(const Scalar q)
Sine of a dimensionless quantity.
Quantity< ScalarUnit > Scalar
Definition Quantities.hpp:9
constexpr auto operator*(Quantity< U1 > a, Quantity< U2 > b)
Multiply two quantities.
Definition Quantity.hpp:524
constexpr auto is_quaternion_v
Convenience variable template for is_quaternion.
constexpr bool is_unit_v
Definition Unit.hpp:79
Quaternion with Quantity components.
constexpr auto operator-() const
Unary negation.
constexpr Quaternion & operator/=(U scalar)
Scalar division assignment.
constexpr Quaternion(const Vector3< T > &v_)
Construct from vector part only (scalar part = 0)
friend std::ostream & operator<<(std::ostream &os, const Quaternion &q)
Stream insertion operator for Quaternion.
Quaternion< Quantity< UnitT > > as() const
Convert all components to a different unit of the same dimension.
constexpr auto operator-(const Quaternion< U > &other) const
Quaternion subtraction.
constexpr bool operator==(const Quaternion< U > &other) const
Equality comparison.
static auto Slerp(const Quaternion &q1, const Quaternion< U > &q2, const Scalar t)
Spherical linear interpolation between two quaternions.
constexpr Quaternion(T w_, const Vector3< T > &v_)
Construct from scalar and vector parts.
constexpr bool operator!=(const Quaternion< U > &other) const
Inequality comparison.
auto LengthSquared() const
Squared magnitude.
constexpr auto operator*(Quantity< U > scalar) const
Scalar multiplication.
constexpr Quaternion Conjugated() const
Conjugate: (w + xi + yj + zk) -> (w - xi - yj - zk)
bool IsUnit() const
Check if the quaternion is a unit quaternion.
constexpr const T & operator[](int i) const
Index-based access (const)
constexpr auto operator*(const Quaternion< U > &other) const
Quaternion multiplication.
constexpr Quaternion(T w_, T x_, T y_, T z_)
Construct from scalar and vector components.
constexpr Vector3< T > ToVector() const
Extract the vector part as a Vector3.
constexpr Quaternion & operator*=(U scalar)
Scalar multiplication assignment.
constexpr Quaternion & operator+=(const Quaternion< U > &other)
Addition assignment.
auto Length() const
Magnitude (sqrt of LengthSquared)
constexpr auto operator+(const Quaternion< U > &other) const
Quaternion addition.
static Quaternion FromAxisAngle(const Vector3< T > &axis, const Scalar theta)
Create a unit quaternion from axis and angle.
constexpr auto Dot(const Quaternion< U > &other) const
Dot product of two quaternions.
static Quaternion FromEuler(const Scalar yaw, const Scalar pitch, const Scalar roll)
Create a unit quaternion from Euler angles (ZYX convention)
constexpr T & operator[](int i)
Index-based access (non-const)
constexpr T ToQuantity() const
Extract the scalar part.
auto Rotated(const Vector3< T > &v) const
Rotate a vector by this quaternion.
auto Normalized() const
Normalized quaternion (unit quaternion)
constexpr auto operator/(U scalar) const
Scalar division.
constexpr Quaternion()
Default constructor - identity quaternion (1 + 0i + 0j + 0k)
auto Inversed() const
Inverse: q^(-1) = conjugate / |q|^2.
constexpr Quaternion & operator-=(const Quaternion< U > &other)
Subtraction assignment.
3D vector with Quantity components
Definition Vector3.hpp:28
Trait: check if a type is a Quaternion instantiation.