41#ifndef UFO_NUMERIC_QUAT_HPP
42#define UFO_NUMERIC_QUAT_HPP
45#include <ufo/numeric/mat.hpp>
46#include <ufo/numeric/vec.hpp>
75template <std::
floating_po
int T =
float>
78 using size_type = std::size_t;
98 constexpr Quat() noexcept = default;
111 template <
std::floating_point U>
113 :
w(static_cast<T>(q.
w))
114 , x(static_cast<T>(q.x))
115 , y(static_cast<T>(q.y))
116 , z(static_cast<T>(q.z))
127 constexpr Quat(T
w, T x, T y, T z) noexcept :
w(
w), x(x), y(y), z(z) {}
138 T norm_u_norm_v = std::sqrt(
dot(u, u) *
dot(v, v));
139 T real_part = norm_u_norm_v +
dot(u, v);
142 if (real_part < T(1.e-6) * norm_u_norm_v) {
144 t = std::abs(u[0]) > std::abs(u[2]) ?
Vec<3, T>(-u[1], u[0], T(0))
160 Vec<3, T> const c{std::cos(euler_angles[0] * T(0.5)),
161 std::cos(euler_angles[1] * T(0.5)),
162 std::cos(euler_angles[2] * T(0.5))};
163 Vec<3, T> const s{std::sin(euler_angles[0] * T(0.5)),
164 std::sin(euler_angles[1] * T(0.5)),
165 std::sin(euler_angles[2] * T(0.5))};
167 w = c[0] * c[1] * c[2] + s[0] * s[1] * s[2];
168 x = s[0] * c[1] * c[2] - c[0] * s[1] * s[2];
169 y = c[0] * s[1] * c[2] + s[0] * c[1] * s[2];
170 z = c[0] * c[1] * s[2] - s[0] * s[1] * c[2];
180 T
const trace = m[0][0] + m[1][1] + m[2][2];
183 T s = std::sqrt(trace + T(1));
187 x = (m[2][1] - m[1][2]) * s;
188 y = (m[0][2] - m[2][0]) * s;
189 z = (m[1][0] - m[0][1]) * s;
191 unsigned const i = m[0][0] < m[1][1] ? (m[1][1] < m[2][2] ? 2u : 1u)
192 : (m[0][0] < m[2][2] ? 2u : 0u);
193 unsigned const j = (i + 1u) % 3u;
194 unsigned const k = (i + 2u) % 3u;
197 T s = std::sqrt(m[i][i] - m[j][j] - m[k][k] + T(1));
198 q[i + 1] = s * T(0.5);
200 q[0] = (m[k][j] - m[j][k]) * s;
201 q[j + 1] = (m[j][i] + m[i][j]) * s;
202 q[k + 1] = (m[k][i] + m[i][k]) * s;
234 template <std::
floating_po
int U>
237 w =
static_cast<T
>(rhs.w);
238 x =
static_cast<T
>(rhs.x);
239 y =
static_cast<T
>(rhs.y);
240 z =
static_cast<T
>(rhs.z);
255 [[nodiscard]]
constexpr explicit operator Mat<3, 3, T>() const noexcept
257 T
const xx(x * x), yy(y * y), zz(z * z);
258 T
const xz(x * z), xy(x * y), yz(y * z);
259 T
const wx(
w * x), wy(
w * y), wz(
w * z);
262 Vec<3, T>(T(1) - T(2) * (yy + zz), T(2) * (xy - wz), T(2) * (xz + wy)),
263 Vec<3, T>(T(2) * (xy + wz), T(1) - T(2) * (xx + zz), T(2) * (yz - wx)),
264 Vec<3, T>(T(2) * (xz - wy), T(2) * (yz + wx), T(1) - T(2) * (xx + yy)));
272 [[nodiscard]]
constexpr explicit operator Mat<4, 4, T>() const noexcept
292 [[nodiscard]]
constexpr auto&
operator[](
this auto& self, size_type pos)
noexcept
296 case 0:
return self.w;
297 case 1:
return self.x;
298 case 2:
return self.y;
299 default:
return self.z;
345 w = p.
w * q.w - p.x * q.x - p.y * q.y - p.z * q.z;
346 x = p.
w * q.x + p.x * q.w + p.y * q.z - p.z * q.y;
347 y = p.
w * q.y + p.y * q.w + p.z * q.x - p.x * q.z;
348 z = p.
w * q.z + p.z * q.w + p.x * q.y - p.y * q.x;
390 [[nodiscard]]
static constexpr size_type
size() noexcept {
return 4; }
442template <std::
floating_po
int T>
454template <std::
floating_po
int T>
457 return {-q.w, -q.x, -q.y, -q.z};
473template <std::
floating_po
int T>
487template <std::
floating_po
int T>
501template <std::
floating_po
int T>
517template <std::
floating_po
int T>
523 return v + ((uv * q.
w) + uuv) * T(2);
534template <std::
floating_po
int T>
548template <std::
floating_po
int T>
552 return Vec<4, T>(r[0], r[1], r[2], v[3]);
562template <std::
floating_po
int T>
566 return Vec<4, T>(r[0], r[1], r[2], v[3]);
576template <std::
floating_po
int T>
590template <std::
floating_po
int T>
604template <std::
floating_po
int T>
623template <std::
floating_po
int T>
642template <std::
floating_po
int T>
645 return a.w *
b.w +
a.x *
b.x +
a.y *
b.y +
a.z *
b.z;
654template <std::
floating_po
int T>
666template <std::
floating_po
int T>
678template <std::
floating_po
int T>
681 T
const len =
norm(q);
683 return {T(1), T(0), T(0), T(0)};
694template <std::
floating_po
int T>
697 return {q.
w, -q.x, -q.y, -q.z};
706template <std::
floating_po
int T>
720template <std::
floating_po
int T>
723 return {q1.
w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
724 q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
725 q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z,
726 q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x};
745template <std::
floating_po
int T>
748 T
const cos_theta =
dot(x, y);
750 if (cos_theta > T(1) - std::numeric_limits<T>::epsilon()) {
751 return {std::lerp(x.
w, y.
w,
a), std::lerp(x.x, y.x,
a), std::lerp(x.y, y.y,
a),
752 std::lerp(x.z, y.z,
a)};
755 T
const angle = std::acos(cos_theta);
756 return (std::sin((T(1) -
a) *
angle) * x + std::sin(
a *
angle) * y) / std::sin(
angle);
769template <std::
floating_po
int T>
772 assert(
a >= T(0) &&
a <= T(1));
773 return x * (T(1) -
a) + y *
a;
786template <std::
floating_po
int T>
790 T cos_theta =
dot(x, y);
792 if (cos_theta < T(0)) {
794 cos_theta = -cos_theta;
797 if (cos_theta > T(1) - std::numeric_limits<T>::epsilon()) {
798 return {std::lerp(x.
w, z.
w,
a), std::lerp(x.x, z.x,
a), std::lerp(x.y, z.y,
a),
799 std::lerp(x.z, z.z,
a)};
802 T
const angle = std::acos(cos_theta);
803 return (std::sin((T(1) -
a) *
angle) * x + std::sin(
a *
angle) * z) / std::sin(
angle);
818template <std::
floating_po
int T, std::
floating_po
int S>
822 T cos_theta =
dot(x, y);
824 if (cos_theta < T(0)) {
826 cos_theta = -cos_theta;
829 if (cos_theta > T(1) - std::numeric_limits<T>::epsilon()) {
830 return {std::lerp(x.
w, z.
w,
a), std::lerp(x.x, z.x,
a), std::lerp(x.y, z.y,
a),
831 std::lerp(x.z, z.z,
a)};
834 T
const angle = std::acos(cos_theta);
835 T
const phi =
angle + T(k) * std::numbers::pi_v<T>;
836 return (std::sin(
angle -
a * phi) * x + std::sin(
a * phi) * z) / std::sin(
angle);
851template <std::
floating_po
int T>
854 constexpr T cos_one_over_two = T(0.877582561890372716130286068203503191);
855 if (std::abs(q.w) > cos_one_over_two) {
856 T
const a = std::asin(std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z)) * T(2);
857 return q.w < T(0) ? std::numbers::pi_v<T> * T(2) -
a :
a;
859 return std::acos(q.w) * T(2);
868template <std::
floating_po
int T>
871 T
const tmp = T(1) - q.
w * q.w;
875 return Vec<3, T>(q.x, q.y, q.z) / std::sqrt(tmp);
885template <std::
floating_po
int T>
888 T
const s = std::sin(
angle * T(0.5));
889 return Quat<T>(std::cos(
angle * T(0.5)),
a[0] * s,
a[1] * s,
a[2] * s);
904template <std::
floating_po
int T>
907 return T(std::atan2(T(2) * (q.x * q.y + q.w * q.z),
908 q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z));
917template <std::
floating_po
int T>
920 return T(std::atan2(T(2) * (q.y * q.z + q.w * q.x),
921 q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z));
930template <std::
floating_po
int T>
933 return std::asin(std::clamp(T(-2) * (q.x * q.z - q.w * q.y), T(-1), T(1)));
942template <std::
floating_po
int T>
964template <std::
floating_po
int T>
968 if (std::abs(len - T(1)) > T(0.001)) {
971 T
const s = std::sin(
angle * T(0.5));
982template <std::
floating_po
int T>
987 right /= std::max(std::sqrt(T(0.00001)),
norm(right));
1009template <std::
floating_po
int T>
1012 return Vec<4, bool>(std::isnan(q.w), std::isnan(q.x), std::isnan(q.y), std::isnan(q.z));
1021template <std::
floating_po
int T>
1024 return Vec<4, bool>(std::isinf(q.w), std::isinf(q.x), std::isinf(q.y), std::isinf(q.z));
1040template <std::
floating_po
int T>
1041std::ostream& operator<<(std::ostream& out,
Quat<T> const& q)
1043 return out <<
"qw: " << q.
w <<
" qx: " << q.x <<
" qy: " << q.y <<
" qz: " << q.z;
1048template <std::
floating_po
int T>
1049 requires std::formattable<T, char>
1050struct std::formatter<
ufo::Quat<T>> {
1051 constexpr auto parse(std::format_parse_context& ctx) {
return ctx.begin(); }
1053 auto format(
ufo::Quat<T> const& q, std::format_context& ctx)
const
1055 return std::format_to(ctx.out(),
"qw: {} qx: {} qy: {} qz: {}", q.
w, q.x, q.y, q.z);
void swap(Quat &other) noexcept
Swaps all components with other.
Vec< 4, bool > isnan(Quat< T > const &q) noexcept
Returns a bool vector indicating which components are NaN.
Quat< T > mix(Quat< T > const &x, Quat< T > const &y, T a)
Spherical or linear interpolation between two quaternions.
T angle(Quat< T > const &q) noexcept
Extracts the rotation angle (in radians) from a unit quaternion.
constexpr Quat() noexcept=default
Default constructor; initializes to the identity rotation (1, 0, 0, 0).
constexpr auto & operator[](this auto &self, size_type pos) noexcept
Component access by index: 0->w, 1->x, 2->y, 3->z.
T roll(Quat< T > const &q) noexcept
Extracts the roll angle (rotation about the X-axis) in radians.
constexpr Quat & operator+=(Quat const &q) noexcept
Component-wise addition.
constexpr Quat & operator=(Quat const &) noexcept=default
Copy assignment operator.
constexpr T dot(Quat< T > const &a, Quat< T > const &b) noexcept
Computes the four-component dot product a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z.
static constexpr size_type size() noexcept
Returns the number of components (always 4: w, x, y, z).
All vision-related classes and functions.
constexpr T normSquared(Quat< T > const &q) noexcept
Returns the squared norm (dot product with itself).
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
constexpr Mat< Rows, Cols, T > operator*(Mat< Rows, Cols, T > lhs, T rhs) noexcept
Multiplies every element of lhs by scalar rhs.
constexpr Mat< Rows, Cols, T > operator/(Mat< Rows, Cols, T > lhs, T rhs) noexcept
Divides every element of lhs by scalar rhs.
Quat< T > slerp(Quat< T > const &x, Quat< T > const &y, T a)
Spherical linear interpolation (SLERP) between two unit quaternions.
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
Quat< T > quatLookAt(Vec< 3, T > const &direction, Vec< 3, T > const &up)
Builds a quaternion that orients an object to look in direction.
T pitch(Quat< T > const &q) noexcept
Extracts the pitch angle (rotation about the Y-axis) in radians.
constexpr Quat< T > angleAxis(T angle, Vec< 3, T > const &a) noexcept
Constructs a unit quaternion from an angle-axis representation.
constexpr T length(Vec< Dim, T > const &v) noexcept
Computes the Euclidean length (magnitude) of a vector.
Vec< 3, T > eulerAngles(Quat< T > const &q) noexcept
Returns the Euler angles (pitch, yaw, roll) in radians.
Vec< 4, bool > isinf(Quat< T > const &q) noexcept
Returns a bool vector indicating which components are infinite.
constexpr Quat< T > normalize(Quat< T > const &q) noexcept
Returns a unit quaternion in the same direction as q.
constexpr T norm(Quat< T > const &q) noexcept
Returns the Euclidean norm sqrt(w² + x² + y² + z²).
T yaw(Quat< T > const &q) noexcept
Extracts the yaw angle (rotation about the Z-axis) in radians.
constexpr Quat< T > cross(Quat< T > const &q1, Quat< T > const &q2) noexcept
Computes the Hamilton cross product of two quaternions.
constexpr Quat< T > lerp(Quat< T > const &x, Quat< T > const &y, T a) noexcept
Normalised linear interpolation (NLERP) between two quaternions.
constexpr M inverse(M const &m) noexcept
Computes the inverse of a square floating-point matrix.
Mat< 4, 4, T > rotate(Mat< 4, 4, T > const &m, T angle, Vec< 3, T > const &v)
Applies an axis-angle rotation to a 4×4 matrix.
Vec< 3, T > axis(Quat< T > const &q) noexcept
Extracts the unit rotation axis from a unit quaternion.
constexpr Quat< T > conjugate(Quat< T > const &q) noexcept
Returns the quaternion conjugate (w, -x, -y, -z).
A fixed-size matrix with Rows rows and Cols columns.
Unit quaternion representing an orientation or rotation in 3-D space.
constexpr Quat(T w, T x, T y, T z) noexcept
Constructs a quaternion from explicit (w, x, y, z) components.
constexpr Quat & operator=(Quat< U > const &rhs) noexcept
Converting assignment from a quaternion with a different scalar type.
constexpr bool operator==(Quat const &) const noexcept=default
Component-wise equality comparison.
constexpr Quat & operator*=(Quat const &q) noexcept
Hamilton (quaternion) product in place.
constexpr Quat & operator/=(T s) noexcept
Divides all components by scalar s.
constexpr Quat & operator*=(T s) noexcept
Scales all components by scalar s.
constexpr Quat(Mat< 3, 3, T > const &m) noexcept
Constructs a quaternion from a row-major 3×3 rotation matrix.
constexpr explicit(!std::is_same_v< T, U >) Quat(Quat< U > const &q) noexcept
Converting constructor from a quaternion with a different scalar type.
T w
Quaternion components. Must satisfy w^2 + x^2 + y^2 + z^2 == 1 for a valid rotation.
constexpr Quat(Mat< 4, 4, T > const &m) noexcept
Constructs a quaternion from the upper-left 3×3 block of a 4×4 matrix.
constexpr Quat & operator-=(Quat const &q) noexcept
Component-wise subtraction.
Quat(Vec< 3, T > const &u, Vec< 3, T > const &v)
Constructs the shortest-arc rotation quaternion from u to v.
Quat(Vec< 3, T > const &euler_angles)
Constructs a quaternion from Euler angles (pitch, yaw, roll) in radians.
A fixed-size arithmetic vector of up to 4 dimensions.
constexpr auto & w(this auto &self) noexcept
Accesses the fourth component (w).