diff --git a/src/Math/Complex.h b/src/Math/Complex.h index 1950a85c8..36f559263 100644 --- a/src/Math/Complex.h +++ b/src/Math/Complex.h @@ -340,6 +340,35 @@ template class Complex { return conjugated(); } + /** + * @brief Rotate vector with complex number + * + * See transformVectorNormalized(), which is faster for normalized + * complex numbers. @f[ + * v' = \frac c {|c|} v = \frac c {|c|} (v_x + iv_y) + * @f] + * @see Complex(const Vector2&), operator Vector2(), Matrix3::transformVector() + */ + inline Vector2 transformVector(const Vector2& vector) const { + return Vector2(normalized()*Complex(vector)); + } + + /** + * @brief Rotate vector with normalized complex number + * + * Faster alternative to transformVector(), expects that the complex + * number is normalized. @f[ + * v' = \frac c {|c|} v = cv = c(v_x + iv_y) + * @f] + * @see Complex(const Vector2&), operator Vector2(), Matrix3::transformVector() + */ + inline Vector2 transformVectorNormalized(const Vector2& vector) const { + CORRADE_ASSERT(MathTypeTraits::equals(dot(), T(1)), + "Math::Complex::transformVectorNormalized(): complex number must be normalized", + Vector2(std::numeric_limits::quiet_NaN())); + return Vector2((*this)*Complex(vector)); + } + private: T _real, _imaginary; }; diff --git a/src/Math/DualQuaternion.h b/src/Math/DualQuaternion.h index 35d67565c..543383718 100644 --- a/src/Math/DualQuaternion.h +++ b/src/Math/DualQuaternion.h @@ -251,7 +251,8 @@ template class DualQuaternion: public 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::transformVector() + * @see DualQuaternion(const Vector3&), dual(), Matrix4::transformPoint(), + * Quaternion::transformVector() */ inline Vector3 transformPoint(const Vector3& vector) const { return ((*this)*DualQuaternion(vector)*inverted().dualConjugated()).dual().vector(); @@ -264,7 +265,8 @@ template class DualQuaternion: public 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::transformVectorNormalized() + * @see DualQuaternion(const Vector3&), dual(), Matrix4::transformPoint(), + * Quaternion::transformVectorNormalized() */ inline Vector3 transformPointNormalized(const Vector3& vector) const { CORRADE_ASSERT(MathTypeTraits>::equals(lengthSquared(), Dual(1)), diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 87be55128..f9b1b09b5 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -212,10 +212,11 @@ template class Matrix3: public Matrix<3, T> { /** * @brief Transform 2D vector with the matrix * - * Translation is not involved in the transformation. @f[ + * Unlike in transformPoint(), translation is not involved in the + * transformation. @f[ * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ 0 \end{pmatrix} * @f] - * @see transformPoint(), Matrix4::transformVector() + * @see Complex::transformVector(), Matrix4::transformVector() */ inline Vector2 transformVector(const Vector2& vector) const { return ((*this)*Vector3(vector, T(0))).xy(); @@ -224,7 +225,8 @@ template class Matrix3: public Matrix<3, T> { /** * @brief Transform 2D point with the matrix * - * Unlike in transformVector(), translation is also involved. @f[ + * Unlike in transformVector(), translation is also involved in the + * transformation. @f[ * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ 1 \end{pmatrix} * @f] * @see Matrix4::transformPoint() diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index b77f5bbf6..198aa8c65 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -359,11 +359,11 @@ template class Matrix4: public Matrix<4, T> { /** * @brief Transform 3D vector with the matrix * - * Translation is not involved in the transformation. @f[ + * Unlike in transformVector(), translation is not involved in the + * transformation. @f[ * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ v_z \\ 0 \end{pmatrix} * @f] - * @see transformPoint(), Quaternion::transformVector(), - * Matrix3::transformVector() + * @see Quaternion::transformVector(), Matrix3::transformVector() */ inline Vector3 transformVector(const Vector3& vector) const { return ((*this)*Vector4(vector, T(0))).xyz(); @@ -372,7 +372,8 @@ template class Matrix4: public Matrix<4, T> { /** * @brief Transform 3D point with the matrix * - * Unlike in transformVector(), translation is also involved. @f[ + * Unlike in transformVector(), translation is also involved in the + * transformation. @f[ * \boldsymbol v' = \boldsymbol M \begin{pmatrix} v_x \\ v_y \\ v_z \\ 1 \end{pmatrix} * @f] * @see DualQuaternion::transformPoint(), Matrix3::transformPoint() diff --git a/src/Math/Quaternion.h b/src/Math/Quaternion.h index 6ce8ae078..a7c04bb22 100644 --- a/src/Math/Quaternion.h +++ b/src/Math/Quaternion.h @@ -408,7 +408,8 @@ template class Quaternion { * quaternions. @f[ * v' = qvq^{-1} = q [\boldsymbol v, 0] q^{-1} * @f] - * @see Quaternion(const Vector3&), Matrix4::transformVector(), DualQuaternion::transformPoint() + * @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(), + * DualQuaternion::transformPoint(), Complex::transformVector() */ inline Vector3 transformVector(const Vector3& vector) const { return ((*this)*Quaternion(vector)*inverted()).vector(); @@ -417,11 +418,13 @@ template class Quaternion { /** * @brief Rotate vector with normalized quaternion * - * Faster alternative to transformVector(), expects that the quaternion is - * normalized. @f[ + * Faster alternative to transformVector(), expects that the quaternion + * is normalized. @f[ * v' = qvq^{-1} = qvq^* = q [\boldsymbol v, 0] q^* * @f] - * @see Quaternion(const Vector3&), Matrix4::transformVector(), DualQuaternion::transformPointNormalized() + * @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(), + * DualQuaternion::transformPointNormalized(), + * Complex::transformVectorNormalized() */ inline Vector3 transformVectorNormalized(const Vector3& vector) const { CORRADE_ASSERT(MathTypeTraits::equals(dot(), T(1)), diff --git a/src/Math/Test/ComplexTest.cpp b/src/Math/Test/ComplexTest.cpp index 697b4a376..a93db8ccf 100644 --- a/src/Math/Test/ComplexTest.cpp +++ b/src/Math/Test/ComplexTest.cpp @@ -49,6 +49,8 @@ class ComplexTest: public Corrade::TestSuite::Tester { void angle(); void rotation(); void matrix(); + void transformVector(); + void transformVectorNormalized(); void debug(); }; @@ -78,6 +80,8 @@ ComplexTest::ComplexTest() { &ComplexTest::angle, &ComplexTest::rotation, &ComplexTest::matrix, + &ComplexTest::transformVector, + &ComplexTest::transformVectorNormalized, &ComplexTest::debug); } @@ -266,6 +270,32 @@ void ComplexTest::matrix() { CORRADE_COMPARE(a.matrix(), m); } +void ComplexTest::transformVector() { + Complex a = Complex::rotation(Deg(23.0f)); + Matrix3 m = Matrix3::rotation(Deg(23.0f)); + Vector2 v(-3.6f, 0.7f); + + Vector2 rotated = a.transformVector(v); + CORRADE_COMPARE(rotated, m.transformVector(v)); + CORRADE_COMPARE(rotated, Vector2(-3.58733f, -0.762279f)); +} + +void ComplexTest::transformVectorNormalized() { + Complex a = Complex::rotation(Deg(23.0f)); + Matrix3 m = Matrix3::rotation(Deg(23.0f)); + Vector2 v(-3.6f, 0.7f); + + std::ostringstream o; + Error::setOutput(&o); + Vector2 notRotated = (a*2).transformVectorNormalized(v); + CORRADE_VERIFY(notRotated != notRotated); + CORRADE_COMPARE(o.str(), "Math::Complex::transformVectorNormalized(): complex number must be normalized\n"); + + Vector2 rotated = a.transformVectorNormalized(v); + CORRADE_COMPARE(rotated, m.transformVector(v)); + CORRADE_COMPARE(rotated, a.transformVector(v)); +} + void ComplexTest::debug() { std::ostringstream o; diff --git a/src/Math/Test/QuaternionTest.cpp b/src/Math/Test/QuaternionTest.cpp index 3b6ad4955..da7b16ed8 100644 --- a/src/Math/Test/QuaternionTest.cpp +++ b/src/Math/Test/QuaternionTest.cpp @@ -340,7 +340,7 @@ void QuaternionTest::transformVectorNormalized() { Vector3 v(5.0f, -3.6f, 0.7f); std::ostringstream o; - Corrade::Utility::Error::setOutput(&o); + Error::setOutput(&o); Vector3 notRotated = (a*2).transformVectorNormalized(v); CORRADE_VERIFY(notRotated != notRotated); CORRADE_COMPARE(o.str(), "Math::Quaternion::transformVectorNormalized(): quaternion must be normalized\n");