20 #ifndef ANTKEEPER_MATH_QUATERNION_HPP
21 #define ANTKEEPER_MATH_QUATERNION_HPP
61 [[nodiscard]]
inline constexpr
const scalar_type&
w() const noexcept
73 [[nodiscard]]
inline constexpr
const scalar_type&
x() const noexcept
85 [[nodiscard]]
inline constexpr
const scalar_type&
y() const noexcept
97 [[nodiscard]]
inline constexpr
const scalar_type&
z() const noexcept
112 return {std::cos(
angle * T{0.5}), std::sin(
angle * T{0.5}), T{0}, T{0}};
124 return {std::cos(
angle * T{0.5}), T{0}, std::sin(
angle * T{0.5}), T{0}};
135 return {std::cos(
angle * T{0.5}), T{0}, T{0}, std::sin(
angle * T{0.5})};
146 [[nodiscard]]
inline constexpr
explicit operator quaternion<U>() const noexcept
157 [[nodiscard]] constexpr
explicit operator matrix_type() const noexcept
159 const T xx =
x() *
x();
160 const T xy =
x() *
y();
161 const T xz =
x() *
z();
162 const T xw =
x() *
w();
163 const T yy =
y() *
y();
164 const T yz =
y() *
z();
165 const T yw =
y() *
w();
166 const T zz =
z() *
z();
167 const T zw =
z() *
w();
171 T{1} - (yy + zz) * T{2}, (xy + zw) * T{2}, (xz - yw) * T{2},
172 (xy - zw) * T{2}, T{1} - (xx + zz) * T{2}, (yz + xw) * T{2},
173 (xz + yw) * T{2}, (yz - xw) * T{2}, T{1} - (xx + yy) * T{2}
188 [[nodiscard]]
inline constexpr
explicit operator vec4<T>() const noexcept
190 return {
r,
i.
x(),
i.
y(),
i.
z()};
207 namespace quaternion_types {
230 using namespace quaternion_types;
244 [[nodiscard]] constexpr quaternion<T> add(
const quaternion<T>& a,
const quaternion<T>& b) noexcept;
255 [[nodiscard]] constexpr quaternion<T> add(
const quaternion<T>& a, T b) noexcept;
265 [[nodiscard]] constexpr quaternion<T>
conjugate(
const quaternion<T>& q) noexcept;
276 [[nodiscard]] constexpr T dot(
const quaternion<T>& a,
const quaternion<T>& b) noexcept;
287 [[nodiscard]] constexpr quaternion<T>
div(
const quaternion<T>& a,
const quaternion<T>& b) noexcept;
298 [[nodiscard]] constexpr quaternion<T>
div(
const quaternion<T>& a, T b) noexcept;
309 [[nodiscard]] constexpr quaternion<T>
div(T a,
const quaternion<T>& b) noexcept;
319 [[nodiscard]] T
inv_length(
const quaternion<T>& q);
329 [[nodiscard]] T
length(
const quaternion<T>& q);
341 [[nodiscard]] constexpr quaternion<T>
lerp(
const quaternion<T>& a,
const quaternion<T>& b, T t) noexcept;
352 [[nodiscard]] quaternion<T>
look_rotation(
const vec3<T>& forward, vec3<T> up);
363 [[nodiscard]] constexpr quaternion<T>
mul(
const quaternion<T>& a,
const quaternion<T>& b) noexcept;
374 [[nodiscard]] constexpr quaternion<T>
mul(
const quaternion<T>& a, T b) noexcept;
389 [[nodiscard]] constexpr vec3<T>
mul(
const quaternion<T>& q,
const vec3<T>& v) noexcept;
402 [[nodiscard]] constexpr vec3<T>
mul(
const vec3<T>& v,
const quaternion<T>& q) noexcept;
412 [[nodiscard]] constexpr quaternion<T>
negate(
const quaternion<T>& q) noexcept;
424 [[nodiscard]] quaternion<T>
nlerp(
const quaternion<T>& a,
const quaternion<T>& b, T t);
434 [[nodiscard]] quaternion<T>
normalize(
const quaternion<T>& q);
459 [[nodiscard]] quaternion<T>
rotation(
const vec3<T>& from,
const vec3<T>& to, T tolerance = T{1e-6});
473 [[nodiscard]] quaternion<T>
rotate_towards(
const vec3<T>& from,
const vec3<T>& to, T max_angle);
486 [[nodiscard]] quaternion<T>
slerp(
const quaternion<T>& a,
const quaternion<T>& b, T t, T tolerance = T{1
e-6});
496 [[nodiscard]] constexpr T
sqr_length(
const quaternion<T>& q) noexcept;
507 [[nodiscard]] constexpr quaternion<T>
sub(
const quaternion<T>& a,
const quaternion<T>& b) noexcept;
519 [[nodiscard]] constexpr quaternion<T>
sub(
const quaternion<T>& a, T b) noexcept;
521 [[nodiscard]] constexpr quaternion<T>
sub(T a,
const quaternion<T>& b) noexcept;
541 [[nodiscard]] std::array<quaternion<T>, 2>
swing_twist(
const quaternion<T>& q,
const vec3<T>& twist_axis, T tolerance = T{1
e-6});
556 return {a.r + b.r, a.i + b.i};
562 return {a.r + b, a.i + b};
574 return a.r * b.r +
dot(a.i, b.i);
580 return {a.r / b.r, a.i / b.i};
586 return {a.r / b, a.i / b};
592 return {a / b.r, a / b.i};
612 (b.r - a.r) * t + a.r,
613 (b.i - a.i) * t + a.i
621 up =
cross(right, forward);
639 a.w() * b.w() - a.x() * b.x() - a.y() * b.y() - a.z() * b.z(),
640 a.w() * b.x() + a.x() * b.w() + a.y() * b.z() - a.z() * b.y(),
641 a.w() * b.y() - a.x() * b.z() + a.y() * b.w() + a.z() * b.x(),
642 a.w() * b.z() + a.x() * b.y() - a.y() * b.x() + a.z() * b.w()
649 return {a.r * b, a.i * b};
655 const auto t =
cross(q.i, v) * T{2};
656 return v + q.r * t +
cross(q.i, t);
662 const auto t =
cross(v, q.i) * T{2};
663 return v + q.r * t +
cross(t, q.i);
687 return {std::cos(
angle * T{0.5}), axis * std::sin(
angle * T{0.5})};
693 const auto cos_theta =
dot(from, to);
695 if (cos_theta <= T{-1} + tolerance)
700 else if (cos_theta >= T{1} - tolerance)
707 const auto r = cos_theta + T{1};
708 const auto i =
cross(from, to);
718 const auto angle = std::acos(
dot(from, to));
719 const auto axis =
cross(from, to);
726 T cos_theta =
dot(a, b);
727 if (cos_theta >= T{1} - tolerance)
734 cos_theta = std::min<T>(std::max<T>(cos_theta, T{-1}), T{1});
736 const T theta = std::acos(cos_theta) * t;
740 return add(
mul(a, std::cos(theta)),
mul(c, std::sin(theta)));
752 return {a.r - b.r, a.i - b.i};
758 return {a.r - b, a.i - b};
764 return {a - b.r, a - b.i};
778 const auto rotated_twist_axis =
mul(q, twist_axis);
779 const auto swing_axis =
cross(twist_axis, rotated_twist_axis);
780 const auto swing_axis_sqr_length =
sqr_length(swing_axis);
782 if (swing_axis_sqr_length <= tolerance)
789 const auto cos_swing_angle = std::min<T>(std::max<T>(
dot(twist_axis, rotated_twist_axis), T{-1}), T{1});
790 swing =
angle_axis(std::acos(cos_swing_angle), swing_axis * (T{1} /
std::sqrt(swing_axis_sqr_length)));
799 return {std::move(swing), std::move(twist)};
805 const T t =
trace(m);
809 const T s = T{0.5} /
std::sqrt(t + T{1});
813 (m[1][2] - m[2][1]) * s,
814 (m[2][0] - m[0][2]) * s,
815 (m[0][1] - m[1][0]) * s
820 if (m[0][0] > m[1][1] && m[0][0] > m[2][2])
822 const T s = T{2} *
std::sqrt(T{1} + m[0][0] - m[1][1] - m[2][2]);
826 (m[1][2] - m[2][1]) / s,
828 (m[1][0] + m[0][1]) / s,
829 (m[2][0] + m[0][2]) / s
832 else if (m[1][1] > m[2][2])
834 const T s = T{2} *
std::sqrt(T{1} + m[1][1] - m[0][0] - m[2][2]);
837 (m[2][0] - m[0][2]) / s,
838 (m[1][0] + m[0][1]) / s,
840 (m[2][1] + m[1][2]) / s
845 const T s = T{2} *
std::sqrt(T{1} + m[2][2] - m[0][0] - m[1][1]);
848 (m[0][1] - m[1][0]) / s,
849 (m[2][0] + m[0][2]) / s,
850 (m[2][1] + m[1][2]) / s,
857 namespace operators {
constexpr quaternion< T > operator-(const quaternion< T > &q) noexcept
Negates a quaternion.
constexpr vec3< T > operator*(const vec3< T > &v, const quaternion< T > &q) noexcept
Rotates a vector by the inverse of a unit quaternion.
constexpr quaternion< T > & operator/=(quaternion< T > &a, T b) noexcept
Divides the first value by the second value and stores the result in the first value.
constexpr quaternion< T > operator+(T a, const quaternion< T > &b) noexcept
constexpr quaternion< T > operator/(T a, const quaternion< T > &b) noexcept
Divides a scalar by a quaternion.
constexpr quaternion< T > & operator-=(quaternion< T > &a, T b) noexcept
Subtracts the first value by the second value and stores the result in the first value.
constexpr quaternion< T > & operator*=(quaternion< T > &a, T b) noexcept
Multiplies two values and stores the result in the first value.
constexpr quaternion< T > & operator+=(quaternion< T > &a, T b) noexcept
Adds two values and stores the result in the first value.
Mathematical functions and data types.
quaternion< T > nlerp(const quaternion< T > &a, const quaternion< T > &b, T t)
Performs normalized linear interpolation between two quaternions.
quaternion< T > rotate_towards(const vec3< T > &from, const vec3< T > &to, T max_angle)
Constructs a quaternion representing an angle-limited rotation from one direction towards another dir...
quaternion< T > quaternion_cast(const mat3< T > &m)
Converts a 3x3 rotation matrix to a quaternion.
constexpr matrix< T, P, M > mul(const matrix< T, N, M > &a, const matrix< T, P, N > &b) noexcept
Multiplies two matrices.
T angle(const vector< T, N > &from, const vector< T, N > &to)
Calculates the angle between two direction vectors.
constexpr T trace(const matrix< T, N, N > &m) noexcept
Calculates the trace of a square matrix.
quaternion< T > slerp(const quaternion< T > &a, const quaternion< T > &b, T t, T tolerance=T{1e-6})
Performs spherical linear interpolation between two quaternions.
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
constexpr matrix< T, N, M > div(const matrix< T, N, M > &a, const matrix< T, N, M > &b) noexcept
Divides a matrix by a matrix.
quaternion< T > angle_axis(T angle, const vec3< T > &axis)
Creates a rotation from an angle and axis.
T length(const quaternion< T > &q)
Calculates the length of a quaternion.
quaternion< T > look_rotation(const vec3< T > &forward, vec3< T > up)
Creates a unit quaternion rotation using forward and up vectors.
constexpr matrix< T, N, M > add(const matrix< T, N, M > &a, const matrix< T, N, M > &b) noexcept
Adds two matrices.
quaternion< T > rotation(const vec3< T > &from, const vec3< T > &to, T tolerance=T{1e-6})
Constructs a quaternion representing the minimum rotation from one direction to another direction.
constexpr T sqr_length(const quaternion< T > &q) noexcept
Calculates the square length of a quaternion.
constexpr matrix< T, N, M > sub(const matrix< T, N, M > &a, const matrix< T, N, M > &b) noexcept
Subtracts a matrix from another matrix.
std::array< quaternion< T >, 2 > swing_twist(const quaternion< T > &q, const vec3< T > &twist_axis, T tolerance=T{1e-6})
Decomposes a quaternion into swing and twist rotation components.
constexpr quaternion< T > conjugate(const quaternion< T > &q) noexcept
Calculates the conjugate of a quaternion.
constexpr vector< T, 3 > cross(const vector< T, 3 > &x, const vector< T, 3 > &y) noexcept
Calculates the cross product of two vectors.
vector< T, N > sqrt(const vector< T, N > &x)
Takes the square root of each element.
constexpr T lerp(const T &x, const T &y, S a) noexcept
Linearly interpolates between x and y.
constexpr T dot(const quaternion< T > &a, const quaternion< T > &b) noexcept
Calculates the dot product of two quaternions.
T inv_length(const quaternion< T > &q)
Calculates the inverse length of a quaternion.
constexpr vector< T, N > min(const vector< T, N > &x, const vector< T, N > &y)
Returns a vector containing the minimum elements of two vectors.
constexpr quaternion< T > negate(const quaternion< T > &q) noexcept
Negates a quaternion.
n by m column-major matrix.
Quaternion composed of a real scalar part and imaginary vector part.
constexpr const scalar_type & w() const noexcept
Returns a reference to the quaternion real part.
mat3< T > matrix_type
Rotation matrix type.
scalar_type r
Quaternion real part.
constexpr matrix_type matrix() const noexcept
Constructs a matrix representing the rotation described by the quaternion.
constexpr scalar_type & w() noexcept
Returns a reference to the quaternion real part.
constexpr const scalar_type & x() const noexcept
Returns a reference to the first element of the quaternion imaginary part.
static quaternion rotate_z(scalar_type angle)
Returns a quaternion representing a rotation about the z-axis.
static constexpr quaternion zero() noexcept
Returns a zero quaternion, where every scalar is equal to zero.
T scalar_type
Scalar type.
static quaternion rotate_x(scalar_type angle)
Returns a quaternion representing a rotation about the x-axis.
vector_type i
Quaternion imaginary part.
static quaternion rotate_y(scalar_type angle)
Returns a quaternion representing a rotation about the y-axis.
constexpr const scalar_type & z() const noexcept
Returns a reference to the third element of the quaternion imaginary part.
constexpr scalar_type & y() noexcept
Returns a reference to the second element of the quaternion imaginary part.
constexpr scalar_type & z() noexcept
Returns a reference to the third element of the quaternion imaginary part.
static constexpr quaternion identity() noexcept
Returns a rotation identity quaternion.
constexpr scalar_type & x() noexcept
Returns a reference to the first element of the quaternion imaginary part.
constexpr const scalar_type & y() const noexcept
Returns a reference to the second element of the quaternion imaginary part.
constexpr element_type & x() noexcept
Returns a reference to the first element.
constexpr element_type & y() noexcept
Returns a reference to the second element.
static constexpr vector zero() noexcept
Returns a zero vector, where every element is equal to zero.
constexpr element_type & z() noexcept
Returns a reference to the third element.