From 0f8d2f2e985c3b17e05628d32959997b94201c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 14 Oct 2013 01:36:27 +0200 Subject: [PATCH] SceneGraph: hide internal transformation implementation from public API. Previously it was possible to access internal transformation implementation from Transformation and thus also from Object, e.g.: typedef SceneGraph::Object Object2D; Object2D o; o.fromMatrix(...); // What does this here and why it returns matrix?! Now everything is hidden in Implementation namespace and all traces of previous code are removed from documentation. It might now be slightly harder for users to implement their own transformation implementations, but it wasn't easy before either. The widely used ones are already implemented, so it shouldn't be too much of a problem. Similarly for potential backward compatibility issues, I assume nobody needed to implement their own transformation yet. --- src/SceneGraph/AbstractTransformation.h | 85 ++----------------- src/SceneGraph/DualComplexTransformation.h | 71 ++++++++-------- src/SceneGraph/DualQuaternionTransformation.h | 75 ++++++++-------- src/SceneGraph/MatrixTransformation2D.h | 45 +++++----- src/SceneGraph/MatrixTransformation3D.h | 45 +++++----- src/SceneGraph/Object.h | 4 +- src/SceneGraph/Object.hpp | 23 ++--- src/SceneGraph/RigidMatrixTransformation2D.h | 77 +++++++++-------- src/SceneGraph/RigidMatrixTransformation3D.h | 77 +++++++++-------- .../Test/DualComplexTransformationTest.cpp | 8 +- .../Test/DualQuaternionTransformationTest.cpp | 8 +- .../Test/MatrixTransformation2DTest.cpp | 8 +- .../Test/MatrixTransformation3DTest.cpp | 8 +- .../Test/RigidMatrixTransformation2DTest.cpp | 12 +-- .../Test/RigidMatrixTransformation3DTest.cpp | 12 +-- 15 files changed, 252 insertions(+), 306 deletions(-) diff --git a/src/SceneGraph/AbstractTransformation.h b/src/SceneGraph/AbstractTransformation.h index baacea042..860893c64 100644 --- a/src/SceneGraph/AbstractTransformation.h +++ b/src/SceneGraph/AbstractTransformation.h @@ -40,15 +40,7 @@ namespace Magnum { namespace SceneGraph { /** @brief Base for transformations -Provides transformation implementation for Object instances. See @ref scenegraph -for introduction. - -@section AbstractTransformation-subclassing Subclassing - -When subclassing, you have to: - -- Implement all members listed in **Subclass implementation** group above -- Provide implicit (parameterless) constructor +Provides transformation implementation for @ref Object instances. @see @ref scenegraph, @ref AbstractBasicTransformation2D, @ref AbstractBasicTransformation3D, @ref AbstractTransformation2D, @@ -64,76 +56,6 @@ template class MAGNUM_SCENEGRAPH_EXPORT Abstrac explicit AbstractTransformation(); - #ifdef DOXYGEN_GENERATING_OUTPUT - /** - * @{ @name Subclass implementation - * - * These members must be defined by the implementation. - */ - - /** - * @todo Common way to call setClean() on the object after setting - * transformation & disallowing transformation setting on scene, - * so the implementer doesn't forget to do it? It could also - * allow to hide Object::isScene() from unwanted publicity. - */ - - /** - * @brief Transformation data type - * - * The type must satisfy the following requirements: - * - * - Default constructor must create identity transformation - * - * Defined in subclasses. - */ - typedef U DataType; - - /** - * @brief Convert transformation to matrix - * - * Defined in subclasses. - */ - static typename DimensionTraits::MatrixType toMatrix(const DataType& transformation); - - /** - * @brief Convert transformation from matrix - * - * Defined in subclasses. - */ - static DataType fromMatrix(const typename DimensionTraits::MatrixType& matrix); - - /** - * @brief Compose transformations - * - * Defined in subclasses. - */ - static DataType compose(const DataType& parent, const DataType& child); - - /** - * @brief Inverted transformation - * - * Defined in subclasses. - */ - static DataType inverted(const DataType& transformation); - - /** - * @brief %Object transformation - * - * Relative to parent. Defined in subclasses. - */ - DataType transformation() const; - - /** - * @brief Absolute transformation - * - * Relative to root object. Defined in subclasses. - */ - DataType absoluteTransformation() const; - - /*@}*/ - #endif - /** * @brief Reset object transformation * @return Reference to self (for method chaining) @@ -212,6 +134,11 @@ typedef AbstractBasicTransformation3D AbstractTransformation3D; typedef AbstractTransformation<3, Float> AbstractTransformation3D; #endif +namespace Implementation { + /* See DualQuaternionTransformation.h for example implementation */ + template struct Transformation; +} + }} #endif diff --git a/src/SceneGraph/DualComplexTransformation.h b/src/SceneGraph/DualComplexTransformation.h index 55f149922..971e17a57 100644 --- a/src/SceneGraph/DualComplexTransformation.h +++ b/src/SceneGraph/DualComplexTransformation.h @@ -46,40 +46,8 @@ template class BasicDualComplexTransformation: public AbstractBasicTran /** @brief Transformation type */ typedef Math::DualComplex DataType; - #ifndef DOXYGEN_GENERATING_OUTPUT - static Math::DualComplex fromMatrix(const Math::Matrix3& matrix) { - return Math::DualComplex::fromMatrix(matrix); - } - - constexpr static Math::Matrix3 toMatrix(const Math::DualComplex& transformation) { - return transformation.toMatrix(); - } - - static Math::DualComplex compose(const Math::DualComplex& parent, const Math::DualComplex& child) { - return parent*child; - } - - static Math::DualComplex inverted(const Math::DualComplex& transformation) { - return transformation.invertedNormalized(); - } - - Math::DualComplex transformation() const { - return _transformation; - } - #endif - - /** - * @brief Normalize rotation part - * @return Reference to self (for method chaining) - * - * Normalizes the rotation part to prevent rounding errors when rotating - * the object subsequently. - * @see DualComplex::normalized() - */ - Object>& normalizeRotation() { - setTransformationInternal(_transformation.normalized()); - return static_cast>&>(*this); - } + /** @brief Object transformation */ + Math::DualComplex transformation() const { return _transformation; } /** * @brief Set transformation @@ -102,6 +70,19 @@ template class BasicDualComplexTransformation: public AbstractBasicTran return static_cast>&>(*this); } + /** + * @brief Normalize rotation part + * @return Reference to self (for method chaining) + * + * Normalizes the rotation part to prevent rounding errors when rotating + * the object subsequently. + * @see DualComplex::normalized() + */ + Object>& normalizeRotation() { + setTransformationInternal(_transformation.normalized()); + return static_cast>&>(*this); + } + /** * @brief Transform object * @param transformation Transformation @@ -195,6 +176,28 @@ template class BasicDualComplexTransformation: public AbstractBasicTran */ typedef BasicDualComplexTransformation DualComplexTransformation; +namespace Implementation { + +template struct Transformation> { + static Math::DualComplex fromMatrix(const Math::Matrix3& matrix) { + return Math::DualComplex::fromMatrix(matrix); + } + + constexpr static Math::Matrix3 toMatrix(const Math::DualComplex& transformation) { + return transformation.toMatrix(); + } + + static Math::DualComplex compose(const Math::DualComplex& parent, const Math::DualComplex& child) { + return parent*child; + } + + static Math::DualComplex inverted(const Math::DualComplex& transformation) { + return transformation.invertedNormalized(); + } +}; + +} + }} #endif diff --git a/src/SceneGraph/DualQuaternionTransformation.h b/src/SceneGraph/DualQuaternionTransformation.h index 8394e5bd2..1f889f40b 100644 --- a/src/SceneGraph/DualQuaternionTransformation.h +++ b/src/SceneGraph/DualQuaternionTransformation.h @@ -46,42 +46,8 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT /** @brief Underlying transformation type */ typedef Math::DualQuaternion DataType; - #ifndef DOXYGEN_GENERATING_OUTPUT - static Math::DualQuaternion fromMatrix(const Math::Matrix4& matrix) { - CORRADE_ASSERT(matrix.isRigidTransformation(), - "SceneGraph::DualQuaternionTransformation::fromMatrix(): the matrix doesn't represent rigid transformation", {}); - return Math::DualQuaternion::fromMatrix(matrix); - } - - constexpr static Math::Matrix4 toMatrix(const Math::DualQuaternion& transformation) { - return transformation.toMatrix(); - } - - static Math::DualQuaternion compose(const Math::DualQuaternion& parent, const Math::DualQuaternion& child) { - return parent*child; - } - - static Math::DualQuaternion inverted(const Math::DualQuaternion& transformation) { - return transformation.invertedNormalized(); - } - - Math::DualQuaternion transformation() const { - return _transformation; - } - #endif - - /** - * @brief Normalize rotation part - * @return Reference to self (for method chaining) - * - * Normalizes the rotation part to prevent rounding errors when rotating - * the object subsequently. - * @see DualQuaternion::normalized() - */ - Object>& normalizeRotation() { - setTransformation(_transformation.normalized()); - return static_cast>&>(*this); - } + /** @brief Object transformation */ + Math::DualQuaternion transformation() const { return _transformation; } /** * @brief Set transformation @@ -104,6 +70,19 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT return static_cast>&>(*this); } + /** + * @brief Normalize rotation part + * @return Reference to self (for method chaining) + * + * Normalizes the rotation part to prevent rounding errors when rotating + * the object subsequently. + * @see DualQuaternion::normalized() + */ + Object>& normalizeRotation() { + setTransformation(_transformation.normalized()); + return static_cast>&>(*this); + } + /** * @brief Multiply transformation * @param transformation Transformation @@ -201,6 +180,30 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT */ typedef BasicDualQuaternionTransformation DualQuaternionTransformation; +namespace Implementation { + +template struct Transformation> { + static Math::DualQuaternion fromMatrix(const Math::Matrix4& matrix) { + CORRADE_ASSERT(matrix.isRigidTransformation(), + "SceneGraph::DualQuaternionTransformation: the matrix doesn't represent rigid transformation", {}); + return Math::DualQuaternion::fromMatrix(matrix); + } + + constexpr static Math::Matrix4 toMatrix(const Math::DualQuaternion& transformation) { + return transformation.toMatrix(); + } + + static Math::DualQuaternion compose(const Math::DualQuaternion& parent, const Math::DualQuaternion& child) { + return parent*child; + } + + static Math::DualQuaternion inverted(const Math::DualQuaternion& transformation) { + return transformation.invertedNormalized(); + } +}; + +} + }} #endif diff --git a/src/SceneGraph/MatrixTransformation2D.h b/src/SceneGraph/MatrixTransformation2D.h index a58232845..05eb7e898 100644 --- a/src/SceneGraph/MatrixTransformation2D.h +++ b/src/SceneGraph/MatrixTransformation2D.h @@ -45,27 +45,8 @@ template class BasicMatrixTransformation2D: public AbstractBasicTransla /** @brief Underlying transformation type */ typedef Math::Matrix3 DataType; - #ifndef DOXYGEN_GENERATING_OUTPUT - constexpr static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { - return matrix; - } - - constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { - return transformation; - } - - static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { - return parent*child; - } - - static Math::Matrix3 inverted(const Math::Matrix3& transformation) { - return transformation.inverted(); - } - - Math::Matrix3 transformation() const { - return _transformation; - } - #endif + /** @brief Object transformation */ + Math::Matrix3 transformation() const { return _transformation; } /** * @brief Set transformation @@ -182,6 +163,28 @@ template class BasicMatrixTransformation2D: public AbstractBasicTransla */ typedef BasicMatrixTransformation2D MatrixTransformation2D; +namespace Implementation { + +template struct Transformation> { + constexpr static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { + return matrix; + } + + constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { + return transformation; + } + + static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { + return parent*child; + } + + static Math::Matrix3 inverted(const Math::Matrix3& transformation) { + return transformation.inverted(); + } +}; + +} + }} #endif diff --git a/src/SceneGraph/MatrixTransformation3D.h b/src/SceneGraph/MatrixTransformation3D.h index a9e4e577b..69c9a9658 100644 --- a/src/SceneGraph/MatrixTransformation3D.h +++ b/src/SceneGraph/MatrixTransformation3D.h @@ -45,27 +45,8 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla /** @brief Underlying transformation type */ typedef Math::Matrix4 DataType; - #ifndef DOXYGEN_GENERATING_OUTPUT - constexpr static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { - return matrix; - } - - constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { - return transformation; - } - - static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { - return parent*child; - } - - static Math::Matrix4 inverted(const Math::Matrix4& transformation) { - return transformation.inverted(); - } - - Math::Matrix4 transformation() const { - return _transformation; - } - #endif + /** @brief Object transformation */ + Math::Matrix4 transformation() const { return _transformation; } /** * @brief Set transformation @@ -222,6 +203,28 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla */ typedef BasicMatrixTransformation3D MatrixTransformation3D; +namespace Implementation { + +template struct Transformation> { + constexpr static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { + return matrix; + } + + constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { + return transformation; + } + + static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { + return parent*child; + } + + static Math::Matrix4 inverted(const Math::Matrix4& transformation) { + return transformation.inverted(); + } +}; + +} + }} #endif diff --git a/src/SceneGraph/Object.h b/src/SceneGraph/Object.h index d48fab792..75bd939fc 100644 --- a/src/SceneGraph/Object.h +++ b/src/SceneGraph/Object.h @@ -215,7 +215,7 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs * @see transformation() */ MatrixType transformationMatrix() const { - return Transformation::toMatrix(Transformation::transformation()); + return Implementation::Transformation::toMatrix(Transformation::transformation()); } /** @@ -224,7 +224,7 @@ template class MAGNUM_SCENEGRAPH_EXPORT Object: public Abs * @see absoluteTransformation() */ MatrixType absoluteTransformationMatrix() const { - return Transformation::toMatrix(absoluteTransformation()); + return Implementation::Transformation::toMatrix(absoluteTransformation()); } /** diff --git a/src/SceneGraph/Object.hpp b/src/SceneGraph/Object.hpp index 67ee09f69..71acb4ed1 100644 --- a/src/SceneGraph/Object.hpp +++ b/src/SceneGraph/Object.hpp @@ -91,8 +91,8 @@ template Object& Object::s template Object& Object::setParentKeepTransformation(Object* parent) { CORRADE_ASSERT(scene() == parent->scene(), "SceneGraph::Object::setParentKeepTransformation(): both parents must be in the same scene", *this); - const auto transformation = Transformation::compose( - Transformation::inverted(parent->absoluteTransformation()), absoluteTransformation()); + const auto transformation = Implementation::Transformation::compose( + Implementation::Transformation::inverted(parent->absoluteTransformation()), absoluteTransformation()); setParent(parent); Transformation::setTransformation(transformation); @@ -101,7 +101,7 @@ template Object& Object::s template typename Transformation::DataType Object::absoluteTransformation() const { if(!parent()) return Transformation::transformation(); - return Transformation::compose(parent()->absoluteTransformation(), Transformation::transformation()); + return Implementation::Transformation::compose(parent()->absoluteTransformation(), Transformation::transformation()); } template void Object::setDirty() { @@ -153,7 +153,7 @@ template void Object::setClean() { objects.pop(); /* Compose transformation and clean object */ - absoluteTransformation = Transformation::compose(absoluteTransformation, o->transformation()); + absoluteTransformation = Implementation::Transformation::compose(absoluteTransformation, o->transformation()); CORRADE_INTERNAL_ASSERT(o->isDirty()); o->setClean(absoluteTransformation); CORRADE_ASSERT(!o->isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", ); @@ -171,10 +171,10 @@ template auto Object::doTransformationMatr } template auto Object::transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { - std::vector transformations = this->transformations(std::move(objects), Transformation::fromMatrix(initialTransformationMatrix)); + std::vector transformations = this->transformations(std::move(objects), Implementation::Transformation::fromMatrix(initialTransformationMatrix)); std::vector transformationMatrices(transformations.size()); for(std::size_t i = 0; i != objects.size(); ++i) - transformationMatrices[i] = Transformation::toMatrix(transformations[i]); + transformationMatrices[i] = Implementation::Transformation::toMatrix(transformations[i]); return transformationMatrices; } @@ -310,16 +310,16 @@ template typename Transformation::DataType ObjectisScene()); return (jointTransformations[joint] = - Transformation::compose(initialTransformation, jointTransformations[joint])); + Implementation::Transformation::compose(initialTransformation, jointTransformations[joint])); /* Joint object, compose transformation with the joint, done */ } else if(parent->flags & Flag::Joint) { return (jointTransformations[joint] = - Transformation::compose(computeJointTransformation(jointObjects, jointTransformations, parent->counter, initialTransformation), jointTransformations[joint])); + Implementation::Transformation::compose(computeJointTransformation(jointObjects, jointTransformations, parent->counter, initialTransformation), jointTransformations[joint])); /* Else compose transformation with parent, go up the hierarchy */ } else { - jointTransformations[joint] = Transformation::compose(parent->transformation(), jointTransformations[joint]); + jointTransformations[joint] = Implementation::Transformation::compose(parent->transformation(), jointTransformations[joint]); o = parent; } } @@ -385,7 +385,7 @@ template void Object::setClean(const typen if(i->cachedTransformations() & CachedTransformation::Absolute) { if(!(cached & CachedTransformation::Absolute)) { cached |= CachedTransformation::Absolute; - matrix = Transformation::toMatrix(absoluteTransformation); + matrix = Implementation::Transformation::toMatrix(absoluteTransformation); } i->clean(matrix); @@ -396,7 +396,8 @@ template void Object::setClean(const typen if(i->cachedTransformations() & CachedTransformation::InvertedAbsolute) { if(!(cached & CachedTransformation::InvertedAbsolute)) { cached |= CachedTransformation::InvertedAbsolute; - invertedMatrix = Transformation::toMatrix(Transformation::inverted(absoluteTransformation)); + invertedMatrix = Implementation::Transformation::toMatrix( + Implementation::Transformation::inverted(absoluteTransformation)); } i->cleanInverted(invertedMatrix); diff --git a/src/SceneGraph/RigidMatrixTransformation2D.h b/src/SceneGraph/RigidMatrixTransformation2D.h index 8db697eab..dda3e97f7 100644 --- a/src/SceneGraph/RigidMatrixTransformation2D.h +++ b/src/SceneGraph/RigidMatrixTransformation2D.h @@ -49,43 +49,8 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr /** @brief Underlying transformation type */ typedef Math::Matrix3 DataType; - #ifndef DOXYGEN_GENERATING_OUTPUT - static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { - CORRADE_ASSERT(matrix.isRigidTransformation(), - "SceneGraph::RigidMatrixTransformation2D::fromMatrix(): the matrix doesn't represent rigid transformation", {}); - return matrix; - } - - constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { - return transformation; - } - - static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { - return parent*child; - } - - static Math::Matrix3 inverted(const Math::Matrix3& transformation) { - return transformation.invertedRigid(); - } - - Math::Matrix3 transformation() const { - return _transformation; - } - #endif - - /** - * @brief Normalize rotation part - * @return Reference to self (for method chaining) - * - * Normalizes the rotation part using Math::Algorithms::gramSchmidt() - * to prevent rounding errors when rotating the object subsequently. - */ - Object>& normalizeRotation() { - setTransformationInternal(Math::Matrix3::from( - Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), - _transformation.translation())); - return static_cast>&>(*this); - } + /** @brief Object transformation */ + Math::Matrix3 transformation() const { return _transformation; } /** * @brief Set transformation @@ -108,6 +73,20 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr return static_cast>&>(*this); } + /** + * @brief Normalize rotation part + * @return Reference to self (for method chaining) + * + * Normalizes the rotation part using Math::Algorithms::gramSchmidt() + * to prevent rounding errors when rotating the object subsequently. + */ + Object>& normalizeRotation() { + setTransformationInternal(Math::Matrix3::from( + Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), + _transformation.translation())); + return static_cast>&>(*this); + } + /** * @brief Transform object * @param transformation Transformation @@ -215,6 +194,30 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr */ typedef BasicRigidMatrixTransformation2D RigidMatrixTransformation2D; +namespace Implementation { + +template struct Transformation> { + static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { + CORRADE_ASSERT(matrix.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation2D: the matrix doesn't represent rigid transformation", {}); + return matrix; + } + + constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { + return transformation; + } + + static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { + return parent*child; + } + + static Math::Matrix3 inverted(const Math::Matrix3& transformation) { + return transformation.invertedRigid(); + } +}; + +} + }} #endif diff --git a/src/SceneGraph/RigidMatrixTransformation3D.h b/src/SceneGraph/RigidMatrixTransformation3D.h index becd46ce2..23026709b 100644 --- a/src/SceneGraph/RigidMatrixTransformation3D.h +++ b/src/SceneGraph/RigidMatrixTransformation3D.h @@ -49,43 +49,8 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr /** @brief Underlying transformation type */ typedef Math::Matrix4 DataType; - #ifndef DOXYGEN_GENERATING_OUTPUT - static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { - CORRADE_ASSERT(matrix.isRigidTransformation(), - "SceneGraph::RigidMatrixTransformation3D::fromMatrix(): the matrix doesn't represent rigid transformation", {}); - return matrix; - } - - constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { - return transformation; - } - - static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { - return parent*child; - } - - static Math::Matrix4 inverted(const Math::Matrix4& transformation) { - return transformation.invertedRigid(); - } - - Math::Matrix4 transformation() const { - return _transformation; - } - #endif - - /** - * @brief Normalize rotation part - * @return Reference to self (for method chaining) - * - * Normalizes the rotation part using Math::Algorithms::gramSchmidt() - * to prevent rounding errors when rotating the object subsequently. - */ - Object>& normalizeRotation() { - setTransformation(Math::Matrix4::from( - Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), - _transformation.translation())); - return static_cast>&>(*this); - } + /** @brief Object transformation */ + Math::Matrix4 transformation() const { return _transformation; } /** * @brief Set transformation @@ -108,6 +73,20 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr return static_cast>&>(*this); } + /** + * @brief Normalize rotation part + * @return Reference to self (for method chaining) + * + * Normalizes the rotation part using Math::Algorithms::gramSchmidt() + * to prevent rounding errors when rotating the object subsequently. + */ + Object>& normalizeRotation() { + setTransformation(Math::Matrix4::from( + Math::Algorithms::gramSchmidtOrthonormalize(_transformation.rotationScaling()), + _transformation.translation())); + return static_cast>&>(*this); + } + /** * @brief Multiply transformation * @param transformation Transformation @@ -260,6 +239,30 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr */ typedef BasicRigidMatrixTransformation3D RigidMatrixTransformation3D; +namespace Implementation { + +template struct Transformation> { + static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { + CORRADE_ASSERT(matrix.isRigidTransformation(), + "SceneGraph::RigidMatrixTransformation3D: the matrix doesn't represent rigid transformation", {}); + return matrix; + } + + constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { + return transformation; + } + + static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { + return parent*child; + } + + static Math::Matrix4 inverted(const Math::Matrix4& transformation) { + return transformation.invertedRigid(); + } +}; + +} + }} #endif diff --git a/src/SceneGraph/Test/DualComplexTransformationTest.cpp b/src/SceneGraph/Test/DualComplexTransformationTest.cpp index 87d222df4..5d7417065 100644 --- a/src/SceneGraph/Test/DualComplexTransformationTest.cpp +++ b/src/SceneGraph/Test/DualComplexTransformationTest.cpp @@ -67,24 +67,24 @@ DualComplexTransformationTest::DualComplexTransformationTest() { void DualComplexTransformationTest::fromMatrix() { Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); DualComplex c = DualComplex::rotation(Deg(17.0f))*DualComplex::translation({1.0f, -0.3f}); - CORRADE_COMPARE(DualComplexTransformation::fromMatrix(m), c); + CORRADE_COMPARE(Implementation::Transformation::fromMatrix(m), c); } void DualComplexTransformationTest::toMatrix() { DualComplex c = DualComplex::rotation(Deg(17.0f))*DualComplex::translation({1.0f, -0.3f}); Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(DualComplexTransformation::toMatrix(c), m); + CORRADE_COMPARE(Implementation::Transformation::toMatrix(c), m); } void DualComplexTransformationTest::compose() { DualComplex parent = DualComplex::rotation(Deg(17.0f)); DualComplex child = DualComplex::translation({1.0f, -0.3f}); - CORRADE_COMPARE(DualComplexTransformation::compose(parent, child), parent*child); + CORRADE_COMPARE(Implementation::Transformation::compose(parent, child), parent*child); } void DualComplexTransformationTest::inverted() { DualComplex c = DualComplex::rotation(Deg(17.0f))*DualComplex::translation({1.0f, -0.3f}); - CORRADE_COMPARE(DualComplexTransformation::inverted(c)*c, DualComplex()); + CORRADE_COMPARE(Implementation::Transformation::inverted(c)*c, DualComplex()); } void DualComplexTransformationTest::setTransformation() { diff --git a/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp b/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp index fd48a3ac7..5da2ae242 100644 --- a/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp +++ b/src/SceneGraph/Test/DualQuaternionTransformationTest.cpp @@ -67,24 +67,24 @@ DualQuaternionTransformationTest::DualQuaternionTransformationTest() { void DualQuaternionTransformationTest::fromMatrix() { Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); DualQuaternion q = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())*DualQuaternion::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(DualQuaternionTransformation::fromMatrix(m), q); + CORRADE_COMPARE(Implementation::Transformation::fromMatrix(m), q); } void DualQuaternionTransformationTest::toMatrix() { DualQuaternion q = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())*DualQuaternion::translation({1.0f, -0.3f, 2.3f}); Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(DualQuaternionTransformation::toMatrix(q), m); + CORRADE_COMPARE(Implementation::Transformation::toMatrix(q), m); } void DualQuaternionTransformationTest::compose() { DualQuaternion parent = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis()); DualQuaternion child = DualQuaternion::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(DualQuaternionTransformation::compose(parent, child), parent*child); + CORRADE_COMPARE(Implementation::Transformation::compose(parent, child), parent*child); } void DualQuaternionTransformationTest::inverted() { DualQuaternion q = DualQuaternion::rotation(Deg(17.0f), Vector3::xAxis())*DualQuaternion::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(DualQuaternionTransformation::inverted(q)*q, DualQuaternion()); + CORRADE_COMPARE(Implementation::Transformation::inverted(q)*q, DualQuaternion()); } void DualQuaternionTransformationTest::setTransformation() { diff --git a/src/SceneGraph/Test/MatrixTransformation2DTest.cpp b/src/SceneGraph/Test/MatrixTransformation2DTest.cpp index d997a0f17..b1408956e 100644 --- a/src/SceneGraph/Test/MatrixTransformation2DTest.cpp +++ b/src/SceneGraph/Test/MatrixTransformation2DTest.cpp @@ -67,23 +67,23 @@ MatrixTransformation2DTest::MatrixTransformation2DTest() { void MatrixTransformation2DTest::fromMatrix() { Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(MatrixTransformation2D::fromMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::fromMatrix(m), m); } void MatrixTransformation2DTest::toMatrix() { Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(MatrixTransformation2D::toMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::toMatrix(m), m); } void MatrixTransformation2DTest::compose() { Matrix3 parent = Matrix3::rotation(Deg(17.0f)); Matrix3 child = Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(MatrixTransformation2D::compose(parent, child), parent*child); + CORRADE_COMPARE(Implementation::Transformation::compose(parent, child), parent*child); } void MatrixTransformation2DTest::inverted() { Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(MatrixTransformation2D::inverted(m)*m, Matrix3()); + CORRADE_COMPARE(Implementation::Transformation::inverted(m)*m, Matrix3()); } void MatrixTransformation2DTest::setTransformation() { diff --git a/src/SceneGraph/Test/MatrixTransformation3DTest.cpp b/src/SceneGraph/Test/MatrixTransformation3DTest.cpp index ab9f3f97d..66240a318 100644 --- a/src/SceneGraph/Test/MatrixTransformation3DTest.cpp +++ b/src/SceneGraph/Test/MatrixTransformation3DTest.cpp @@ -67,23 +67,23 @@ MatrixTransformation3DTest::MatrixTransformation3DTest() { void MatrixTransformation3DTest::fromMatrix() { Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); - CORRADE_COMPARE(MatrixTransformation3D::fromMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::fromMatrix(m), m); } void MatrixTransformation3DTest::toMatrix() { Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); - CORRADE_COMPARE(MatrixTransformation3D::toMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::toMatrix(m), m); } void MatrixTransformation3DTest::compose() { Matrix4 parent = Matrix4::rotationX(Deg(17.0f)); Matrix4 child = Matrix4::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(MatrixTransformation3D::compose(parent, child), parent*child); + CORRADE_COMPARE(Implementation::Transformation::compose(parent, child), parent*child); } void MatrixTransformation3DTest::inverted() { Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); - CORRADE_COMPARE(MatrixTransformation3D::inverted(m)*m, Matrix4()); + CORRADE_COMPARE(Implementation::Transformation::inverted(m)*m, Matrix4()); } void MatrixTransformation3DTest::setTransformation() { diff --git a/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp index b362e97de..f33537c2f 100644 --- a/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp +++ b/src/SceneGraph/Test/RigidMatrixTransformation2DTest.cpp @@ -69,27 +69,27 @@ RigidMatrixTransformation2DTest::RigidMatrixTransformation2DTest() { void RigidMatrixTransformation2DTest::fromMatrix() { std::ostringstream o; Error::setOutput(&o); - RigidMatrixTransformation2D::fromMatrix(Matrix3::scaling(Vector2(4.0f))); - CORRADE_COMPARE(o.str(), "SceneGraph::RigidMatrixTransformation2D::fromMatrix(): the matrix doesn't represent rigid transformation\n"); + Implementation::Transformation::fromMatrix(Matrix3::scaling(Vector2(4.0f))); + CORRADE_COMPARE(o.str(), "SceneGraph::RigidMatrixTransformation2D: the matrix doesn't represent rigid transformation\n"); Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(RigidMatrixTransformation2D::fromMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::fromMatrix(m), m); } void RigidMatrixTransformation2DTest::toMatrix() { Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(RigidMatrixTransformation2D::toMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::toMatrix(m), m); } void RigidMatrixTransformation2DTest::compose() { Matrix3 parent = Matrix3::rotation(Deg(17.0f)); Matrix3 child = Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(RigidMatrixTransformation2D::compose(parent, child), parent*child); + CORRADE_COMPARE(Implementation::Transformation::compose(parent, child), parent*child); } void RigidMatrixTransformation2DTest::inverted() { Matrix3 m = Matrix3::rotation(Deg(17.0f))*Matrix3::translation({1.0f, -0.3f}); - CORRADE_COMPARE(RigidMatrixTransformation2D::inverted(m)*m, Matrix3()); + CORRADE_COMPARE(Implementation::Transformation::inverted(m)*m, Matrix3()); } void RigidMatrixTransformation2DTest::setTransformation() { diff --git a/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp index fd1a464b0..d6cf466a7 100644 --- a/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp +++ b/src/SceneGraph/Test/RigidMatrixTransformation3DTest.cpp @@ -69,27 +69,27 @@ RigidMatrixTransformation3DTest::RigidMatrixTransformation3DTest() { void RigidMatrixTransformation3DTest::fromMatrix() { std::ostringstream o; Error::setOutput(&o); - RigidMatrixTransformation3D::fromMatrix(Matrix4::scaling(Vector3(4.0f))); - CORRADE_COMPARE(o.str(), "SceneGraph::RigidMatrixTransformation3D::fromMatrix(): the matrix doesn't represent rigid transformation\n"); + Implementation::Transformation::fromMatrix(Matrix4::scaling(Vector3(4.0f))); + CORRADE_COMPARE(o.str(), "SceneGraph::RigidMatrixTransformation3D: the matrix doesn't represent rigid transformation\n"); Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(RigidMatrixTransformation3D::fromMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::fromMatrix(m), m); } void RigidMatrixTransformation3DTest::toMatrix() { Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(RigidMatrixTransformation3D::toMatrix(m), m); + CORRADE_COMPARE(Implementation::Transformation::toMatrix(m), m); } void RigidMatrixTransformation3DTest::compose() { Matrix4 parent = Matrix4::rotationX(Deg(17.0f)); Matrix4 child = Matrix4::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(RigidMatrixTransformation3D::compose(parent, child), parent*child); + CORRADE_COMPARE(Implementation::Transformation::compose(parent, child), parent*child); } void RigidMatrixTransformation3DTest::inverted() { Matrix4 m = Matrix4::rotationX(Deg(17.0f))*Matrix4::translation({1.0f, -0.3f, 2.3f}); - CORRADE_COMPARE(RigidMatrixTransformation3D::inverted(m)*m, Matrix4()); + CORRADE_COMPARE(Implementation::Transformation::inverted(m)*m, Matrix4()); } void RigidMatrixTransformation3DTest::setTransformation() {