diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index d977a79c1..ab88b85c4 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -164,7 +164,7 @@ template class Matrix3: public Matrix<3, T> { * * Upper-left 2x2 part of the matrix. * @see from(const Matrix<2, T>&, const Vector2&), rotation() const - * rotationNormalized(), rotation(T), + * rotationNormalized(), @ref uniformScaling(), rotation(T), * Matrix4::rotationScaling() const */ constexpr Matrix<2, T> rotationScaling() const { @@ -177,7 +177,8 @@ template class Matrix3: public Matrix<3, T> { * * Similar to @ref rotationScaling(), but additionally checks that the * base vectors are normalized. - * @see rotation() const, @ref Matrix4::rotationNormalized() + * @see rotation() const, @ref uniformScaling(), + * @ref Matrix4::rotationNormalized() * @todo assert also orthogonality or this is good enough? */ Matrix<2, T> rotationNormalized() const { @@ -191,8 +192,8 @@ template class Matrix3: public Matrix<3, T> { * @brief 2D rotation part of the matrix * * Normalized upper-left 2x2 part of the matrix. - * @see rotationNormalized(), rotationScaling() const, rotation(T), - * Matrix4::rotation() const + * @see rotationNormalized(), rotationScaling(), @ref uniformScaling(), + * rotation(T), Matrix4::rotation() const * @todo assert uniform scaling (otherwise this would be garbage) */ Matrix<2, T> rotation() const { @@ -200,7 +201,21 @@ template class Matrix3: public Matrix<3, T> { (*this)[1].xy().normalized()}; } - /** @todo uniform scaling extraction */ + /** + * @brief Uniform scaling part of the matrix + * + * Length of vectors in upper-left 2x2 part of the matrix. Expects that + * the scaling is the same in all axes. + * @see @ref rotationScaling(), @ref rotation(), + * @ref rotationNormalized(), @ref scaling(const Vector2&), + * @ref Matrix4::uniformScaling() + */ + T uniformScaling() const { + const T scalingSquared = (*this)[0].xy().dot(); + CORRADE_ASSERT(TypeTraits::equals((*this)[1].xy().dot(), scalingSquared), + "Math::Matrix3::uniformScaling(): the matrix doesn't have uniform scaling", {}); + return std::sqrt(scalingSquared); + } /** * @brief Right-pointing 2D vector diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index dec15dbfc..a082f3bbd 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -227,8 +227,8 @@ template class Matrix4: public Matrix<4, T> { * * Upper-left 3x3 part of the matrix. * @see from(const Matrix<3, T>&, const Vector3&), rotation() const, - * rotationNormalized(), rotation(T, const Vector3&), - * Matrix3::rotationScaling() const + * rotationNormalized(), @ref uniformScaling(), + * rotation(T, const Vector3&), Matrix3::rotationScaling() const */ /* Not Matrix3, because it is for affine 2D transformations */ constexpr Matrix<3, T> rotationScaling() const { @@ -242,7 +242,8 @@ template class Matrix4: public Matrix<4, T> { * * Similar to @ref rotationScaling(), but additionally checks that the * base vectors are normalized. - * @see rotation() const, @ref Matrix3::rotationNormalized() + * @see rotation() const, @ref uniformScaling(), + * @ref Matrix3::rotationNormalized() * @todo assert also orthogonality or this is good enough? */ /* Not Matrix3, because it is for affine 2D transformations */ @@ -259,13 +260,23 @@ template class Matrix4: public Matrix<4, T> { * * Normalized upper-left 3x3 part of the matrix. * @see rotationNormalized(), rotationScaling() const, - * rotation(T, const Vector3&), Matrix3::rotation() const + * @ref uniformScaling(), rotation(T, const Vector3&), + * Matrix3::rotation() const * @todo assert uniform scaling (otherwise this would be garbage) */ /* Not Matrix3, because it is for affine 2D transformations */ Matrix<3, T> rotation() const; - /** @todo uniform scaling extraction */ + /** + * @brief Uniform scaling part of the matrix + * + * Length of vectors in upper-left 3x3 part of the matrix. Expects that + * the scaling is the same in all axes. + * @see @ref rotationScaling(), @ref rotation(), + * @ref rotationNormalized(), @ref scaling(const Vector3&), + * @ref Matrix3::uniformScaling() + */ + T uniformScaling() const; /** * @brief Right-pointing 3D vector @@ -446,6 +457,14 @@ template inline Matrix<3, T> Matrix4::rotation() const { (*this)[2].xyz().normalized()}; } +template T Matrix4::uniformScaling() const { + const T scalingSquared = (*this)[0].xyz().dot(); + CORRADE_ASSERT(TypeTraits::equals((*this)[1].xyz().dot(), scalingSquared) && + TypeTraits::equals((*this)[2].xyz().dot(), scalingSquared), + "Math::Matrix4::uniformScaling(): the matrix doesn't have uniform scaling", {}); + return std::sqrt(scalingSquared); +} + template Matrix4 Matrix4::invertedRigid() const { CORRADE_ASSERT(isRigidTransformation(), "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {}); diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index efadb60af..c55425112 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -78,6 +78,7 @@ class Matrix3Test: public Corrade::TestSuite::Tester { void rotationScalingPart(); void rotationNormalizedPart(); void rotationPart(); + void uniformScalingPart(); void vectorParts(); void invertedRigid(); void transform(); @@ -113,6 +114,7 @@ Matrix3Test::Matrix3Test() { &Matrix3Test::rotationScalingPart, &Matrix3Test::rotationNormalizedPart, &Matrix3Test::rotationPart, + &Matrix3Test::uniformScalingPart, &Matrix3Test::vectorParts, &Matrix3Test::invertedRigid, &Matrix3Test::transform, @@ -334,6 +336,20 @@ void Matrix3Test::rotationPart() { } } +void Matrix3Test::uniformScalingPart() { + const Matrix3 rotation = Matrix3::rotation(Deg(-74.0f)); + + /* Test uniform scaling */ + CORRADE_COMPARE((rotation*Matrix3::scaling(Vector2(3.0f))).uniformScaling(), 3.0f); + + /* Fails on non-uniform scaling */ + std::ostringstream o; + Error::setOutput(&o); + const Float nonUniformScaling = (rotation*Matrix3::scaling(Vector2::yScale(3.0f))).uniformScaling(); + CORRADE_COMPARE(o.str(), "Math::Matrix3::uniformScaling(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(nonUniformScaling, 0.0f); +} + void Matrix3Test::vectorParts() { constexpr Matrix3 a({15.0f, 0.0f, 0.0f}, { 0.0f, -3.0f, 0.0f}, diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index 31659580a..fb84fc54e 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -85,6 +85,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester { void rotationScalingPart(); void rotationNormalizedPart(); void rotationPart(); + void uniformScalingPart(); void vectorParts(); void invertedRigid(); void transform(); @@ -125,6 +126,7 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::rotationScalingPart, &Matrix4Test::rotationNormalizedPart, &Matrix4Test::rotationPart, + &Matrix4Test::uniformScalingPart, &Matrix4Test::vectorParts, &Matrix4Test::invertedRigid, &Matrix4Test::transform, @@ -420,6 +422,20 @@ void Matrix4Test::rotationPart() { } } +void Matrix4Test::uniformScalingPart() { + const Matrix4 rotation = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()); + + /* Test uniform scaling */ + CORRADE_COMPARE((rotation*Matrix4::scaling(Vector3(3.0f))).uniformScaling(), 3.0f); + + /* Fails on non-uniform scaling */ + std::ostringstream o; + Error::setOutput(&o); + const Float nonUniformScaling = (rotation*Matrix4::scaling(Vector3::yScale(3.0f))).uniformScaling(); + CORRADE_COMPARE(o.str(), "Math::Matrix4::uniformScaling(): the matrix doesn't have uniform scaling\n"); + CORRADE_COMPARE(nonUniformScaling, 0.0f); +} + void Matrix4Test::vectorParts() { constexpr Matrix4 a({-1.0f, 0.0f, 0.0f, 0.0f}, { 0.0f, 12.0f, 0.0f, 0.0f},