diff --git a/doc/transformations.dox b/doc/transformations.dox index a069e2fe8..138adb951 100644 --- a/doc/transformations.dox +++ b/doc/transformations.dox @@ -243,18 +243,18 @@ Matrix3 c = Matrix3::from(rotation, {1.0f, 3.0f}); @endcode %Complex numbers and quaternions are far better in this regard and they allow -you to extract rotation angle using Complex::rotationAngle(), Quaternion::rotationAngle(), -DualComplex::rotationAngle() or DualQuaternion::rotationAngle(), and rotation -axis in 3D using Quaternion::rotationAxis() or DualQuaternion::rotationAxis(). -It is also possible to extract translation from their dual versions using -DualComplex::translation() const and DualQuaternion::translation() const. +you to extract rotation angle using Complex::angle() or Quaternion::angle() or +rotation axis in 3D using Quaternion::axis(). Their dual versions allow to +extract both rotation and translation part using DualComplex::rotation() const, +DualQuaternion::rotation() const, DualComplex::translation() const and +DualQuaternion::translation() const. @code DualComplex a; -Rad rotation = a.rotationAngle(); +Rad rotationAngle = a.rotation().angle(); Vector2 translation = a.translation(); Quaternion b; -Vector3 rotationAxis = b.rotationAxis(); +Vector3 rotationAxis = b.axis(); @endcode You can convert Complex and Quaternion to rotation matrix using Complex::toMatrix() diff --git a/src/Math/Complex.h b/src/Math/Complex.h index 9b1d36ea3..766d577cb 100644 --- a/src/Math/Complex.h +++ b/src/Math/Complex.h @@ -90,7 +90,7 @@ template class Complex { * @f[ * c = cos \theta + i sin \theta * @f] - * @see rotationAngle(), Matrix3::rotation(), Quaternion::rotation() + * @see angle(), Matrix3::rotation(), Quaternion::rotation() */ inline static Complex rotation(Rad angle) { return {std::cos(T(angle)), std::sin(T(angle))}; @@ -182,9 +182,9 @@ template class Complex { * @f[ * \theta = atan2(b, a) * @f] - * @see rotation(), DualComplex::rotationAngle() + * @see rotation() */ - inline Rad rotationAngle() const { + inline Rad angle() const { return Rad(std::atan2(_imaginary, _real)); } diff --git a/src/Math/DualComplex.h b/src/Math/DualComplex.h index 6854c4f6a..1655ac529 100644 --- a/src/Math/DualComplex.h +++ b/src/Math/DualComplex.h @@ -55,7 +55,7 @@ template class DualComplex: public Dual> { * @f[ * \hat c = (cos \theta + i sin \theta) + \epsilon (0 + i0) * @f] - * @see rotationAngle(), Complex::rotation(), Matrix3::rotation(), + * @see angle(), Complex::rotation(), Matrix3::rotation(), * DualQuaternion::rotation() */ inline static DualComplex rotation(Rad angle) { @@ -139,15 +139,12 @@ template class DualComplex: public Dual> { } /** - * @brief Rotation angle of dual complex number + * @brief Rotation part of dual complex number * - * @f[ - * \theta = atan2(b_0, a_0) - * @f] - * @see rotation(), Complex::rotationAngle() + * @see Complex::angle() */ - inline Rad rotationAngle() const { - return this->real().rotationAngle(); + inline constexpr Complex rotation() const { + return this->real(); } /** diff --git a/src/Math/DualQuaternion.h b/src/Math/DualQuaternion.h index 29aefc127..6d6e86cf3 100644 --- a/src/Math/DualQuaternion.h +++ b/src/Math/DualQuaternion.h @@ -54,9 +54,9 @@ template class DualQuaternion: public Dual> { * Expects that the rotation axis is normalized. @f[ * \hat q = [\boldsymbol a \cdot sin \frac \theta 2, cos \frac \theta 2] + \epsilon [\boldsymbol 0, 0] * @f] - * @see rotationAngle(), rotationAxis(), Quaternion::rotation(), - * Matrix4::rotation(), DualComplex::rotation(), Vector3::xAxis(), - * Vector3::yAxis(), Vector3::zAxis(), Vector::isNormalized() + * @see rotation() const, Quaternion::rotation(), Matrix4::rotation(), + * DualComplex::rotation(), Vector3::xAxis(), Vector3::yAxis(), + * Vector3::zAxis(), Vector::isNormalized() */ inline static DualQuaternion rotation(Rad angle, const Vector3& normalizedAxis) { return {Quaternion::rotation(angle, normalizedAxis), {{}, T(0)}}; @@ -145,29 +145,12 @@ template class DualQuaternion: public Dual> { } /** - * @brief Rotation angle of unit dual quaternion + * @brief Rotation part of unit dual quaternion * - * Expects that the real part of the quaternion is normalized. @f[ - * \theta = 2 \cdot acos q_{S 0} - * @f] - * @see rotationAxis(), rotation(), Quaternion::rotationAngle() - */ - inline Math::Rad rotationAngle() const { - return this->real().rotationAngle(); - } - - /** - * @brief Rotation axis of unit dual quaternion - * - * Expects that the quaternion is normalized. Returns either unit-length - * vector for valid rotation quaternion or NaN vector for - * default-constructed quaternion. @f[ - * \boldsymbol a = \frac{\boldsymbol q_{V 0}}{\sqrt{1 - q_{S 0}^2}} - * @f] - * @see rotationAngle(), rotation(), Quaternion::rotationAxis() + * @see Quaternion::angle(), Quaternion::axis() */ - inline Vector3 rotationAxis() const { - return this->real().rotationAxis(); + inline constexpr Quaternion rotation() const { + return this->real(); } /** diff --git a/src/Math/Quaternion.h b/src/Math/Quaternion.h index 2d373eae1..0e3f77503 100644 --- a/src/Math/Quaternion.h +++ b/src/Math/Quaternion.h @@ -162,7 +162,7 @@ template class Quaternion { * Expects that the rotation axis is normalized. @f[ * q = [\boldsymbol a \cdot sin \frac \theta 2, cos \frac \theta 2] * @f] - * @see rotationAngle(), rotationAxis(), DualQuaternion::rotation(), + * @see angle(), axis(), DualQuaternion::rotation(), * Matrix4::rotation(), Complex::rotation(), Vector3::xAxis(), * Vector3::yAxis(), Vector3::zAxis(), Vector::isNormalized() */ @@ -247,12 +247,11 @@ template class Quaternion { * Expects that the quaternion is normalized. @f[ * \theta = 2 \cdot acos q_S * @f] - * @see isNormalized(), rotationAxis(), rotation(), - * DualQuaternion::rotationAngle() + * @see isNormalized(), axis(), rotation() */ - inline Rad rotationAngle() const { + inline Rad angle() const { CORRADE_ASSERT(isNormalized(), - "Math::Quaternion::rotationAngle(): quaternion must be normalized", + "Math::Quaternion::angle(): quaternion must be normalized", Rad(std::numeric_limits::quiet_NaN())); return Rad(T(2)*std::acos(_scalar)); } @@ -265,11 +264,11 @@ template class Quaternion { * default-constructed quaternion. @f[ * \boldsymbol a = \frac{\boldsymbol q_V}{\sqrt{1 - q_S^2}} * @f] - * @see isNormalized(), rotationAngle(), rotation() + * @see isNormalized(), angle(), rotation() */ - inline Vector3 rotationAxis() const { + inline Vector3 axis() const { CORRADE_ASSERT(isNormalized(), - "Math::Quaternion::rotationAxis(): quaternion must be normalized", + "Math::Quaternion::axis(): quaternion must be normalized", {}); return _vector/std::sqrt(1-pow2(_scalar)); } diff --git a/src/Math/Test/ComplexTest.cpp b/src/Math/Test/ComplexTest.cpp index 931a66ead..ae5b2a6e4 100644 --- a/src/Math/Test/ComplexTest.cpp +++ b/src/Math/Test/ComplexTest.cpp @@ -273,15 +273,15 @@ void ComplexTest::rotation() { Complex a = Complex::rotation(Deg(120.0f)); CORRADE_COMPARE(a.length(), 1.0f); CORRADE_COMPARE(a, Complex(-0.5f, 0.8660254f)); - CORRADE_COMPARE_AS(a.rotationAngle(), Deg(120.0f), Rad); + CORRADE_COMPARE_AS(a.angle(), Deg(120.0f), Rad); /* Verify negative angle */ Complex b = Complex::rotation(Deg(-240.0f)); CORRADE_COMPARE(b, Complex(-0.5f, 0.8660254f)); - CORRADE_COMPARE_AS(b.rotationAngle(), Deg(120.0f), Rad); + CORRADE_COMPARE_AS(b.angle(), Deg(120.0f), Rad); /* Default-constructed complex number has zero angle */ - CORRADE_COMPARE_AS(Complex().rotationAngle(), Deg(0.0f), Rad); + CORRADE_COMPARE_AS(Complex().angle(), Deg(0.0f), Rad); } void ComplexTest::matrix() { diff --git a/src/Math/Test/DualComplexTest.cpp b/src/Math/Test/DualComplexTest.cpp index 9d8db2094..6ea187159 100644 --- a/src/Math/Test/DualComplexTest.cpp +++ b/src/Math/Test/DualComplexTest.cpp @@ -207,7 +207,12 @@ void DualComplexTest::rotation() { DualComplex a = DualComplex::rotation(Deg(120.0f)); CORRADE_COMPARE(a.length(), 1.0f); CORRADE_COMPARE(a, DualComplex({-0.5f, 0.8660254f}, {0.0f, 0.0f})); - CORRADE_COMPARE_AS(a.rotationAngle(), Deg(120.0f), Rad); + CORRADE_COMPARE_AS(a.rotation().angle(), Deg(120.0f), Rad); + + /* Constexpr access to rotation */ + constexpr DualComplex b({-1.0f, 2.0f}, {}); + constexpr Complex c = b.rotation(); + CORRADE_COMPARE(c, Complex(-1.0f, 2.0f)); } void DualComplexTest::translation() { @@ -223,8 +228,8 @@ void DualComplexTest::combinedTransformParts() { DualComplex a = DualComplex::translation(translation)*DualComplex::rotation(Deg(23.0f)); DualComplex b = DualComplex::rotation(Deg(23.0f))*DualComplex::translation(translation); - CORRADE_COMPARE_AS(a.rotationAngle(), Deg(23.0f), Rad); - CORRADE_COMPARE_AS(b.rotationAngle(), Deg(23.0f), Rad); + CORRADE_COMPARE_AS(a.rotation().angle(), Deg(23.0f), Rad); + CORRADE_COMPARE_AS(b.rotation().angle(), Deg(23.0f), Rad); CORRADE_COMPARE(a.translation(), translation); CORRADE_COMPARE(b.translation(), Complex::rotation(Deg(23.0f)).transformVector(translation)); } diff --git a/src/Math/Test/DualQuaternionTest.cpp b/src/Math/Test/DualQuaternionTest.cpp index d8594fcfb..db6809b26 100644 --- a/src/Math/Test/DualQuaternionTest.cpp +++ b/src/Math/Test/DualQuaternionTest.cpp @@ -210,8 +210,13 @@ void DualQuaternionTest::rotation() { DualQuaternion q = DualQuaternion::rotation(Deg(120.0f), axis); CORRADE_COMPARE(q.length(), 1.0f); CORRADE_COMPARE(q, DualQuaternion({Vector3(0.5f, 0.5f, 0.5f), 0.5f}, {{}, 0.0f})); - CORRADE_COMPARE_AS(q.rotationAngle(), Deg(120.0f), Deg); - CORRADE_COMPARE(q.rotationAxis(), axis); + CORRADE_COMPARE_AS(q.rotation().angle(), Deg(120.0f), Deg); + CORRADE_COMPARE(q.rotation().axis(), axis); + + /* Constexpr access to rotation */ + constexpr DualQuaternion b({{-1.0f, 2.0f, 3.0f}, 4.0f}, {}); + constexpr Quaternion c = b.rotation(); + CORRADE_COMPARE(c, Quaternion({-1.0f, 2.0f, 3.0f}, 4.0f)); } void DualQuaternionTest::translation() { @@ -227,10 +232,10 @@ void DualQuaternionTest::combinedTransformParts() { DualQuaternion a = DualQuaternion::translation(translation)*DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis()); DualQuaternion b = DualQuaternion::rotation(Deg(23.0f), Vector3::xAxis())*DualQuaternion::translation(translation); - CORRADE_COMPARE(a.rotationAxis(), Vector3::xAxis()); - CORRADE_COMPARE(b.rotationAxis(), Vector3::xAxis()); - CORRADE_COMPARE_AS(a.rotationAngle(), Deg(23.0f), Rad); - CORRADE_COMPARE_AS(b.rotationAngle(), Deg(23.0f), Rad); + CORRADE_COMPARE(a.rotation().axis(), Vector3::xAxis()); + CORRADE_COMPARE(b.rotation().axis(), Vector3::xAxis()); + CORRADE_COMPARE_AS(a.rotation().angle(), Deg(23.0f), Rad); + CORRADE_COMPARE_AS(b.rotation().angle(), Deg(23.0f), Rad); CORRADE_COMPARE(a.translation(), translation); CORRADE_COMPARE(b.translation(), Quaternion::rotation(Deg(23.0f), Vector3::xAxis()).transformVector(translation)); diff --git a/src/Math/Test/QuaternionTest.cpp b/src/Math/Test/QuaternionTest.cpp index 18b635da5..4ffefcdd2 100644 --- a/src/Math/Test/QuaternionTest.cpp +++ b/src/Math/Test/QuaternionTest.cpp @@ -255,19 +255,19 @@ void QuaternionTest::rotation() { Quaternion q = Quaternion::rotation(Deg(120.0f), axis); CORRADE_COMPARE(q.length(), 1.0f); CORRADE_COMPARE(q, Quaternion(Vector3(0.5f, 0.5f, 0.5f), 0.5f)); - CORRADE_COMPARE_AS(q.rotationAngle(), Deg(120.0f), Deg); - CORRADE_COMPARE(q.rotationAxis(), axis); - CORRADE_COMPARE(q.rotationAxis().length(), 1.0f); + CORRADE_COMPARE_AS(q.angle(), Deg(120.0f), Deg); + CORRADE_COMPARE(q.axis(), axis); + CORRADE_COMPARE(q.axis().length(), 1.0f); /* Verify negative angle */ Quaternion q2 = Quaternion::rotation(Deg(-120.0f), axis); CORRADE_COMPARE(q2, Quaternion(Vector3(-0.5f, -0.5f, -0.5f), 0.5f)); - CORRADE_COMPARE_AS(q2.rotationAngle(), Deg(120.0f), Deg); - CORRADE_COMPARE(q2.rotationAxis(), -axis); + CORRADE_COMPARE_AS(q2.angle(), Deg(120.0f), Deg); + CORRADE_COMPARE(q2.axis(), -axis); /* Default-constructed quaternion has zero angle and NaN axis */ - CORRADE_COMPARE_AS(Quaternion().rotationAngle(), Deg(0.0f), Deg); - CORRADE_VERIFY(Quaternion().rotationAxis() != Quaternion().rotationAxis()); + CORRADE_COMPARE_AS(Quaternion().angle(), Deg(0.0f), Deg); + CORRADE_VERIFY(Quaternion().axis() != Quaternion().axis()); } void QuaternionTest::angle() {