From 8f05ef141c088c268955042e3f48ded1c3b84f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 19 Dec 2024 17:35:57 +0100 Subject: [PATCH] Math: add Quaternion::xyzw() and wxyz(). --- doc/changelog.dox | 2 ++ src/Magnum/Math/Complex.h | 3 +- src/Magnum/Math/Quaternion.h | 38 +++++++++++++++++++++++-- src/Magnum/Math/Test/QuaternionTest.cpp | 25 ++++++++++------ 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index c1a560c72..37ef1b6ee 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -285,6 +285,8 @@ See also: @ref Math::Quaternion::reflectVector(), but mainly just for documentation purposes as reflections cannot be combined with rotations and thus are mostly useless in practice +- Added @ref Math::Quaternion::xyzw() and @ref Math::Quaternion::wxyz() + helpers for converting to a @ref Vector4 in chosen component order - New @ref Magnum/Math/ColorBatch.h header with utilities for performing Y flip of various block-compressed formats - New @ref Math::Nanoseconds and @ref Math::Seconds classes for strongly diff --git a/src/Magnum/Math/Complex.h b/src/Magnum/Math/Complex.h index e3c31bb7c..33fbb6fd6 100644 --- a/src/Magnum/Math/Complex.h +++ b/src/Magnum/Math/Complex.h @@ -257,7 +257,8 @@ template class Complex { * @f[ * \boldsymbol v = \begin{pmatrix} a \\ b \end{pmatrix} * @f] - * @see @ref Complex(const Vector2&) + * @see @ref Complex(const Vector2&), @ref Quaternion::xyzw(), + * @ref Quaternion::wxyz() */ constexpr explicit operator Vector2() const { return {_real, _imaginary}; diff --git a/src/Magnum/Math/Quaternion.h b/src/Magnum/Math/Quaternion.h index 4c755216d..63155cda3 100644 --- a/src/Magnum/Math/Quaternion.h +++ b/src/Magnum/Math/Quaternion.h @@ -469,16 +469,50 @@ template class Quaternion { return Implementation::isNormalizedSquared(dot()); } - /** @brief Vector part (@f$ \boldsymbol{q}_V @f$) */ + /** + * @brief Vector part (@f$ \boldsymbol{q}_V @f$) + * + * @see @ref xyzw(), @ref wxyz() + */ Vector3& vector() { return _vector; } /* Returning const so it's possible to call constexpr functions on the result. WTF, C++?! */ constexpr const Vector3 vector() const { return _vector; } /**< @overload */ - /** @brief Scalar part (@f$ q_S @f$) */ + /** + * @brief Scalar part (@f$ q_S @f$) + * + * @see @ref xyzw(), @ref wxyz() + */ T& scalar() { return _scalar; } constexpr T scalar() const { return _scalar; } /**< @overload */ + /** + * @brief Quaternion components in a XYZW order + * @m_since_latest + * + * Returns a four-component vector containing @ref vector() in the XYZ + * components and @ref scalar() in W: @f[ + * v = [q_{V_x}, q_{V_y}, q_{V_z}, s] + * @f] + * @see @ref Complex::operator Vector2() + */ + constexpr Vector4 xyzw() const { return {_vector, _scalar}; } + + /** + * @brief Quaternion components in a WXYZ order + * @m_since_latest + * + * Returns a four-component vector containing @ref scalar() in the X + * component and @ref vector() in YZW: @f[ + * v = [s, q_{V_x}, q_{V_y}, q_{V_z}] + * @f] + * @see @ref Complex::operator Vector2() + */ + constexpr Vector4 wxyz() const { + return {_scalar, _vector.x(), _vector.y(), _vector.z()}; + } + /** * @brief Rotation angle of a unit quaternion * diff --git a/src/Magnum/Math/Test/QuaternionTest.cpp b/src/Magnum/Math/Test/QuaternionTest.cpp index c15747674..e92a20705 100644 --- a/src/Magnum/Math/Test/QuaternionTest.cpp +++ b/src/Magnum/Math/Test/QuaternionTest.cpp @@ -339,24 +339,31 @@ void QuaternionTest::convert() { } void QuaternionTest::data() { + Quaternion a{{1.0f, 2.0f, 3.0f}, -4.0f}; + CORRADE_COMPARE(a.vector(), (Vector3{1.0f, 2.0f, 3.0f})); + CORRADE_COMPARE(a.scalar(), -4.0f); + CORRADE_COMPARE(a.xyzw(), (Vector4{1.0f, 2.0f, 3.0f, -4.0f})); + CORRADE_COMPARE(a.wxyz(), (Vector4{-4.0f, 1.0f, 2.0f, 3.0f})); + + a.vector().y() = 4.3f; + a.scalar() = 1.1f; + CORRADE_COMPARE(a, (Quaternion{{1.0f, 4.3f, 3.0f}, 1.1f})); + CORRADE_COMPARE(a.data()[3], 1.1f); + CORRADE_COMPARE(Containers::arraySize(a.data()), 4); + constexpr Quaternion ca{{1.0f, 2.0f, 3.0f}, -4.0f}; constexpr Vector3 vector = ca.vector(); constexpr Float scalar = ca.scalar(); + constexpr Vector4 xyzw = ca.xyzw(); + constexpr Vector4 wxyz = ca.wxyz(); CORRADE_COMPARE(vector, (Vector3{1.0f, 2.0f, 3.0f})); CORRADE_COMPARE(scalar, -4.0f); - - Quaternion a{{1.0f, 2.0f, 3.0f}, -4.0f}; - a.vector().y() = 4.3f; - a.scalar() = 1.1f; - CORRADE_COMPARE(a, (Quaternion{{1.0f, 4.3f, 3.0f}, 1.1f})); + CORRADE_COMPARE(xyzw, (Vector4{1.0f, 2.0f, 3.0f, -4.0f})); + CORRADE_COMPARE(wxyz, (Vector4{-4.0f, 1.0f, 2.0f, 3.0f})); /* Not constexpr anymore, as it has to reinterpret to return a correctly-sized array */ - CORRADE_COMPARE(a.data()[3], 1.1f); CORRADE_COMPARE(ca.data()[1], 2.0f); - - /* It actually returns an array */ - CORRADE_COMPARE(Containers::arraySize(a.data()), 4); CORRADE_COMPARE(Containers::arraySize(ca.data()), 4); }