diff --git a/doc/changelog.dox b/doc/changelog.dox index 398d6ceaf..58369276c 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -76,6 +76,11 @@ See also: - Added @ref Math::Quaternion::toEuler() and documented how to convert Euler angles to a quaternion (see [mosra/magnum#397](https://github.com/mosra/magnum/pull/397)) +- Added @ref Math::DualComplex::transformVector(), + @ref Math::DualQuaternion::transformVector(), + @ref Math::DualQuaternion::transformVectorNormalized() delegating to + respective APIs in the underlying @ref Complex / @ref Quaternion to make + the transformation API more consistent with @ref Matrix3 / @ref Matrix4 @subsubsection changelog-latest-new-platform Platform libraries diff --git a/src/Magnum/Math/DualComplex.h b/src/Magnum/Math/DualComplex.h index a6b487601..1c030b234 100644 --- a/src/Magnum/Math/DualComplex.h +++ b/src/Magnum/Math/DualComplex.h @@ -339,6 +339,17 @@ template class DualComplex: public Dual> { return DualComplex(Dual>::real().invertedNormalized(), {{}, {}})*DualComplex({}, -Dual>::dual()); } + /** + * @brief Rotate a vector with a dual complex number + * @m_since_latest + * + * Calls @ref Complex::transformVector() on the @ref real() part, + * see its documentation for more information. + */ + Vector2 transformVector(const Vector2& vector) const { + return Dual>::real().transformVector(vector); + } + /** * @brief Rotate and translate point with dual complex number * @@ -346,7 +357,7 @@ template class DualComplex: public Dual> { * v' = \hat c v = \hat c ((0 + i) + \epsilon(v_x + iv_y)) * @f] * @see @ref DualComplex(const Vector2&), @ref dual(), - * @ref Matrix3::transformPoint(), @ref Complex::transformVector(), + * @ref Matrix3::transformPoint(), * @ref DualQuaternion::transformPoint() */ Vector2 transformPoint(const Vector2& vector) const { diff --git a/src/Magnum/Math/DualQuaternion.h b/src/Magnum/Math/DualQuaternion.h index cd7515998..1d56ec991 100644 --- a/src/Magnum/Math/DualQuaternion.h +++ b/src/Magnum/Math/DualQuaternion.h @@ -474,6 +474,28 @@ template class DualQuaternion: public Dual> { return quaternionConjugated(); } + /** + * @brief Rotate a vector with a dual quaternion + * @m_since_latest + * + * Calls @ref Quaternion::transformVector() on the @ref real() part, + * see its documentation for more information. + */ + Vector3 transformVector(const Vector3& vector) const { + return Dual>::real().transformVector(vector); + } + + /** + * @brief Rotate a vector with a normalized dual quaternion + * @m_since_latest + * + * Calls @ref Quaternion::transformVectorNormalized() on the + * @ref real() part, see its documentation for more information. + */ + Vector3 transformVectorNormalized(const Vector3& vector) const { + return Dual>::real().transformVectorNormalized(vector); + } + /** * @brief Rotate and translate point with dual quaternion * @@ -483,7 +505,6 @@ template class DualQuaternion: public Dual> { * @f] * @see @ref DualQuaternion(const Vector3&), @ref dual(), * @ref Matrix4::transformPoint(), - * @ref Quaternion::transformVector(), * @ref DualComplex::transformPoint() */ Vector3 transformPoint(const Vector3& vector) const { diff --git a/src/Magnum/Math/Test/DualComplexTest.cpp b/src/Magnum/Math/Test/DualComplexTest.cpp index ae304b91a..b08338137 100644 --- a/src/Magnum/Math/Test/DualComplexTest.cpp +++ b/src/Magnum/Math/Test/DualComplexTest.cpp @@ -90,6 +90,7 @@ struct DualComplexTest: Corrade::TestSuite::Tester { void combinedTransformParts(); void matrix(); void matrixNotOrthogonal(); + void transformVector(); void transformPoint(); void strictWeakOrdering(); @@ -147,6 +148,7 @@ DualComplexTest::DualComplexTest() { &DualComplexTest::combinedTransformParts, &DualComplexTest::matrix, &DualComplexTest::matrixNotOrthogonal, + &DualComplexTest::transformVector, &DualComplexTest::transformPoint, &DualComplexTest::strictWeakOrdering, @@ -439,6 +441,17 @@ void DualComplexTest::matrixNotOrthogonal() { " 0, 0, 2)\n"); } +void DualComplexTest::transformVector() { + DualComplex a = Complex::rotation(23.0_degf); + Complex c = Complex::rotation(23.0_degf); + Vector2 v{-3.6f, 0.7f}; + + Vector2 rotated = a.transformVector(v); + /* Delegates to Complex, so should give the same result */ + CORRADE_COMPARE(rotated, c.transformVector(v)); + CORRADE_COMPARE(rotated, (Vector2{-3.58733f, -0.762279f})); +} + void DualComplexTest::transformPoint() { DualComplex a = DualComplex::translation({2.0f, 3.0f})*DualComplex::rotation(Deg(23.0f)); DualComplex b = DualComplex::rotation(Deg(23.0f))*DualComplex::translation({2.0f, 3.0f}); diff --git a/src/Magnum/Math/Test/DualQuaternionTest.cpp b/src/Magnum/Math/Test/DualQuaternionTest.cpp index c5cc451ef..f0670e68d 100644 --- a/src/Magnum/Math/Test/DualQuaternionTest.cpp +++ b/src/Magnum/Math/Test/DualQuaternionTest.cpp @@ -92,6 +92,9 @@ struct DualQuaternionTest: Corrade::TestSuite::Tester { void combinedTransformParts(); void matrix(); void matrixNotOrthogonal(); + void transformVector(); + void transformVectorNormalized(); + void transformVectorNormalizedNotNormalized(); void transformPoint(); void transformPointNormalized(); void transformPointNormalizedNotNormalized(); @@ -154,6 +157,9 @@ DualQuaternionTest::DualQuaternionTest() { &DualQuaternionTest::combinedTransformParts, &DualQuaternionTest::matrix, &DualQuaternionTest::matrixNotOrthogonal, + &DualQuaternionTest::transformVector, + &DualQuaternionTest::transformVectorNormalized, + &DualQuaternionTest::transformVectorNormalizedNotNormalized, &DualQuaternionTest::transformPoint, &DualQuaternionTest::transformPointNormalized, &DualQuaternionTest::transformPointNormalizedNotNormalized, @@ -493,6 +499,38 @@ void DualQuaternionTest::matrixNotOrthogonal() { " 0, 0, 0, 2)\n"); } +void DualQuaternionTest::transformVector() { + DualQuaternion a = DualQuaternion::rotation(23.0_degf, Vector3::xAxis()); + Quaternion q = Quaternion::rotation(23.0_degf, Vector3::xAxis()); + Vector3 v(5.0f, -3.6f, 0.7f); + + Vector3 rotated = a.transformVector(v); + /* Delegates to Quaternion, so should give the same result */ + CORRADE_COMPARE(rotated, q.transformVector(v)); + CORRADE_COMPARE(rotated, (Vector3{5.0f, -3.58733f, -0.762279f})); +} + +void DualQuaternionTest::transformVectorNormalized() { + DualQuaternion a = DualQuaternion::rotation(23.0_degf, Vector3::xAxis()); + Quaternion q = Quaternion::rotation(23.0_degf, Vector3::xAxis()); + Vector3 v(5.0f, -3.6f, 0.7f); + + Vector3 rotated = a.transformVectorNormalized(v); + /* Delegates to Quaternion, so should give the same result */ + CORRADE_COMPARE(rotated, q.transformVector(v)); + CORRADE_COMPARE(rotated, a.transformVector(v)); +} + +void DualQuaternionTest::transformVectorNormalizedNotNormalized() { + std::ostringstream out; + Error redirectError{&out}; + + Quaternion a = Quaternion::rotation(23.0_degf, Vector3::xAxis()); + (a*2).transformVectorNormalized({}); + /* Delegates to quaternion, so the assert prints Quaternion */ + CORRADE_COMPARE(out.str(), "Math::Quaternion::transformVectorNormalized(): Quaternion({0.398736, 0, 0}, 1.95985) is not normalized\n"); +} + void DualQuaternionTest::transformPoint() { DualQuaternion a = DualQuaternion::translation({-1.0f, 2.0f, 3.0f})*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis()); DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation({-1.0f, 2.0f, 3.0f}); diff --git a/src/Magnum/Math/Test/QuaternionTest.cpp b/src/Magnum/Math/Test/QuaternionTest.cpp index fc56beca4..1c2c2d4cc 100644 --- a/src/Magnum/Math/Test/QuaternionTest.cpp +++ b/src/Magnum/Math/Test/QuaternionTest.cpp @@ -744,6 +744,7 @@ void QuaternionTest::transformVectorNormalized() { Quaternion a = Quaternion::rotation(Deg(23.0f), Vector3::xAxis()); Matrix4 m = Matrix4::rotationX(Deg(23.0f)); Vector3 v(5.0f, -3.6f, 0.7f); + Vector3 rotated = a.transformVectorNormalized(v); CORRADE_COMPARE(rotated, m.transformVector(v)); CORRADE_COMPARE(rotated, a.transformVector(v));