diff --git a/src/Magnum/Math/Quaternion.h b/src/Magnum/Math/Quaternion.h index 838e6ecdd..a7274e744 100644 --- a/src/Magnum/Math/Quaternion.h +++ b/src/Magnum/Math/Quaternion.h @@ -39,6 +39,10 @@ namespace Magnum { namespace Math { +namespace Implementation { + template struct QuaternionConverter; +} + /** @relatesalso Quaternion @brief Dot product between two quaternions @@ -214,6 +218,14 @@ template class Quaternion { */ constexpr explicit Quaternion(const Vector3& vector): _vector(vector), _scalar(T(0)) {} + /** @brief Construct quaternion from external representation */ + template::from(std::declval()))> constexpr explicit Quaternion(const U& other): Quaternion{Implementation::QuaternionConverter::from(other)} {} + + /** @brief Convert quaternion to external representation */ + template::to(std::declval>()))> constexpr explicit operator U() const { + return Implementation::QuaternionConverter::to(*this); + } + /** @brief Equality comparison */ bool operator==(const Quaternion& other) const { return _vector == other._vector && TypeTraits::equals(_scalar, other._scalar); @@ -237,7 +249,7 @@ template class Quaternion { } /** @brief Vector part */ - constexpr Vector3 vector() const { return _vector; } + constexpr const Vector3 vector() const { return _vector; } /** @brief Scalar part */ constexpr T scalar() const { return _scalar; } diff --git a/src/Magnum/Math/Test/QuaternionTest.cpp b/src/Magnum/Math/Test/QuaternionTest.cpp index b9aba3231..115061eb1 100644 --- a/src/Magnum/Math/Test/QuaternionTest.cpp +++ b/src/Magnum/Math/Test/QuaternionTest.cpp @@ -29,7 +29,27 @@ #include "Magnum/Math/Matrix4.h" #include "Magnum/Math/Quaternion.h" -namespace Magnum { namespace Math { namespace Test { +struct Quat { + float x, y, z, w; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct QuaternionConverter { + constexpr static Quaternion from(const Quat& other) { + return {{other.x, other.y, other.z}, other.w}; + } + + constexpr static Quat to(const Quaternion& other) { + return {other.vector().x(), other.vector().y(), other.vector().z(), other.scalar() }; + } +}; + +} + +namespace Test { struct QuaternionTest: Corrade::TestSuite::Tester { explicit QuaternionTest(); @@ -38,6 +58,7 @@ struct QuaternionTest: Corrade::TestSuite::Tester { void constructDefault(); void constructFromVector(); void constructCopy(); + void convert(); void compare(); void isNormalized(); @@ -80,6 +101,7 @@ QuaternionTest::QuaternionTest() { &QuaternionTest::constructDefault, &QuaternionTest::constructFromVector, &QuaternionTest::constructCopy, + &QuaternionTest::convert, &QuaternionTest::compare, &QuaternionTest::isNormalized, @@ -139,6 +161,24 @@ void QuaternionTest::constructCopy() { CORRADE_COMPARE(b, Quaternion({1.0f, -3.0f, 7.0f}, 2.5f)); } +void QuaternionTest::convert() { + constexpr Quat a{1.5f, -3.5f, 7.0f, -0.5f}; + constexpr Quaternion b{{1.5f, -3.5f, 7.0f}, -0.5f}; + + constexpr Quaternion c{a}; + CORRADE_COMPARE(c, b); + + constexpr Quat d(b); + CORRADE_COMPARE(d.x, a.x); + CORRADE_COMPARE(d.y, a.y); + CORRADE_COMPARE(d.z, a.z); + CORRADE_COMPARE(d.w, a.w); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void QuaternionTest::compare() { CORRADE_VERIFY(Quaternion({1.0f+TypeTraits::epsilon()/2, 2.0f, 3.0f}, -4.0f) == Quaternion({1.0f, 2.0f, 3.0f}, -4.0f)); CORRADE_VERIFY(Quaternion({1.0f+TypeTraits::epsilon()*2, 2.0f, 3.0f}, -4.0f) != Quaternion({1.0f, 2.0f, 3.0f}, -4.0f));