diff --git a/src/Math/DualQuaternion.h b/src/Math/DualQuaternion.h index 3076acd42..5ede6da05 100644 --- a/src/Math/DualQuaternion.h +++ b/src/Math/DualQuaternion.h @@ -239,11 +239,25 @@ template class DualQuaternion: public Dual> { return quaternionConjugated(); } + /** + * @brief Rotate and translate point with dual quaternion + * + * See rotateVectorNormalized(), which is faster for normalized dual + * quaternions. @f[ + * v' = qv \overline{\hat q^{-1}} = q ([\boldsymbol 0, 1] + \epsilon [\boldsymbol v, 0]) \overline{\hat q^{-1}} + * @f] + * @see DualQuaternion(const Vector3&), Matrix4::transformPoint(), Quaternion::rotateVectorNormalized() + */ + inline Vector3 transformPoint(const Vector3& vector) const { + return ((*this)*DualQuaternion(vector)*inverted().dualConjugated()).dual().vector(); + } + /** * @brief Rotate and translate point with normalized dual quaternion * - * Expects that the dual quaternion is normalized. @f[ - * v' = qv \overline{\hat q^*} = q ([\boldsymbol 0, 1] + \epsilon [\boldsymbol v, 0]) \overline{\hat q^*} + * Faster alternative to transformPoint(), expects that the dual + * quaternion is normalized. @f[ + * v' = qv \overline{\hat q^{-1}} = qv \overline{\hat q^*} = q ([\boldsymbol 0, 1] + \epsilon [\boldsymbol v, 0]) \overline{\hat q^*} * @f] * @see DualQuaternion(const Vector3&), Matrix4::transformPoint(), Quaternion::rotateVectorNormalized() */ diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index da1a0d9be..6fa43559b 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -367,7 +367,7 @@ template class Matrix4: public Matrix<4, T> { * Unlike in transformVector(), translation is also involved. @f[ * \boldsymbol v' = \boldsymbol M (v_x, v_y, v_z, 1)^T * @f] - * @see DualQuaternion::transformPointNormalized(), Matrix3::transformPoint() + * @see DualQuaternion::transformPoint(), Matrix3::transformPoint() */ inline Vector3 transformPoint(const Vector3& vector) const { return ((*this)*Vector4(vector, T(1))).xyz(); diff --git a/src/Math/Quaternion.h b/src/Math/Quaternion.h index 74572bc55..2b83b8d70 100644 --- a/src/Math/Quaternion.h +++ b/src/Math/Quaternion.h @@ -403,7 +403,7 @@ template class Quaternion { * quaternions. @f[ * v' = qvq^{-1} = q [\boldsymbol v, 0] q^{-1} * @f] - * @see Quaternion(const Vector3&), Matrix4::transformVector(), DualQuaternion::transformPointNormalized() + * @see Quaternion(const Vector3&), Matrix4::transformVector(), DualQuaternion::transformPoint() */ inline Vector3 rotateVector(const Vector3& vector) const { return ((*this)*Quaternion(vector)*inverted()).vector(); diff --git a/src/Math/Test/DualQuaternionTest.cpp b/src/Math/Test/DualQuaternionTest.cpp index bed18d4f4..bcc3aa50d 100644 --- a/src/Math/Test/DualQuaternionTest.cpp +++ b/src/Math/Test/DualQuaternionTest.cpp @@ -42,6 +42,7 @@ class DualQuaternionTest: public Corrade::TestSuite::Tester { void translation(); void combinedTransformParts(); void matrix(); + void transformPoint(); void transformPointNormalized(); void debug(); @@ -72,6 +73,7 @@ DualQuaternionTest::DualQuaternionTest() { &DualQuaternionTest::translation, &DualQuaternionTest::combinedTransformParts, &DualQuaternionTest::matrix, + &DualQuaternionTest::transformPoint, &DualQuaternionTest::transformPointNormalized, &DualQuaternionTest::debug); @@ -187,6 +189,22 @@ void DualQuaternionTest::matrix() { CORRADE_COMPARE((-q).matrix(), m); } +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}); + Matrix4 m = Matrix4::translation({-1.0f, 2.0f, 3.0f})*Matrix4::rotationX(deg(23.0f)); + Matrix4 n = Matrix4::rotationX(deg(23.0f))*Matrix4::translation({-1.0f, 2.0f, 3.0f}); + Vector3 v(0.0f, -3.6f, 0.7f); + + Vector3 transformedA = (a*Dual(2)).transformPoint(v); + CORRADE_COMPARE(transformedA, m.transformPoint(v)); + CORRADE_COMPARE(transformedA, Vector3(-1.0f, -1.58733f, 2.237721f)); + + Vector3 transformedB = (b*Dual(2)).transformPoint(v); + CORRADE_COMPARE(transformedB, n.transformPoint(v)); + CORRADE_COMPARE(transformedB, Vector3(-1.0f, -2.918512f, 2.780698f)); +} + void DualQuaternionTest::transformPointNormalized() { 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});