From 0d5f234f644633ccef44654a21a608dc0ba38f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 15 Mar 2013 12:16:57 +0100 Subject: [PATCH] SceneGraph: public setTransformation() and transform() for RigidMT*D. Now it is nearly similar to MatrixTransformation*D except for scaling. Public functions setTransformation() and transform() assert that the matrix represents rigid transformation. --- src/SceneGraph/RigidMatrixTransformation2D.h | 56 +++++++++++++--- src/SceneGraph/RigidMatrixTransformation3D.h | 66 ++++++++++++++----- .../Test/RigidMatrixTransformation2DTest.cpp | 54 +++++++++++---- .../Test/RigidMatrixTransformation3DTest.cpp | 55 ++++++++++++---- 4 files changed, 181 insertions(+), 50 deletions(-) diff --git a/src/SceneGraph/RigidMatrixTransformation2D.h b/src/SceneGraph/RigidMatrixTransformation2D.h index 20a79dd02..cdc76d65a 100644 --- a/src/SceneGraph/RigidMatrixTransformation2D.h +++ b/src/SceneGraph/RigidMatrixTransformation2D.h @@ -85,20 +85,53 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * to prevent rounding errors when rotating the object subsequently. */ RigidMatrixTransformation2D* normalizeRotation() { - setTransformation(Math::Matrix3::from( + setTransformationInternal(Math::Matrix3::from( Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), _transformation.translation())); return this; } + /** + * @brief Set transformation + * @return Pointer to self (for method chaining) + * + * Expects that the matrix represents rigid transformation. + * @see Matrix3::isRigidTransformation() + */ + RigidMatrixTransformation2D* setTransformation(const Math::Matrix3& transformation) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation2D::setTransformation(): the matrix doesn't represent rigid transformation", this); + setTransformationInternal(transformation); + return this; + } + inline RigidMatrixTransformation2D* resetTransformation() override { - setTransformation({}); + setTransformationInternal({}); + return this; + } + + /** + * @brief Transform object + * @param transformation Transformation + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Expects that the matrix represents rigid transformation. + * @see Matrix3::isRigidTransformation() + */ + inline RigidMatrixTransformation2D* transform(const Math::Matrix3& transformation, TransformationType type = TransformationType::Global) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation2D::transform(): the matrix doesn't represent rigid transformation", this); + transformInternal(transformation, type); return this; } - /** @copydoc AbstractTranslationRotation2D::translate() */ + /** + * @copydoc AbstractTranslationRotationScaling2D::translate() + * Same as calling transform() with Matrix3::translation(). + */ inline RigidMatrixTransformation2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { - transform(Math::Matrix3::translation(vector), type); + transformInternal(Math::Matrix3::translation(vector), type); return this; } @@ -108,10 +141,11 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see normalizeRotation(), Matrix3::rotation() + * Same as calling transform() with Matrix3::rotation(). + * @see normalizeRotation() */ inline RigidMatrixTransformation2D* rotate(Math::Rad angle, TransformationType type = TransformationType::Global) override { - transform(Math::Matrix3::rotation(angle), type); + transformInternal(Math::Matrix3::rotation(angle), type); return this; } @@ -122,10 +156,10 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see Matrix3::reflection() + * Same as calling transform() with Matrix3::reflection(). */ inline RigidMatrixTransformation2D* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { - transform(Math::Matrix3::reflection(normal), type); + transformInternal(Math::Matrix3::reflection(normal), type); return this; } @@ -145,7 +179,8 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { inline explicit RigidMatrixTransformation2D() = default; private: - inline void setTransformation(const Math::Matrix3& transformation) { + /* No assertions fired, for internal use */ + inline void setTransformationInternal(const Math::Matrix3& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -155,7 +190,8 @@ class RigidMatrixTransformation2D: public AbstractTranslationRotation2D { } } - inline void transform(const Math::Matrix3& transformation, TransformationType type) { + /* No assertions fired, for internal use */ + inline void transformInternal(const Math::Matrix3& transformation, TransformationType type) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); } diff --git a/src/SceneGraph/RigidMatrixTransformation3D.h b/src/SceneGraph/RigidMatrixTransformation3D.h index e89ceb498..e087b7420 100644 --- a/src/SceneGraph/RigidMatrixTransformation3D.h +++ b/src/SceneGraph/RigidMatrixTransformation3D.h @@ -91,22 +91,47 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { return this; } + /** + * @brief Set transformation + * @return Pointer to self (for method chaining) + * + * Expects that the matrix represents rigid transformation. + * @see Matrix4::isRigidTransformation() + */ + RigidMatrixTransformation3D* setTransformation(const Math::Matrix4& transformation) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation3D::setTransformation(): the matrix doesn't represent rigid transformation", this); + setTransformationInternal(transformation); + return this; + } + inline RigidMatrixTransformation3D* resetTransformation() override { setTransformation({}); return this; } /** - * @brief Translate object - * @param vector Translation vector + * @brief Multiply transformation + * @param transformation Transformation * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(), - * Matrix4::translation() + * Expects that the matrix represents rigid transformation. + * @see Matrix4::isRigidTransformation() + */ + inline RigidMatrixTransformation3D* transform(const Math::Matrix4& transformation, TransformationType type = TransformationType::Global) { + CORRADE_ASSERT(transformation.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation3D::transform(): the matrix doesn't represent rigid transformation", this); + transformInternal(transformation, type); + return this; + } + + /** + * @copydoc AbstractTranslationRotationScaling3D::translate() + * Same as calling transform() with Matrix4::translation(). */ inline RigidMatrixTransformation3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { - transform(Math::Matrix4::translation(vector), type); + transformInternal(Math::Matrix4::translation(vector), type); return this; } @@ -117,12 +142,12 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * @param type Transformation type * @return Pointer to self (for method chaining) * + * Same as calling transform() with Matrix4::rotation(). * @see rotateX(), rotateY(), rotateZ(), Vector3::xAxis(), - * Vector3::yAxis(), Vector3::zAxis(), normalizeRotation(), - * Matrix4::rotation() + * Vector3::yAxis(), Vector3::zAxis(), normalizeRotation() */ inline RigidMatrixTransformation3D* rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { - transform(Math::Matrix4::rotation(angle, normalizedAxis), type); + transformInternal(Math::Matrix4::rotation(angle, normalizedAxis), type); return this; } @@ -132,10 +157,11 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see normalizeRotation(), Matrix4::rotationX() + * Same as calling transform() with Matrix4::rotationX(). + * @see normalizeRotation() */ inline RigidMatrixTransformation3D* rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) override { - transform(Math::Matrix4::rotationX(angle), type); + transformInternal(Math::Matrix4::rotationX(angle), type); return this; } @@ -145,10 +171,11 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see normalizeRotation(), Matrix4::rotationY() + * Same as calling transform() with Matrix4::rotationY(). + * @see normalizeRotation() */ inline RigidMatrixTransformation3D* rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) override { - transform(Math::Matrix4::rotationY(angle), type); + transformInternal(Math::Matrix4::rotationY(angle), type); return this; } @@ -158,10 +185,11 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see normalizeRotation(), Matrix4::rotationZ() + * Same as calling transform() with Matrix4::rotationZ(). + * @see normalizeRotation() */ inline RigidMatrixTransformation3D* rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) override { - transform(Math::Matrix4::rotationZ(angle), type); + transformInternal(Math::Matrix4::rotationZ(angle), type); return this; } @@ -172,10 +200,10 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { * @param type Transformation type * @return Pointer to self (for method chaining) * - * @see Matrix4::reflection() + * Same as calling transform() with Matrix4::reflection(). */ inline RigidMatrixTransformation3D* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { - transform(Math::Matrix4::reflection(normal), type); + transformInternal(Math::Matrix4::reflection(normal), type); return this; } @@ -184,7 +212,8 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { inline explicit RigidMatrixTransformation3D() = default; private: - inline void setTransformation(const Math::Matrix4& transformation) { + /* No assertions fired, for internal use */ + inline void setTransformationInternal(const Math::Matrix4& transformation) { /* Setting transformation is forbidden for the scene */ /** @todo Assert for this? */ /** @todo Do this in some common code so we don't need to include Object? */ @@ -194,7 +223,8 @@ class RigidMatrixTransformation3D: public AbstractTranslationRotation3D { } } - inline void transform(const Math::Matrix4& transformation, TransformationType type) { + /* No assertions fired, for internal use */ + inline void transformInternal(const Math::Matrix4& transformation, TransformationType type) { setTransformation(type == TransformationType::Global ? transformation*_transformation : _transformation*transformation); } diff --git a/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp index 2457b3ac9..dccefa1b3 100644 --- a/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp +++ b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp @@ -44,6 +44,7 @@ class RigidMatrixTransformation2DTest: public Corrade::TestSuite::Tester { void setTransformation(); void resetTransformation(); + void transform(); void translate(); void rotate(); void reflect(); @@ -58,6 +59,7 @@ RigidMatrixTransformation2DTest::RigidMatrixTransformation2DTest() { &RigidMatrixTransformation2DTest::setTransformation, &RigidMatrixTransformation2DTest::resetTransformation, + &RigidMatrixTransformation2DTest::transform, &RigidMatrixTransformation2DTest::translate, &RigidMatrixTransformation2DTest::rotate, &RigidMatrixTransformation2DTest::reflect, @@ -91,37 +93,67 @@ void RigidMatrixTransformation2DTest::inverted() { } void RigidMatrixTransformation2DTest::setTransformation() { - /* Dirty after setting transformation */ Object2D o; + + /* Can't transform with non-rigid transformation */ + std::ostringstream out; + Error::setOutput(&out); + o.setTransformation(Matrix3::scaling(Vector2(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation2D::setTransformation(): the matrix doesn't represent rigid transformation\n"); + + /* Dirty after setting transformation */ o.setClean(); - o.rotate(Deg(17.0f)); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))); /* Scene cannot be transformed */ Scene2D s; s.setClean(); - s.rotate(Deg(17.0f)); + s.setTransformation(Matrix3::rotation(Deg(17.0f))); CORRADE_VERIFY(!s.isDirty()); CORRADE_COMPARE(s.transformationMatrix(), Matrix3()); } void RigidMatrixTransformation2DTest::resetTransformation() { Object2D o; - o.rotate(Deg(17.0f)); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); CORRADE_VERIFY(o.transformationMatrix() != Matrix3()); o.resetTransformation(); CORRADE_COMPARE(o.transformationMatrix(), Matrix3()); } +void RigidMatrixTransformation2DTest::transform() { + { + /* Can't transform with non-rigid transformation */ + Object2D o; + std::ostringstream out; + Error::setOutput(&out); + o.transform(Matrix3::scaling(Vector2(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation2D::transform(): the matrix doesn't represent rigid transformation\n"); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.transform(Matrix3::translation({1.0f, -0.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); + } { + Object2D o; + o.setTransformation(Matrix3::rotation(Deg(17.0f))); + o.transform(Matrix3::translation({1.0f, -0.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); + } +} + void RigidMatrixTransformation2DTest::translate() { { Object2D o; - o.rotate(Deg(17.0f)); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); o.translate({1.0f, -0.3f}); CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); } { Object2D o; - o.rotate(Deg(17.0f)); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); o.translate({1.0f, -0.3f}, TransformationType::Local); CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); } @@ -130,12 +162,12 @@ void RigidMatrixTransformation2DTest::translate() { void RigidMatrixTransformation2DTest::rotate() { { Object2D o; - o.translate({1.0f, -0.3f}); + o.setTransformation(Matrix3::translation({1.0f, -0.3f})); o.rotate(Deg(17.0f)); CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f})); } { Object2D o; - o.translate({1.0f, -0.3f}); + o.setTransformation(Matrix3::translation({1.0f, -0.3f})); o.rotate(Deg(17.0f), TransformationType::Local); CORRADE_COMPARE(o.transformationMatrix(), Matrix3::translation({1.0f, -0.3f})*Matrix3::rotation(Deg(17.0f))); } @@ -144,12 +176,12 @@ void RigidMatrixTransformation2DTest::rotate() { void RigidMatrixTransformation2DTest::reflect() { { Object2D o; - o.rotate(Deg(17.0f)); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); o.reflect(Vector2(-1.0f/Constants::sqrt2())); CORRADE_COMPARE(o.transformationMatrix(), Matrix3::reflection(Vector2(-1.0f/Constants::sqrt2()))*Matrix3::rotation(Deg(17.0f))); } { Object2D o; - o.rotate(Deg(17.0f)); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); o.reflect(Vector2(-1.0f/Constants::sqrt2()), TransformationType::Local); CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))*Matrix3::reflection(Vector2(-1.0f/Constants::sqrt2()))); } @@ -157,7 +189,7 @@ void RigidMatrixTransformation2DTest::reflect() { void RigidMatrixTransformation2DTest::normalizeRotation() { Object2D o; - o.rotate(Deg(17.0f)); + o.setTransformation(Matrix3::rotation(Deg(17.0f))); o.normalizeRotation(); CORRADE_COMPARE(o.transformationMatrix(), Matrix3::rotation(Deg(17.0f))); } diff --git a/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp index a154a487f..2d14c3bab 100644 --- a/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp +++ b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp @@ -44,6 +44,7 @@ class RigidMatrixTransformation3DTest: public Corrade::TestSuite::Tester { void setTransformation(); void resetTransformation(); + void transform(); void translate(); void rotate(); void reflect(); @@ -58,6 +59,7 @@ RigidMatrixTransformation3DTest::RigidMatrixTransformation3DTest() { &RigidMatrixTransformation3DTest::setTransformation, &RigidMatrixTransformation3DTest::resetTransformation, + &RigidMatrixTransformation3DTest::transform, &RigidMatrixTransformation3DTest::translate, &RigidMatrixTransformation3DTest::rotate, &RigidMatrixTransformation3DTest::reflect, @@ -91,37 +93,68 @@ void RigidMatrixTransformation3DTest::inverted() { } void RigidMatrixTransformation3DTest::setTransformation() { - /* Dirty after setting transformation */ Object3D o; + + /* Can't transform with non-rigid transformation */ + std::ostringstream out; + Error::setOutput(&out); + o.setTransformation(Matrix4::scaling(Vector3(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation3D::setTransformation(): the matrix doesn't represent rigid transformation\n"); + + /* Dirty after setting transformation */ o.setClean(); - o.rotateX(Deg(17.0f)); + CORRADE_VERIFY(!o.isDirty()); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); CORRADE_VERIFY(o.isDirty()); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))); /* Scene cannot be transformed */ Scene3D s; s.setClean(); - s.rotateX(Deg(17.0f)); + CORRADE_VERIFY(!s.isDirty()); + s.setTransformation(Matrix4::rotationX(Deg(17.0f))); CORRADE_VERIFY(!s.isDirty()); CORRADE_COMPARE(s.transformationMatrix(), Matrix4()); } void RigidMatrixTransformation3DTest::resetTransformation() { Object3D o; - o.rotateX(Deg(17.0f)); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); CORRADE_VERIFY(o.transformationMatrix() != Matrix4()); o.resetTransformation(); CORRADE_COMPARE(o.transformationMatrix(), Matrix4()); } +void RigidMatrixTransformation3DTest::transform() { + { + /* Can't transform with non-rigid transformation */ + Object3D o; + std::ostringstream out; + Error::setOutput(&out); + o.transform(Matrix4::scaling(Vector3(3.0f))); + CORRADE_COMPARE(out.str(), "SceneGraph::RigidMatrixTransformation3D::transform(): the matrix doesn't represent rigid transformation\n"); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.transform(Matrix4::translation({1.0f, -0.3f, 2.3f})); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); + } { + Object3D o; + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); + o.transform(Matrix4::translation({1.0f, -0.3f, 2.3f}), TransformationType::Local); + CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); + } +} + void RigidMatrixTransformation3DTest::translate() { { Object3D o; - o.rotateX(Deg(17.0f)); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); o.translate({1.0f, -0.3f, 2.3f}); CORRADE_COMPARE(o.transformationMatrix(), Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::rotationX(Deg(17.0f))); } { Object3D o; - o.rotateX(Deg(17.0f)); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); o.translate({1.0f, -0.3f, 2.3f}, TransformationType::Local); CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})); } @@ -130,7 +163,7 @@ void RigidMatrixTransformation3DTest::translate() { void RigidMatrixTransformation3DTest::rotate() { { Object3D o; - o.translate({1.0f, -0.3f, 2.3f}); + o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); o.rotateX(Deg(17.0f)) ->rotateY(Deg(25.0f)) ->rotateZ(Deg(-23.0f)) @@ -143,7 +176,7 @@ void RigidMatrixTransformation3DTest::rotate() { Matrix4::translation({1.0f, -0.3f, 2.3f})); } { Object3D o; - o.translate({1.0f, -0.3f, 2.3f}); + o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); o.rotateX(Deg(17.0f), TransformationType::Local) ->rotateY(Deg(25.0f), TransformationType::Local) ->rotateZ(Deg(-23.0f), TransformationType::Local) @@ -160,12 +193,12 @@ void RigidMatrixTransformation3DTest::rotate() { void RigidMatrixTransformation3DTest::reflect() { { Object3D o; - o.rotateX(Deg(17.0f)); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); o.reflect(Vector3(-1.0f/Constants::sqrt3())); CORRADE_COMPARE(o.transformationMatrix(), Matrix4::reflection(Vector3(-1.0f/Constants::sqrt3()))*Matrix4::rotationX(Deg(17.0f))); } { Object3D o; - o.rotateX(Deg(17.0f)); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); o.reflect(Vector3(-1.0f/Constants::sqrt3()), TransformationType::Local); CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))*Matrix4::reflection(Vector3(-1.0f/Constants::sqrt3()))); } @@ -173,7 +206,7 @@ void RigidMatrixTransformation3DTest::reflect() { void RigidMatrixTransformation3DTest::normalizeRotation() { Object3D o; - o.rotateX(Deg(17.0f)); + o.setTransformation(Matrix4::rotationX(Deg(17.0f))); o.normalizeRotation(); CORRADE_COMPARE(o.transformationMatrix(), Matrix4::rotationX(Deg(17.0f))); }