From 2734fde59393725f6ed1832fb65e5232f56ec854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 18 Dec 2012 13:49:42 +0100 Subject: [PATCH] SceneGraph: euclidean transformation using matrices. Allows for faster computation of inverted transformations. --- src/SceneGraph/CMakeLists.txt | 6 +- .../EuclideanMatrixTransformation2D.cpp | 26 +++ .../EuclideanMatrixTransformation2D.h | 138 ++++++++++++++ .../EuclideanMatrixTransformation3D.cpp | 26 +++ .../EuclideanMatrixTransformation3D.h | 168 ++++++++++++++++++ src/SceneGraph/MatrixTransformation2D.h | 2 +- src/SceneGraph/MatrixTransformation3D.h | 2 +- src/SceneGraph/Object.h | 2 + src/SceneGraph/SceneGraph.h | 3 + 9 files changed, 370 insertions(+), 3 deletions(-) create mode 100644 src/SceneGraph/EuclideanMatrixTransformation2D.cpp create mode 100644 src/SceneGraph/EuclideanMatrixTransformation2D.h create mode 100644 src/SceneGraph/EuclideanMatrixTransformation3D.cpp create mode 100644 src/SceneGraph/EuclideanMatrixTransformation3D.h diff --git a/src/SceneGraph/CMakeLists.txt b/src/SceneGraph/CMakeLists.txt index 5348905bf..d8f3b047a 100644 --- a/src/SceneGraph/CMakeLists.txt +++ b/src/SceneGraph/CMakeLists.txt @@ -1,6 +1,8 @@ set(MagnumSceneGraph_SRCS Animable.cpp - Camera.cpp) + Camera.cpp + EuclideanMatrixTransformation2D.cpp + EuclideanMatrixTransformation3D.cpp) set(MagnumSceneGraph_HEADERS AbstractCamera.h AbstractCamera.hpp @@ -20,6 +22,8 @@ set(MagnumSceneGraph_HEADERS Camera3D.h Camera3D.hpp Drawable.h + EuclideanMatrixTransformation2D.h + EuclideanMatrixTransformation3D.h FeatureGroup.h MatrixTransformation2D.h MatrixTransformation3D.h diff --git a/src/SceneGraph/EuclideanMatrixTransformation2D.cpp b/src/SceneGraph/EuclideanMatrixTransformation2D.cpp new file mode 100644 index 000000000..589b0f569 --- /dev/null +++ b/src/SceneGraph/EuclideanMatrixTransformation2D.cpp @@ -0,0 +1,26 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "EuclideanMatrixTransformation2D.h" + +#include "Object.hpp" + +namespace Magnum { namespace SceneGraph { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +#endif + +}} diff --git a/src/SceneGraph/EuclideanMatrixTransformation2D.h b/src/SceneGraph/EuclideanMatrixTransformation2D.h new file mode 100644 index 000000000..1eb73381b --- /dev/null +++ b/src/SceneGraph/EuclideanMatrixTransformation2D.h @@ -0,0 +1,138 @@ +#ifndef Magnum_SceneGraph_EuclideanMatrixTransformation2D_h +#define Magnum_SceneGraph_EuclideanMatrixTransformation2D_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::SceneGraph::EuclideanMatrixTransformation2D + */ + +#include "Math/Matrix3.h" +#include "AbstractTranslationRotation2D.h" +#include "Object.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Two-dimensional euclidean transformation implemented using matrices + +Unlike MatrixTransformation2D this class allows only rotation, reflection and +translation (no scaling or setting arbitrary transformations). This allows to +use Matrix3::invertedEuclidean() for faster computation of inverse +transformations. +@see @ref scenegraph, EuclideanMatrixTransformation3D +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class EuclideanMatrixTransformation2D: public AbstractTranslationRotation2D { + public: + /** @brief Transformation matrix type */ + typedef typename DimensionTraits<2, T>::MatrixType DataType; + + #ifndef DOXYGEN_GENERATING_OUTPUT + inline constexpr static Math::Matrix3 fromMatrix(const Math::Matrix3& matrix) { + return matrix; + } + + inline constexpr static Math::Matrix3 toMatrix(const Math::Matrix3& transformation) { + return transformation; + } + + inline static Math::Matrix3 compose(const Math::Matrix3& parent, const Math::Matrix3& child) { + return parent*child; + } + + inline static Math::Matrix3 inverted(const Math::Matrix3& transformation) { + return transformation.invertedEuclidean(); + } + + inline Math::Matrix3 transformation() const { + return _transformation; + } + #endif + + /** + * @brief Reset transformation to default + * @return Pointer to self (for method chaining) + */ + inline EuclideanMatrixTransformation2D* resetTransformation() { + setTransformation({}); + return this; + } + + /** @copydoc AbstractTranslationRotation2D::translate() */ + inline EuclideanMatrixTransformation2D* translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) override { + transform(Math::Matrix3::translation(vector), type); + return this; + } + + /** @copydoc AbstractTranslationRotation2D::rotate() */ + inline EuclideanMatrixTransformation2D* rotate(T angle, TransformationType type = TransformationType::Global) override { + transform(Math::Matrix3::rotation(angle), type); + return this; + } + + /** + * @brief Reflect object + * @param normal Normal of the line through which to reflect + * (normalized) + * @param type Transformation type + * @return Pointer to self (for method chaining) + */ + inline EuclideanMatrixTransformation2D* reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { + transform(Math::Matrix3::reflection(normal), type); + return this; + } + + /** + * @brief Move object in stacking order + * @param under Sibling object under which to move or `nullptr`, + * if you want to move it above all. + * @return Pointer to self (for method chaining) + */ + inline EuclideanMatrixTransformation2D* move(Object>* under) { + static_cast*>(this)->Corrade::Containers::LinkedList>>::move(this, under); + return this; + } + + protected: + /* Allow construction only from Object */ + inline explicit EuclideanMatrixTransformation2D() = default; + + private: + inline void setTransformation(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? */ + if(!static_cast>*>(this)->isScene()) { + _transformation = transformation; + static_cast>*>(this)->setDirty(); + } + } + + inline void transform(const Math::Matrix3& transformation, TransformationType type) { + setTransformation(type == TransformationType::Global ? + transformation*_transformation : _transformation*transformation); + } + + Math::Matrix3 _transformation; +}; + +}} + +#endif diff --git a/src/SceneGraph/EuclideanMatrixTransformation3D.cpp b/src/SceneGraph/EuclideanMatrixTransformation3D.cpp new file mode 100644 index 000000000..f670329ce --- /dev/null +++ b/src/SceneGraph/EuclideanMatrixTransformation3D.cpp @@ -0,0 +1,26 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "EuclideanMatrixTransformation3D.h" + +#include "Object.hpp" + +namespace Magnum { namespace SceneGraph { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SCENEGRAPH_EXPORT Object>; +#endif + +}} diff --git a/src/SceneGraph/EuclideanMatrixTransformation3D.h b/src/SceneGraph/EuclideanMatrixTransformation3D.h new file mode 100644 index 000000000..45e2ba8b0 --- /dev/null +++ b/src/SceneGraph/EuclideanMatrixTransformation3D.h @@ -0,0 +1,168 @@ +#ifndef Magnum_SceneGraph_EuclideanMatrixTransformation3D_h +#define Magnum_SceneGraph_EuclideanMatrixTransformation3D_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::SceneGraph::EuclideanMatrixTransformation3D + */ + +#include "Math/Matrix4.h" +#include "AbstractTranslationRotation3D.h" +#include "Object.h" + +namespace Magnum { namespace SceneGraph { + +/** +@brief Three-dimensional euclidean transformation implemented using matrices + +Unlike MatrixTransformation3D this class allows only rotation, reflection and +translation (no scaling or setting arbitrary transformations). This allows to +use Matrix4::invertedEuclidean() for faster computation of inverse +transformations. +@see @ref scenegraph, EuclideanMatrixTransformation2D +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template +#else +template +#endif +class EuclideanMatrixTransformation3D: public AbstractTranslationRotation3D { + public: + /** @brief Transformation matrix type */ + typedef typename DimensionTraits<3, T>::MatrixType DataType; + + #ifndef DOXYGEN_GENERATING_OUTPUT + inline constexpr static Math::Matrix4 fromMatrix(const Math::Matrix4& matrix) { + return matrix; + } + + inline constexpr static Math::Matrix4 toMatrix(const Math::Matrix4& transformation) { + return transformation; + } + + inline static Math::Matrix4 compose(const Math::Matrix4& parent, const Math::Matrix4& child) { + return parent*child; + } + + inline static Math::Matrix4 inverted(const Math::Matrix4& transformation) { + return transformation.invertedEuclidean(); + } + + inline Math::Matrix4 transformation() const { + return _transformation; + } + #endif + + /** + * @brief Reset transformation to default + * @return Pointer to self (for method chaining) + */ + inline EuclideanMatrixTransformation3D* resetTransformation() { + setTransformation({}); + return this; + } + + /** @copydoc AbstractTranslationRotation3D::translate() */ + inline EuclideanMatrixTransformation3D* translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) override { + transform(Math::Matrix4::translation(vector), type); + return this; + } + + /** @copydoc AbstractTranslationRotation3D::rotate() */ + inline EuclideanMatrixTransformation3D* rotate(T angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) override { + transform(Math::Matrix4::rotation(angle, normalizedAxis), type); + return this; + } + + /** + * @brief Rotate object around X axis + * @param angle Angle in radians, counterclockwise + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * @see deg(), rad() + */ + inline EuclideanMatrixTransformation3D* rotateX(T angle, TransformationType type = TransformationType::Global) override { + transform(Math::Matrix4::rotationX(angle), type); + return this; + } + + /** + * @brief Rotate object around Y axis + * @param angle Angle in radians, counterclockwise + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * @see deg(), rad() + */ + inline EuclideanMatrixTransformation3D* rotateY(T angle, TransformationType type = TransformationType::Global) override { + transform(Math::Matrix4::rotationY(angle), type); + return this; + } + + /** + * @brief Rotate object around Z axis + * @param angle Angle in radians, counterclockwise + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * @see deg(), rad() + */ + inline EuclideanMatrixTransformation3D* rotateZ(T angle, TransformationType type = TransformationType::Global) override { + transform(Math::Matrix4::rotationZ(angle), type); + return this; + } + + /** + * @brief Reflect object + * @param normal Normal of the plane through which to reflect + * (normalized) + * @param type Transformation type + * @return Pointer to self (for method chaining) + * + * Same as calling transform() with Matrix4::reflection(). + */ + inline EuclideanMatrixTransformation3D* reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { + transform(Math::Matrix4::reflection(normal), type); + return this; + } + + protected: + /* Allow construction only from Object */ + inline explicit EuclideanMatrixTransformation3D() = default; + + private: + inline void setTransformation(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? */ + if(!static_cast>*>(this)->isScene()) { + _transformation = transformation; + static_cast>*>(this)->setDirty(); + } + } + + inline void transform(const Math::Matrix4& transformation, TransformationType type) { + setTransformation(type == TransformationType::Global ? + transformation*_transformation : _transformation*transformation); + } + + Math::Matrix4 _transformation; +}; + +}} + +#endif diff --git a/src/SceneGraph/MatrixTransformation2D.h b/src/SceneGraph/MatrixTransformation2D.h index 9ecb37a70..fa469bc42 100644 --- a/src/SceneGraph/MatrixTransformation2D.h +++ b/src/SceneGraph/MatrixTransformation2D.h @@ -29,7 +29,7 @@ namespace Magnum { namespace SceneGraph { @brief Two-dimensional transformation implemented using matrices Uses Math::Matrix3 as underlying type. -@see @ref scenegraph, MatrixTransformation3D +@see @ref scenegraph, EuclideanMatrixTransformation2D, MatrixTransformation3D */ #ifndef DOXYGEN_GENERATING_OUTPUT template diff --git a/src/SceneGraph/MatrixTransformation3D.h b/src/SceneGraph/MatrixTransformation3D.h index c133aca7b..c5018a684 100644 --- a/src/SceneGraph/MatrixTransformation3D.h +++ b/src/SceneGraph/MatrixTransformation3D.h @@ -29,7 +29,7 @@ namespace Magnum { namespace SceneGraph { @brief Three-dimensional transformation implemented using matrices Uses Math::Matrix4 as underlying type. -@see @ref scenegraph, MatrixTransformation2D +@see @ref scenegraph, EuclideanMatrixTransformation3D, MatrixTransformation2D */ #ifndef DOXYGEN_GENERATING_OUTPUT template diff --git a/src/SceneGraph/Object.h b/src/SceneGraph/Object.h index b6f06696d..9b5efdc6f 100644 --- a/src/SceneGraph/Object.h +++ b/src/SceneGraph/Object.h @@ -73,6 +73,8 @@ avoid linker errors. See @ref compilation-speedup-hpp for more information. - @ref MatrixTransformation2D "Object>" - @ref MatrixTransformation3D "Object>" + - @ref EuclideanMatrixTransformation2D "Object>" + - @ref EuclideanMatrixTransformation3D "Object>" @see Scene, AbstractFeature, AbstractTransformation */ diff --git a/src/SceneGraph/SceneGraph.h b/src/SceneGraph/SceneGraph.h index 14fba11ca..c958654f1 100644 --- a/src/SceneGraph/SceneGraph.h +++ b/src/SceneGraph/SceneGraph.h @@ -89,6 +89,9 @@ template using Drawable2D = Drawable<2, T>; template using Drawable3D = Drawable<3, T>; #endif +template class EuclideanMatrixTransformation2D; +template class EuclideanMatrixTransformation3D; + template class FeatureGroup; #ifndef CORRADE_GCC46_COMPATIBILITY template using FeatureGroup2D = FeatureGroup<2, Feature, T>;