diff --git a/src/Magnum/Math/DualComplex.h b/src/Magnum/Math/DualComplex.h index a35b2e58f..43fd16319 100644 --- a/src/Magnum/Math/DualComplex.h +++ b/src/Magnum/Math/DualComplex.h @@ -106,6 +106,22 @@ template class DualComplex: public Dual> { return {Implementation::complexFromMatrix(matrix.rotationScaling()), Complex(matrix.translation())}; } + /** + * @brief Create dual complext from rotation complex and translation vector + * + * @f[ + * \hat c = r + \epsilon (r(v_x + iv_y)) + * @f] + * + * @see @ref translation(), @ref rotation() + * @ref Matrix3::from(const Matrix2x2&, const Vector2&), + * @ref Matrix4::from(const Matrix3x3&, const Vector3&), + * @ref DualQuaternion::from(const Quaternion&, const Vector3&) + */ + static DualComplex from(const Complex& rotation, const Vector2& translation) { + return DualComplex::translation(translation)*DualComplex(rotation, {{}, {}}); + } + /** * @brief Default constructor * diff --git a/src/Magnum/Math/DualQuaternion.h b/src/Magnum/Math/DualQuaternion.h index b10212b09..a5fb4412a 100644 --- a/src/Magnum/Math/DualQuaternion.h +++ b/src/Magnum/Math/DualQuaternion.h @@ -246,6 +246,22 @@ template class DualQuaternion: public Dual> { return {q, Quaternion(matrix.translation()/2)*q}; } + /** + * @brief Create dual quaternion from rotation quaternion and translation vector + * + * @f[ + * \hat q = r + \epsilon (r[\frac{\boldsymbol t}{2}, 0]) + * @f] + * + * @see @ref translation(), @ref rotation(), + * @ref Matrix3::from(const Matrix2x2&, const Vector2&), + * @ref Matrix4::from(const Matrix3x3&, const Vector3&), + * @ref DualComplex::from(const Complex&, const Vector2&) + */ + static DualQuaternion from(const Quaternion& rotation, const Vector3& translation) { + return {rotation, Quaternion(translation/T(2))*rotation}; + } + /** * @brief Default constructor * diff --git a/src/Magnum/Math/Matrix3.h b/src/Magnum/Math/Matrix3.h index e299a4d7b..adaec6a7a 100644 --- a/src/Magnum/Math/Matrix3.h +++ b/src/Magnum/Math/Matrix3.h @@ -188,7 +188,10 @@ template class Matrix3: public Matrix3x3 { * @param translation Translation part (first two elements of * third column) * - * @see @ref rotationScaling(), @ref translation() const + * @see @ref rotationScaling(), @ref translation() const, + * @ref Matrix4::from(const Matrix3x3&, const Vector3&), + * @ref DualComplex::from(const Complex&, const Vector2&), + * @ref DualQuaternion::from(const Quaternion&, const Vector3&) */ constexpr static Matrix3 from(const Matrix2x2& rotationScaling, const Vector2& translation) { return {{rotationScaling[0], T(0)}, diff --git a/src/Magnum/Math/Matrix4.h b/src/Magnum/Math/Matrix4.h index ca3c5145e..81b7be0f3 100644 --- a/src/Magnum/Math/Matrix4.h +++ b/src/Magnum/Math/Matrix4.h @@ -421,7 +421,10 @@ template class Matrix4: public Matrix4x4 { * @param translation Translation part (first three elements of * fourth column) * - * @see @ref rotationScaling(), @ref translation() const + * @see @ref rotationScaling(), @ref translation() const, + * @ref Matrix3::from(const Matrix2x2&, const Vector2&), + * @ref DualComplex::from(const Complex&, const Vector2&), + * @ref DualQuaternion::from(const Quaternion&, const Vector3&) */ constexpr static Matrix4 from(const Matrix3x3& rotationScaling, const Vector3& translation) { return {{rotationScaling[0], T(0)}, diff --git a/src/Magnum/Math/Test/DualComplexTest.cpp b/src/Magnum/Math/Test/DualComplexTest.cpp index 669c66496..8b01e77d4 100644 --- a/src/Magnum/Math/Test/DualComplexTest.cpp +++ b/src/Magnum/Math/Test/DualComplexTest.cpp @@ -87,6 +87,7 @@ struct DualComplexTest: Corrade::TestSuite::Tester { void rotation(); void translation(); + void rotationTranslation(); void combinedTransformParts(); void matrix(); void matrixNotOrthogonal(); @@ -145,6 +146,7 @@ DualComplexTest::DualComplexTest() { &DualComplexTest::rotation, &DualComplexTest::translation, + &DualComplexTest::rotationTranslation, &DualComplexTest::combinedTransformParts, &DualComplexTest::matrix, &DualComplexTest::matrixNotOrthogonal, @@ -414,6 +416,17 @@ void DualComplexTest::translation() { CORRADE_COMPARE(a.translation(), vec); } +void DualComplexTest::rotationTranslation() { + const Complex r = Complex::rotation(120.0_degf); + + const Vector2 vec(1.0f, -3.5f); + const DualComplex t = DualComplex::translation(vec); + + const DualComplex rt = t*DualComplex{r}; + CORRADE_COMPARE(DualComplex::from(r, vec), rt); +} + + void DualComplexTest::combinedTransformParts() { Vector2 translation = Vector2(-1.5f, 2.75f); DualComplex a = DualComplex::translation(translation)*DualComplex::rotation(23.0_degf); diff --git a/src/Magnum/Math/Test/DualQuaternionTest.cpp b/src/Magnum/Math/Test/DualQuaternionTest.cpp index 20917423d..23e82a5fa 100644 --- a/src/Magnum/Math/Test/DualQuaternionTest.cpp +++ b/src/Magnum/Math/Test/DualQuaternionTest.cpp @@ -89,6 +89,7 @@ struct DualQuaternionTest: Corrade::TestSuite::Tester { void rotation(); void rotationNotNormalized(); void translation(); + void rotationTranslation(); void combinedTransformParts(); void matrix(); void matrixNotOrthogonal(); @@ -154,6 +155,7 @@ DualQuaternionTest::DualQuaternionTest() { &DualQuaternionTest::rotation, &DualQuaternionTest::rotationNotNormalized, &DualQuaternionTest::translation, + &DualQuaternionTest::rotationTranslation, &DualQuaternionTest::combinedTransformParts, &DualQuaternionTest::matrix, &DualQuaternionTest::matrixNotOrthogonal, @@ -469,6 +471,17 @@ void DualQuaternionTest::translation() { CORRADE_COMPARE(q.translation(), vec); } +void DualQuaternionTest::rotationTranslation() { + Vector3 axis(1.0f/Constants::sqrt3()); + Quaternion r = Quaternion::rotation(120.0_degf, axis); + + Vector3 vec(1.0f, -3.5f, 0.5f); + DualQuaternion t = DualQuaternion::translation(vec); + + DualQuaternion rt = t*DualQuaternion{r}; + CORRADE_COMPARE(DualQuaternion::from(r, vec), rt); +} + void DualQuaternionTest::combinedTransformParts() { Vector3 translation = Vector3(-1.0f, 2.0f, 3.0f); DualQuaternion a = DualQuaternion::translation(translation)*DualQuaternion::rotation(23.0_degf, Vector3::xAxis());