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
DualQuaternion::inverted(). %Matrix inversion is quite costly, so if your
transformation involves only translation and rotation, you can use faster
alternatives Matrix3::invertedEuclidean() and Matrix4::invertedEuclidean(). If
you are sure that the (dual) complex number or (dual) quaternion is of unit
length, you can use Complex::invertedNormalized(), Quaternion::invertedNormalized(),
alternatives Matrix3::invertedRigid() and Matrix4::invertedRigid(). If you are
sure that the (dual) complex number or (dual) quaternion is of unit length, you
can use Complex::invertedNormalized(), Quaternion::invertedNormalized(),
DualComplex::invertedNormalized() or DualQuaternion::invertedNormalized() which
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[
* A^{-1} = \frac{1}{\det(A)} Adj(A)
* @f]
*
* See Matrix3::invertedEuclidean() and Matrix4::invertedEuclidean()
* See invertedOrthogonal(), Matrix3::invertedRigid() and Matrix4::invertedRigid()
* which are faster alternatives for particular matrix types.
*/
Matrix<size, T> inverted() const {
@ -184,6 +183,21 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
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
/* Reimplementation of functions to return correct type */
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> 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) \
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 */
/**
* @brief Inverted Euclidean transformation matrix
* @brief Inverted rigid transformation matrix
*
* Assumes that the matrix represents Euclidean transformation (i.e.
* only rotation and translation, no scaling) and creates inverted
* matrix from transposed rotation part and negated translation part.
* Expects that the matrix represents rigid transformation.
* 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 {
CORRADE_ASSERT((*this)[0][2] == T(0) && (*this)[1][2] == T(0) && (*this)[2][2] == T(1),
"Math::Matrix3::invertedEuclidean(): unexpected values on last row", {});
inline Matrix3<T> invertedRigid() const {
CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation", {});
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());
}

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 */
/**
* @brief Inverted Euclidean transformation matrix
* @brief Inverted rigid transformation matrix
*
* Expects that the matrix represents Euclidean transformation (i.e.
* only rotation and translation, no scaling) and creates inverted
* matrix from transposed rotation part and negated translation part.
* Expects that the matrix represents rigid transformation.
* 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 {
CORRADE_ASSERT((*this)[0][3] == T(0) && (*this)[1][3] == T(0) && (*this)[2][3] == T(0) && (*this)[3][3] == T(1),
"Math::Matrix4::invertedEuclidean(): unexpected values on last row", {});
inline Matrix4<T> invertedRigid() const {
CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {});
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());
}

1
src/Math/Test/CMakeLists.txt

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

28
src/Math/Test/Matrix3Test.cpp

@ -51,7 +51,7 @@ class Matrix3Test: public Corrade::TestSuite::Tester {
void rotationScalingPart();
void rotationPart();
void vectorParts();
void invertedEuclidean();
void invertedRigid();
void transform();
void debug();
@ -82,7 +82,7 @@ Matrix3Test::Matrix3Test() {
&Matrix3Test::rotationScalingPart,
&Matrix3Test::rotationPart,
&Matrix3Test::vectorParts,
&Matrix3Test::invertedEuclidean,
&Matrix3Test::invertedRigid,
&Matrix3Test::transform,
&Matrix3Test::debug,
@ -271,20 +271,7 @@ void Matrix3Test::vectorParts() {
CORRADE_COMPARE(translation, Vector2(-5.0f, 12.0f));
}
void Matrix3Test::invertedEuclidean() {
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");
void Matrix3Test::invertedRigid() {
Matrix3 actual = Matrix3::rotation(Deg(-74.0f))*
Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())*
Matrix3::translation({2.0f, -3.0f});
@ -292,8 +279,13 @@ void Matrix3Test::invertedEuclidean() {
Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())*
Matrix3::rotation(Deg(74.0f));
CORRADE_COMPARE(actual.invertedEuclidean(), expected);
CORRADE_COMPARE(actual.invertedEuclidean(), actual.inverted());
std::ostringstream o;
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() {

29
src/Math/Test/Matrix4Test.cpp

@ -56,7 +56,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester {
void rotationScalingPart();
void rotationPart();
void vectorParts();
void invertedEuclidean();
void invertedRigid();
void transform();
void debug();
@ -93,7 +93,7 @@ Matrix4Test::Matrix4Test() {
&Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationPart,
&Matrix4Test::vectorParts,
&Matrix4Test::invertedEuclidean,
&Matrix4Test::invertedRigid,
&Matrix4Test::transform,
&Matrix4Test::debug,
@ -355,21 +355,7 @@ void Matrix4Test::vectorParts() {
CORRADE_COMPARE(translation, Vector3(-5.0f, 12.0f, 0.5f));
}
void Matrix4Test::invertedEuclidean() {
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");
void Matrix4Test::invertedRigid() {
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::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::rotation(Deg(74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized());
CORRADE_COMPARE(actual.invertedEuclidean(), expected);
CORRADE_COMPARE(actual.invertedEuclidean(), actual.inverted());
std::ostringstream o;
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() {

17
src/Math/Test/MatrixTest.cpp

@ -46,6 +46,7 @@ class MatrixTest: public Corrade::TestSuite::Tester {
void ij();
void determinant();
void inverted();
void invertedOrthogonal();
void debug();
void configuration();
@ -57,6 +58,7 @@ typedef Matrix<3, Float> Matrix3;
typedef Vector<4, Float> Vector4;
typedef Vector<4, Int> Vector4i;
typedef Vector<3, Float> Vector3;
typedef Math::Constants<Float> Constants;
MatrixTest::MatrixTest() {
addTests({&MatrixTest::construct,
@ -71,6 +73,7 @@ MatrixTest::MatrixTest() {
&MatrixTest::ij,
&MatrixTest::determinant,
&MatrixTest::inverted,
&MatrixTest::invertedOrthogonal,
&MatrixTest::debug,
&MatrixTest::configuration});
}
@ -209,6 +212,20 @@ void MatrixTest::inverted() {
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() {
Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.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) {
return transformation.invertedEuclidean();
return transformation.invertedRigid();
}
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) {
return transformation.invertedEuclidean();
return transformation.invertedRigid();
}
inline Math::Matrix4<T> transformation() const {

Loading…
Cancel
Save