Browse Source

Math: Matrix::invertedOrthogonal(), Matrix{3,4}::invertedRigid().

Renamed original invertedEuclidean() functions to invertedRigid() and
simplified them using isRigidTransformation().
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
33058aa5b0
  1. 6
      doc/transformations.dox
  2. 23
      src/Math/Matrix.h
  3. 18
      src/Math/Matrix3.h
  4. 18
      src/Math/Matrix4.h
  5. 1
      src/Math/Test/CMakeLists.txt
  6. 28
      src/Math/Test/Matrix3Test.cpp
  7. 29
      src/Math/Test/Matrix4Test.cpp
  8. 17
      src/Math/Test/MatrixTest.cpp
  9. 2
      src/SceneGraph/EuclideanMatrixTransformation2D.h
  10. 2
      src/SceneGraph/EuclideanMatrixTransformation3D.h

6
doc/transformations.dox

@ -188,9 +188,9 @@ Inverse transformation can be computed using Matrix3::inverted(), Matrix4::inver
Complex::inverted(), Quaternion::inverted(), DualComplex::inverted() or Complex::inverted(), Quaternion::inverted(), DualComplex::inverted() or
DualQuaternion::inverted(). %Matrix inversion is quite costly, so if your DualQuaternion::inverted(). %Matrix inversion is quite costly, so if your
transformation involves only translation and rotation, you can use faster transformation involves only translation and rotation, you can use faster
alternatives Matrix3::invertedEuclidean() and Matrix4::invertedEuclidean(). If alternatives Matrix3::invertedRigid() and Matrix4::invertedRigid(). If you are
you are sure that the (dual) complex number or (dual) quaternion is of unit sure that the (dual) complex number or (dual) quaternion is of unit length, you
length, you can use Complex::invertedNormalized(), Quaternion::invertedNormalized(), can use Complex::invertedNormalized(), Quaternion::invertedNormalized(),
DualComplex::invertedNormalized() or DualQuaternion::invertedNormalized() which DualComplex::invertedNormalized() or DualQuaternion::invertedNormalized() which
is a little bit faster, because it doesn't need to renormalize the result. is a little bit faster, because it doesn't need to renormalize the result.

23
src/Math/Matrix.h

@ -168,8 +168,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* Computed using Cramer's rule: @f[ * Computed using Cramer's rule: @f[
* A^{-1} = \frac{1}{\det(A)} Adj(A) * A^{-1} = \frac{1}{\det(A)} Adj(A)
* @f] * @f]
* * See invertedOrthogonal(), Matrix3::invertedRigid() and Matrix4::invertedRigid()
* See Matrix3::invertedEuclidean() and Matrix4::invertedEuclidean()
* which are faster alternatives for particular matrix types. * which are faster alternatives for particular matrix types.
*/ */
Matrix<size, T> inverted() const { Matrix<size, T> inverted() const {
@ -184,6 +183,21 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
return out; return out;
} }
/**
* @brief Inverted orthogonal matrix
*
* Equivalent to transposed(), expects that the matrix is orthogonal. @f[
* A^{-1} = A^T
* @f]
* @see inverted(), isOrthogonal(), Matrix3::invertedRigid(),
* Matrix4::invertedRigid()
*/
inline Matrix<size, T> invertedOrthogonal() const {
CORRADE_ASSERT(isOrthogonal(),
"Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {});
return this->transposed();
}
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
/* Reimplementation of functions to return correct type */ /* Reimplementation of functions to return correct type */
inline Matrix<size, T> operator*(const Matrix<size, T>& other) const { inline Matrix<size, T> operator*(const Matrix<size, T>& other) const {
@ -239,7 +253,10 @@ template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Co
} \ } \
\ \
inline Type<T> transposed() const { return Matrix<size, T>::transposed(); } \ inline Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
inline Type<T> inverted() const { return Matrix<size, T>::inverted(); } inline Type<T> inverted() const { return Matrix<size, T>::inverted(); } \
inline Type<T> invertedOrthogonal() const { \
return Matrix<size, T>::invertedOrthogonal(); \
}
#define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ #define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number, const Type<T>& matrix) { \ template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number, const Type<T>& matrix) { \

18
src/Math/Matrix3.h

@ -218,20 +218,18 @@ template<class T> class Matrix3: public Matrix<3, T> {
inline constexpr Vector2<T> translation() const { return (*this)[2].xy(); } /**< @overload */ inline constexpr Vector2<T> translation() const { return (*this)[2].xy(); } /**< @overload */
/** /**
* @brief Inverted Euclidean transformation matrix * @brief Inverted rigid transformation matrix
* *
* Assumes that the matrix represents Euclidean transformation (i.e. * Expects that the matrix represents rigid transformation.
* only rotation and translation, no scaling) and creates inverted
* matrix from transposed rotation part and negated translation part.
* Significantly faster than the general algorithm in inverted(). * Significantly faster than the general algorithm in inverted().
* @see rotationScaling() const, translation() const * @see isRigidTransformation(), invertedOrthogonal(),
* rotationScaling() const, translation() const
*/ */
inline Matrix3<T> invertedEuclidean() const { inline Matrix3<T> invertedRigid() const {
CORRADE_ASSERT((*this)[0][2] == T(0) && (*this)[1][2] == T(0) && (*this)[2][2] == T(1), CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix3::invertedEuclidean(): unexpected values on last row", {}); "Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation", {});
Matrix<2, T> inverseRotation = rotationScaling().transposed(); Matrix<2, T> inverseRotation = rotationScaling().transposed();
CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<2, T>()),
"Math::Matrix3::invertedEuclidean(): the matrix doesn't represent Euclidean transformation", {});
return from(inverseRotation, inverseRotation*-translation()); return from(inverseRotation, inverseRotation*-translation());
} }

18
src/Math/Matrix4.h

@ -363,20 +363,18 @@ template<class T> class Matrix4: public Matrix<4, T> {
inline constexpr Vector3<T> translation() const { return (*this)[3].xyz(); } /**< @overload */ inline constexpr Vector3<T> translation() const { return (*this)[3].xyz(); } /**< @overload */
/** /**
* @brief Inverted Euclidean transformation matrix * @brief Inverted rigid transformation matrix
* *
* Expects that the matrix represents Euclidean transformation (i.e. * Expects that the matrix represents rigid transformation.
* only rotation and translation, no scaling) and creates inverted
* matrix from transposed rotation part and negated translation part.
* Significantly faster than the general algorithm in inverted(). * Significantly faster than the general algorithm in inverted().
* @see rotationScaling() const, translation() const * @see isRigidTransformation(), invertedOrthogonal(),
* rotationScaling() const, translation() const
*/ */
inline Matrix4<T> invertedEuclidean() const { inline Matrix4<T> invertedRigid() const {
CORRADE_ASSERT((*this)[0][3] == T(0) && (*this)[1][3] == T(0) && (*this)[2][3] == T(0) && (*this)[3][3] == T(1), CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix4::invertedEuclidean(): unexpected values on last row", {}); "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {});
Matrix<3, T> inverseRotation = rotationScaling().transposed(); Matrix<3, T> inverseRotation = rotationScaling().transposed();
CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<3, T>()),
"Math::Matrix4::invertedEuclidean(): the matrix doesn't represent Euclidean transformation", {});
return from(inverseRotation, inverseRotation*-translation()); return from(inverseRotation, inverseRotation*-translation());
} }

1
src/Math/Test/CMakeLists.txt

@ -49,6 +49,7 @@ corrade_add_test(MathDualQuaternionTest DualQuaternionTest.cpp LIBRARIES MagnumM
set_target_properties( set_target_properties(
MathVectorTest MathVectorTest
MathMatrixTest
MathMatrix3Test MathMatrix3Test
MathMatrix4Test MathMatrix4Test
MathComplexTest MathComplexTest

28
src/Math/Test/Matrix3Test.cpp

@ -51,7 +51,7 @@ class Matrix3Test: public Corrade::TestSuite::Tester {
void rotationScalingPart(); void rotationScalingPart();
void rotationPart(); void rotationPart();
void vectorParts(); void vectorParts();
void invertedEuclidean(); void invertedRigid();
void transform(); void transform();
void debug(); void debug();
@ -82,7 +82,7 @@ Matrix3Test::Matrix3Test() {
&Matrix3Test::rotationScalingPart, &Matrix3Test::rotationScalingPart,
&Matrix3Test::rotationPart, &Matrix3Test::rotationPart,
&Matrix3Test::vectorParts, &Matrix3Test::vectorParts,
&Matrix3Test::invertedEuclidean, &Matrix3Test::invertedRigid,
&Matrix3Test::transform, &Matrix3Test::transform,
&Matrix3Test::debug, &Matrix3Test::debug,
@ -271,20 +271,7 @@ void Matrix3Test::vectorParts() {
CORRADE_COMPARE(translation, Vector2(-5.0f, 12.0f)); CORRADE_COMPARE(translation, Vector2(-5.0f, 12.0f));
} }
void Matrix3Test::invertedEuclidean() { void Matrix3Test::invertedRigid() {
std::ostringstream o;
Error::setOutput(&o);
Matrix3 m({3.0f, 5.0f, 8.0f},
{4.0f, 4.0f, 7.0f},
{7.0f, -1.0f, 8.0f});
CORRADE_COMPARE(m.invertedEuclidean(), Matrix3());
CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedEuclidean(): unexpected values on last row\n");
o.str({});
CORRADE_COMPARE(Matrix3::scaling(Vector2(2.0f)).invertedEuclidean(), Matrix3());
CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedEuclidean(): the matrix doesn't represent Euclidean transformation\n");
Matrix3 actual = Matrix3::rotation(Deg(-74.0f))* Matrix3 actual = Matrix3::rotation(Deg(-74.0f))*
Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())* Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())*
Matrix3::translation({2.0f, -3.0f}); Matrix3::translation({2.0f, -3.0f});
@ -292,8 +279,13 @@ void Matrix3Test::invertedEuclidean() {
Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())* Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())*
Matrix3::rotation(Deg(74.0f)); Matrix3::rotation(Deg(74.0f));
CORRADE_COMPARE(actual.invertedEuclidean(), expected); std::ostringstream o;
CORRADE_COMPARE(actual.invertedEuclidean(), actual.inverted()); Error::setOutput(&o);
(2*actual).invertedRigid();
CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation\n");
CORRADE_COMPARE(actual.invertedRigid(), expected);
CORRADE_COMPARE(actual.invertedRigid(), actual.inverted());
} }
void Matrix3Test::transform() { void Matrix3Test::transform() {

29
src/Math/Test/Matrix4Test.cpp

@ -56,7 +56,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester {
void rotationScalingPart(); void rotationScalingPart();
void rotationPart(); void rotationPart();
void vectorParts(); void vectorParts();
void invertedEuclidean(); void invertedRigid();
void transform(); void transform();
void debug(); void debug();
@ -93,7 +93,7 @@ Matrix4Test::Matrix4Test() {
&Matrix4Test::rotationScalingPart, &Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationPart, &Matrix4Test::rotationPart,
&Matrix4Test::vectorParts, &Matrix4Test::vectorParts,
&Matrix4Test::invertedEuclidean, &Matrix4Test::invertedRigid,
&Matrix4Test::transform, &Matrix4Test::transform,
&Matrix4Test::debug, &Matrix4Test::debug,
@ -355,21 +355,7 @@ void Matrix4Test::vectorParts() {
CORRADE_COMPARE(translation, Vector3(-5.0f, 12.0f, 0.5f)); CORRADE_COMPARE(translation, Vector3(-5.0f, 12.0f, 0.5f));
} }
void Matrix4Test::invertedEuclidean() { void Matrix4Test::invertedRigid() {
std::ostringstream o;
Error::setOutput(&o);
Matrix4 m({3.0f, 5.0f, 8.0f, 4.0f},
{4.0f, 4.0f, 7.0f, 3.0f},
{7.0f, -1.0f, 8.0f, 0.0f},
{9.0f, 4.0f, 5.0f, 9.0f});
CORRADE_COMPARE(m.invertedEuclidean(), Matrix4());
CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedEuclidean(): unexpected values on last row\n");
o.str({});
CORRADE_COMPARE(Matrix4::scaling(Vector3(2.0f)).invertedEuclidean(), Matrix4());
CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedEuclidean(): the matrix doesn't represent Euclidean transformation\n");
Matrix4 actual = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized())* Matrix4 actual = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized())*
Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())* Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())*
Matrix4::translation({1.0f, 2.0f, -3.0f}); Matrix4::translation({1.0f, 2.0f, -3.0f});
@ -377,8 +363,13 @@ void Matrix4Test::invertedEuclidean() {
Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())* Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())*
Matrix4::rotation(Deg(74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized()); Matrix4::rotation(Deg(74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized());
CORRADE_COMPARE(actual.invertedEuclidean(), expected); std::ostringstream o;
CORRADE_COMPARE(actual.invertedEuclidean(), actual.inverted()); Error::setOutput(&o);
(2*actual).invertedRigid();
CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation\n");
CORRADE_COMPARE(actual.invertedRigid(), expected);
CORRADE_COMPARE(actual.invertedRigid(), actual.inverted());
} }
void Matrix4Test::transform() { void Matrix4Test::transform() {

17
src/Math/Test/MatrixTest.cpp

@ -46,6 +46,7 @@ class MatrixTest: public Corrade::TestSuite::Tester {
void ij(); void ij();
void determinant(); void determinant();
void inverted(); void inverted();
void invertedOrthogonal();
void debug(); void debug();
void configuration(); void configuration();
@ -57,6 +58,7 @@ typedef Matrix<3, Float> Matrix3;
typedef Vector<4, Float> Vector4; typedef Vector<4, Float> Vector4;
typedef Vector<4, Int> Vector4i; typedef Vector<4, Int> Vector4i;
typedef Vector<3, Float> Vector3; typedef Vector<3, Float> Vector3;
typedef Math::Constants<Float> Constants;
MatrixTest::MatrixTest() { MatrixTest::MatrixTest() {
addTests({&MatrixTest::construct, addTests({&MatrixTest::construct,
@ -71,6 +73,7 @@ MatrixTest::MatrixTest() {
&MatrixTest::ij, &MatrixTest::ij,
&MatrixTest::determinant, &MatrixTest::determinant,
&MatrixTest::inverted, &MatrixTest::inverted,
&MatrixTest::invertedOrthogonal,
&MatrixTest::debug, &MatrixTest::debug,
&MatrixTest::configuration}); &MatrixTest::configuration});
} }
@ -209,6 +212,20 @@ void MatrixTest::inverted() {
CORRADE_COMPARE(_inverse*m, Matrix4()); CORRADE_COMPARE(_inverse*m, Matrix4());
} }
void MatrixTest::invertedOrthogonal() {
std::ostringstream o;
Error::setOutput(&o);
Matrix3 a(Vector3(Constants::sqrt3()/2.0f, 0.5f, 0.0f),
Vector3(-0.5f, Constants::sqrt3()/2.0f, 0.0f),
Vector3(0.0f, 0.0f, 1.0f));
(a*2).invertedOrthogonal();
CORRADE_COMPARE(o.str(), "Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal\n");
CORRADE_COMPARE(a.invertedOrthogonal()*a, Matrix3());
CORRADE_COMPARE(a.invertedOrthogonal(), a.inverted());
}
void MatrixTest::debug() { void MatrixTest::debug() {
Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f), Vector4(4.0f, 4.0f, 7.0f, 3.0f),

2
src/SceneGraph/EuclideanMatrixTransformation2D.h

@ -68,7 +68,7 @@ class EuclideanMatrixTransformation2D: public AbstractTranslationRotation2D<T> {
} }
inline static Math::Matrix3<T> inverted(const Math::Matrix3<T>& transformation) { inline static Math::Matrix3<T> inverted(const Math::Matrix3<T>& transformation) {
return transformation.invertedEuclidean(); return transformation.invertedRigid();
} }
inline Math::Matrix3<T> transformation() const { inline Math::Matrix3<T> transformation() const {

2
src/SceneGraph/EuclideanMatrixTransformation3D.h

@ -68,7 +68,7 @@ class EuclideanMatrixTransformation3D: public AbstractTranslationRotation3D<T> {
} }
inline static Math::Matrix4<T> inverted(const Math::Matrix4<T>& transformation) { inline static Math::Matrix4<T> inverted(const Math::Matrix4<T>& transformation) {
return transformation.invertedEuclidean(); return transformation.invertedRigid();
} }
inline Math::Matrix4<T> transformation() const { inline Math::Matrix4<T> transformation() const {

Loading…
Cancel
Save