mirror of https://github.com/mosra/magnum.git
Browse Source
Useful for using with animation tracks that target the translation/rotation/scaling properties separately.pull/191/head
10 changed files with 1222 additions and 0 deletions
@ -0,0 +1,223 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/SceneGraph/TranslationRotationScalingTransformation2D.h" |
||||
#include "Magnum/SceneGraph/Scene.h" |
||||
|
||||
namespace Magnum { namespace SceneGraph { namespace Test { |
||||
|
||||
typedef Object<TranslationRotationScalingTransformation2D> Object2D; |
||||
typedef Scene<TranslationRotationScalingTransformation2D> Scene2D; |
||||
|
||||
struct TranslationRotationScalingTransformation2DTest: TestSuite::Tester { |
||||
explicit TranslationRotationScalingTransformation2DTest(); |
||||
|
||||
void fromMatrix(); |
||||
void toMatrix(); |
||||
void compose(); |
||||
void inverted(); |
||||
|
||||
void defaults(); |
||||
void setTransformation(); |
||||
void resetTransformation(); |
||||
|
||||
void translate(); |
||||
void rotate(); |
||||
void scale(); |
||||
}; |
||||
|
||||
TranslationRotationScalingTransformation2DTest::TranslationRotationScalingTransformation2DTest() { |
||||
addTests({&TranslationRotationScalingTransformation2DTest::fromMatrix, |
||||
&TranslationRotationScalingTransformation2DTest::toMatrix, |
||||
&TranslationRotationScalingTransformation2DTest::compose, |
||||
&TranslationRotationScalingTransformation2DTest::inverted, |
||||
|
||||
&TranslationRotationScalingTransformation2DTest::defaults, |
||||
&TranslationRotationScalingTransformation2DTest::setTransformation, |
||||
&TranslationRotationScalingTransformation2DTest::resetTransformation, |
||||
|
||||
&TranslationRotationScalingTransformation2DTest::translate, |
||||
&TranslationRotationScalingTransformation2DTest::rotate, |
||||
&TranslationRotationScalingTransformation2DTest::scale}); |
||||
} |
||||
|
||||
using namespace Math::Literals; |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::fromMatrix() { |
||||
Matrix3 m = Matrix3::rotation(17.0_degf)*Matrix3::translation({1.0f, -0.3f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation2D>::fromMatrix(m), m); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::toMatrix() { |
||||
Matrix3 m = Matrix3::rotation(17.0_degf)*Matrix3::translation({1.0f, -0.3f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation2D>::toMatrix(m), m); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::compose() { |
||||
Matrix3 parent = Matrix3::rotation(17.0_degf); |
||||
Matrix3 child = Matrix3::translation({1.0f, -0.3f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation2D>::compose(parent, child), parent*child); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::inverted() { |
||||
Matrix3 m = Matrix3::rotation(17.0_degf)*Matrix3::translation({1.0f, -0.3f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation2D>::inverted(m)*m, Matrix3()); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::defaults() { |
||||
Object2D o; |
||||
CORRADE_COMPARE(o.translation(), Vector2{}); |
||||
CORRADE_COMPARE(o.rotation(), Complex{}); |
||||
CORRADE_COMPARE(o.scaling(), Vector2{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), Matrix3{}); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::setTransformation() { |
||||
/* Dirty after setting transformation */ |
||||
Object2D o; |
||||
o.setClean(); |
||||
CORRADE_VERIFY(!o.isDirty()); |
||||
o.setTransformation( |
||||
Matrix3::translation({7.0f, -1.0f})* |
||||
Matrix3::rotation(17.0_degf)* |
||||
Matrix3::scaling({1.5f, 0.5f})); |
||||
CORRADE_VERIFY(o.isDirty()); |
||||
CORRADE_COMPARE(o.translation(), (Vector2{7.0f, -1.0f})); |
||||
CORRADE_COMPARE(o.rotation(), Complex::rotation(17.0_degf)); |
||||
CORRADE_COMPARE(o.scaling(), (Vector2{1.5f, 0.5f})); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix3::translation({7.0f, -1.0f})* |
||||
Matrix3::rotation(17.0_degf)* |
||||
Matrix3::scaling({1.5f, 0.5f})); |
||||
|
||||
/* Scene cannot be transformed */ |
||||
Scene2D s; |
||||
s.setClean(); |
||||
CORRADE_VERIFY(!s.isDirty()); |
||||
s.setTransformation(Matrix3::rotation(17.0_degf)); |
||||
CORRADE_VERIFY(!s.isDirty()); |
||||
CORRADE_COMPARE(s.transformationMatrix(), Matrix3()); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::resetTransformation() { |
||||
Object2D o; |
||||
o.rotate(17.0_degf); |
||||
CORRADE_VERIFY(o.transformationMatrix() != Matrix3()); |
||||
o.resetTransformation(); |
||||
CORRADE_COMPARE(o.translation(), Vector2{}); |
||||
CORRADE_COMPARE(o.rotation(), Complex{}); |
||||
CORRADE_COMPARE(o.scaling(), Vector2{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), Matrix3()); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::translate() { |
||||
{ |
||||
Object2D o; |
||||
o.setTransformation(Matrix3::rotation(17.0_degf)); |
||||
o.translate({1.0f, -0.3f}) |
||||
.translate({1.0f, 0.1f}); |
||||
CORRADE_COMPARE(o.translation(), (Vector2{2.0f, -0.2f})); |
||||
CORRADE_COMPARE(o.rotation(), Complex::rotation(17.0_degf)); |
||||
CORRADE_COMPARE(o.scaling(), Vector2{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix3::translation({1.0f, 0.1f})* |
||||
Matrix3::translation({1.0f, -0.3f})* |
||||
Matrix3::rotation(17.0_degf)); |
||||
} { |
||||
Object2D o; |
||||
o.setTransformation(Matrix3::rotation(17.0_degf)); |
||||
o.translateLocal({1.0f, -0.3f}) |
||||
.translateLocal({1.0f, 0.1f}); |
||||
CORRADE_COMPARE(o.translation(), (Vector2{2.0f, -0.2f})); |
||||
CORRADE_COMPARE(o.rotation(), Complex::rotation(17.0_degf)); |
||||
CORRADE_COMPARE(o.scaling(), Vector2{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix3::translation({1.0f, -0.3f})* |
||||
Matrix3::translation({1.0f, 0.1f})* |
||||
Matrix3::rotation(17.0_degf)); |
||||
} |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::rotate() { |
||||
{ |
||||
Object2D o; |
||||
o.setTransformation(Matrix3::translation({1.0f, -0.3f})); |
||||
o.rotate(17.0_degf) |
||||
.rotate(-96.0_degf); |
||||
CORRADE_COMPARE(o.translation(), (Vector2{1.0f, -0.3f})); |
||||
CORRADE_COMPARE(o.rotation(), Complex::rotation(-79.0_degf)); |
||||
CORRADE_COMPARE(o.scaling(), Vector2{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix3::translation({1.0f, -0.3f})* |
||||
Matrix3::rotation(-96.0_degf)* |
||||
Matrix3::rotation(17.0_degf)); |
||||
} { |
||||
Object2D o; |
||||
o.setTransformation(Matrix3::translation({1.0f, -0.3f})); |
||||
o.rotateLocal(17.0_degf) |
||||
.rotateLocal(-96.0_degf); |
||||
CORRADE_COMPARE(o.translation(), (Vector2{1.0f, -0.3f})); |
||||
CORRADE_COMPARE(o.rotation(), Complex::rotation(-79.0_degf)); |
||||
CORRADE_COMPARE(o.scaling(), Vector2{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix3::translation({1.0f, -0.3f})* |
||||
Matrix3::rotation(17.0_degf)* |
||||
Matrix3::rotation(-96.0_degf)); |
||||
} |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation2DTest::scale() { |
||||
{ |
||||
Object2D o; |
||||
o.setTransformation(Matrix3::rotation(17.0_degf)); |
||||
o.scale({1.0f, -0.3f}) |
||||
.scale({0.5f, 1.1f}); |
||||
CORRADE_COMPARE(o.translation(), Vector2{}); |
||||
CORRADE_COMPARE(o.rotation(), Complex::rotation(17.0_degf)); |
||||
CORRADE_COMPARE(o.scaling(), (Vector2{0.5f, -0.33f})); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix3::rotation(17.0_degf)* |
||||
Matrix3::scaling({0.5f, 1.1f})* |
||||
Matrix3::scaling({1.0f, -0.3f})); |
||||
} { |
||||
Object2D o; |
||||
o.setTransformation(Matrix3::rotation(17.0_degf)); |
||||
o.scaleLocal({1.0f, -0.3f}) |
||||
.scaleLocal({0.5f, 1.1f}); |
||||
CORRADE_COMPARE(o.translation(), Vector2{}); |
||||
CORRADE_COMPARE(o.rotation(), Complex::rotation(17.0_degf)); |
||||
CORRADE_COMPARE(o.scaling(), (Vector2{0.5f, -0.33f})); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix3::rotation(17.0_degf)* |
||||
Matrix3::scaling({1.0f, -0.3f})* |
||||
Matrix3::scaling({0.5f, 1.1f})); |
||||
} |
||||
} |
||||
|
||||
}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::TranslationRotationScalingTransformation2DTest) |
||||
@ -0,0 +1,239 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/SceneGraph/TranslationRotationScalingTransformation3D.h" |
||||
#include "Magnum/SceneGraph/Scene.h" |
||||
|
||||
namespace Magnum { namespace SceneGraph { namespace Test { |
||||
|
||||
typedef Object<TranslationRotationScalingTransformation3D> Object3D; |
||||
typedef Scene<TranslationRotationScalingTransformation3D> Scene3D; |
||||
|
||||
struct TranslationRotationScalingTransformation3DTest: TestSuite::Tester { |
||||
explicit TranslationRotationScalingTransformation3DTest(); |
||||
|
||||
void fromMatrix(); |
||||
void toMatrix(); |
||||
void compose(); |
||||
void inverted(); |
||||
|
||||
void defaults(); |
||||
void setTransformation(); |
||||
void resetTransformation(); |
||||
|
||||
void translate(); |
||||
void rotate(); |
||||
void scale(); |
||||
}; |
||||
|
||||
TranslationRotationScalingTransformation3DTest::TranslationRotationScalingTransformation3DTest() { |
||||
addTests({&TranslationRotationScalingTransformation3DTest::fromMatrix, |
||||
&TranslationRotationScalingTransformation3DTest::toMatrix, |
||||
&TranslationRotationScalingTransformation3DTest::compose, |
||||
&TranslationRotationScalingTransformation3DTest::inverted, |
||||
|
||||
&TranslationRotationScalingTransformation3DTest::defaults, |
||||
&TranslationRotationScalingTransformation3DTest::setTransformation, |
||||
&TranslationRotationScalingTransformation3DTest::resetTransformation, |
||||
|
||||
&TranslationRotationScalingTransformation3DTest::translate, |
||||
&TranslationRotationScalingTransformation3DTest::rotate, |
||||
&TranslationRotationScalingTransformation3DTest::scale}); |
||||
} |
||||
|
||||
using namespace Math::Literals; |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::fromMatrix() { |
||||
Matrix4 m = Matrix4::rotationX(17.0_degf)*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation3D>::fromMatrix(m), m); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::toMatrix() { |
||||
Matrix4 m = Matrix4::rotationX(17.0_degf)*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation3D>::toMatrix(m), m); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::compose() { |
||||
Matrix4 parent = Matrix4::rotationX(17.0_degf); |
||||
Matrix4 child = Matrix4::translation({1.0f, -0.3f, 2.3f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation3D>::compose(parent, child), parent*child); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::inverted() { |
||||
Matrix4 m = Matrix4::rotationX(17.0_degf)*Matrix4::translation({1.0f, -0.3f, 2.3f})*Matrix4::scaling({2.0f, 1.4f, -2.1f}); |
||||
CORRADE_COMPARE(Implementation::Transformation<TranslationRotationScalingTransformation3D>::inverted(m)*m, Matrix4()); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::defaults() { |
||||
Object3D o; |
||||
CORRADE_COMPARE(o.translation(), Vector3{}); |
||||
CORRADE_COMPARE(o.rotation(), Quaternion{}); |
||||
CORRADE_COMPARE(o.scaling(), Vector3{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), Matrix4{}); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::setTransformation() { |
||||
/* Dirty after setting transformation */ |
||||
Object3D o; |
||||
o.setClean(); |
||||
CORRADE_VERIFY(!o.isDirty()); |
||||
o.setTransformation( |
||||
Matrix4::translation({7.0f, -1.0f, 2.2f})* |
||||
Matrix4::rotationX(17.0_degf)* |
||||
Matrix4::scaling({1.5f, 0.5f, 3.0f})); |
||||
CORRADE_VERIFY(o.isDirty()); |
||||
CORRADE_COMPARE(o.translation(), (Vector3{7.0f, -1.0f, 2.2f})); |
||||
CORRADE_COMPARE(o.rotation(), Quaternion::rotation(17.0_degf, Vector3::xAxis())); |
||||
CORRADE_COMPARE(o.scaling(), (Vector3{1.5f, 0.5f, 3.0f})); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix4::translation({7.0f, -1.0f, 2.2f})* |
||||
Matrix4::rotationX(17.0_degf)* |
||||
Matrix4::scaling({1.5f, 0.5f, 3.0f})); |
||||
|
||||
/* Scene cannot be transformed */ |
||||
Scene3D s; |
||||
s.setClean(); |
||||
CORRADE_VERIFY(!s.isDirty()); |
||||
s.setTransformation(Matrix4::rotationX(17.0_degf)); |
||||
CORRADE_VERIFY(!s.isDirty()); |
||||
CORRADE_COMPARE(s.transformationMatrix(), Matrix4()); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::resetTransformation() { |
||||
Object3D o; |
||||
o.rotateX(17.0_degf); |
||||
CORRADE_VERIFY(o.transformationMatrix() != Matrix4()); |
||||
o.resetTransformation(); |
||||
CORRADE_COMPARE(o.translation(), Vector3{}); |
||||
CORRADE_COMPARE(o.rotation(), Quaternion{}); |
||||
CORRADE_COMPARE(o.scaling(), Vector3{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), Matrix4()); |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::translate() { |
||||
{ |
||||
Object3D o; |
||||
o.setTransformation(Matrix4::rotationX(17.0_degf)); |
||||
o.translate({1.0f, -0.3f, 2.3f}) |
||||
.translate({1.0f, 0.1f, 0.2f}); |
||||
CORRADE_COMPARE(o.translation(), (Vector3{2.0f, -0.2f, 2.5f})); |
||||
CORRADE_COMPARE(o.rotation(), Quaternion::rotation(17.0_degf, Vector3::xAxis())); |
||||
CORRADE_COMPARE(o.scaling(), Vector3{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix4::translation({1.0f, 0.1f, 0.2f})* |
||||
Matrix4::translation({1.0f, -0.3f, 2.3f})* |
||||
Matrix4::rotationX(17.0_degf)); |
||||
} { |
||||
Object3D o; |
||||
o.setTransformation(Matrix4::rotationX(17.0_degf)); |
||||
o.translateLocal({1.0f, -0.3f, 2.3f}) |
||||
.translateLocal({1.0f, 0.1f, 0.2f}); |
||||
CORRADE_COMPARE(o.translation(), (Vector3{2.0f, -0.2f, 2.5f})); |
||||
CORRADE_COMPARE(o.rotation(), Quaternion::rotation(17.0_degf, Vector3::xAxis())); |
||||
CORRADE_COMPARE(o.scaling(), Vector3{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix4::translation({1.0f, -0.3f, 2.3f})* |
||||
Matrix4::translation({1.0f, 0.1f, 0.2f})* |
||||
Matrix4::rotationX(17.0_degf)); |
||||
} |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::rotate() { |
||||
{ |
||||
Object3D o; |
||||
o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); |
||||
o.rotateX(17.0_degf) |
||||
.rotateY(25.0_degf) |
||||
.rotateZ(-23.0_degf) |
||||
.rotate(96.0_degf, Vector3{1.0f/Constants::sqrt3()}); |
||||
CORRADE_COMPARE(o.translation(), (Vector3{1.0f, -0.3f, 2.3f})); |
||||
CORRADE_COMPARE(o.rotation(), |
||||
Quaternion::rotation(96.0_degf, Vector3{1.0f/Constants::sqrt3()})* |
||||
Quaternion::rotation(-23.0_degf, Vector3::zAxis())* |
||||
Quaternion::rotation(25.0_degf, Vector3::yAxis())* |
||||
Quaternion::rotation(17.0_degf, Vector3::xAxis())); |
||||
CORRADE_COMPARE(o.scaling(), Vector3{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix4::translation({1.0f, -0.3f, 2.3f})* |
||||
Matrix4::rotation(96.0_degf, Vector3{1.0f/Constants::sqrt3()})* |
||||
Matrix4::rotationZ(-23.0_degf)* |
||||
Matrix4::rotationY(25.0_degf)* |
||||
Matrix4::rotationX(17.0_degf)); |
||||
} { |
||||
Object3D o; |
||||
o.setTransformation(Matrix4::translation({1.0f, -0.3f, 2.3f})); |
||||
o.rotateXLocal(17.0_degf) |
||||
.rotateYLocal(25.0_degf) |
||||
.rotateZLocal(-23.0_degf) |
||||
.rotateLocal(96.0_degf, Vector3{1.0f/Constants::sqrt3()}); |
||||
CORRADE_COMPARE(o.translation(), (Vector3{1.0f, -0.3f, 2.3f})); |
||||
CORRADE_COMPARE(o.rotation(), |
||||
Quaternion::rotation(17.0_degf, Vector3::xAxis())* |
||||
Quaternion::rotation(25.0_degf, Vector3::yAxis())* |
||||
Quaternion::rotation(-23.0_degf, Vector3::zAxis())* |
||||
Quaternion::rotation(96.0_degf, Vector3(1.0f/Constants::sqrt3()))); |
||||
CORRADE_COMPARE(o.scaling(), Vector3{1.0f}); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix4::translation({1.0f, -0.3f, 2.3f})* |
||||
Matrix4::rotationX(17.0_degf)* |
||||
Matrix4::rotationY(25.0_degf)* |
||||
Matrix4::rotationZ(-23.0_degf)* |
||||
Matrix4::rotation(96.0_degf, Vector3{1.0f/Constants::sqrt3()})); |
||||
} |
||||
} |
||||
|
||||
void TranslationRotationScalingTransformation3DTest::scale() { |
||||
{ |
||||
Object3D o; |
||||
o.setTransformation(Matrix4::rotationX(17.0_degf)); |
||||
o.scale({1.0f, -0.3f, 2.3f}) |
||||
.scale({0.5f, 1.1f, 2.0f}); |
||||
CORRADE_COMPARE(o.translation(), Vector3{}); |
||||
CORRADE_COMPARE(o.rotation(), Quaternion::rotation(17.0_degf, Vector3::xAxis())); |
||||
CORRADE_COMPARE(o.scaling(), (Vector3{0.5f, -0.33f, 4.6f})); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix4::rotationX(17.0_degf)* |
||||
Matrix4::scaling({0.5f, 1.1f, 2.0f})* |
||||
Matrix4::scaling({1.0f, -0.3f, 2.3f})); |
||||
} { |
||||
Object3D o; |
||||
o.setTransformation(Matrix4::rotationX(17.0_degf)); |
||||
o.scaleLocal({1.0f, -0.3f, 2.3f}) |
||||
.scaleLocal({0.5f, 1.1f, 2.0f}); |
||||
CORRADE_COMPARE(o.translation(), Vector3{}); |
||||
CORRADE_COMPARE(o.rotation(), Quaternion::rotation(17.0_degf, Vector3::xAxis())); |
||||
CORRADE_COMPARE(o.scaling(), (Vector3{0.5f, -0.33f, 4.6f})); |
||||
CORRADE_COMPARE(o.transformationMatrix(), |
||||
Matrix4::rotationX(17.0_degf)* |
||||
Matrix4::scaling({1.0f, -0.3f, 2.3f})* |
||||
Matrix4::scaling({0.5f, 1.1f, 2.0f})); |
||||
} |
||||
} |
||||
|
||||
}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::TranslationRotationScalingTransformation3DTest) |
||||
@ -0,0 +1,320 @@
|
||||
#ifndef Magnum_SceneGraph_TranslationRotationScalingTransformation2D_h |
||||
#define Magnum_SceneGraph_TranslationRotationScalingTransformation2D_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class @ref Magnum::SceneGraph::BasicTranslationRotationScalingTransformation2D, typedef @ref Magnum::SceneGraph::TranslationRotationScalingTransformation2D |
||||
*/ |
||||
|
||||
#include "Magnum/Math/Complex.h" |
||||
#include "Magnum/Math/Matrix3.h" |
||||
#include "Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h" |
||||
#include "Magnum/SceneGraph/Object.h" |
||||
|
||||
namespace Magnum { namespace SceneGraph { |
||||
|
||||
/**
|
||||
@brief Two-dimensional transformation implemented using translation, rotation and scaling |
||||
|
||||
Similar to @ref BasicMatrixTransformation2D, but stores translation, rotation |
||||
and scaling separately. This makes it more suitable for e.g. animation, where |
||||
there are usually separate animation tracks for translation, rotation and |
||||
scaling. This separation also imposes some constraints --- for given object, |
||||
scaling is always applied first, rotation second and translation last. In |
||||
particular, unlike with matrix-based transformation implementation, it's not |
||||
possible to rotate a translated object, for example --- one has to apply the |
||||
rotation first and then translate using a rotated vector. |
||||
@see @ref scenegraph, @ref TranslationRotationScalingTransformation2D, |
||||
@ref BasicTranslationRotationScalingTransformation3D |
||||
*/ |
||||
template<class T> class BasicTranslationRotationScalingTransformation2D: public AbstractBasicTranslationRotationScaling2D<T> { |
||||
public: |
||||
/** @brief Underlying transformation type */ |
||||
typedef Math::Matrix3<T> DataType; |
||||
|
||||
/** @brief Object transformation */ |
||||
Math::Matrix3<T> transformation() const; |
||||
|
||||
/**
|
||||
* @brief Set transformation |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Expects that the transformation doesn't contain shear or reflection. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& setTransformation(const Math::Matrix3<T>& transformation); |
||||
|
||||
/** @brief Object translation */ |
||||
Math::Vector2<T> translation() const { return _translation; } |
||||
|
||||
/**
|
||||
* @brief Set translation |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Translation is always applied last, after rotation and scaling. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& setTranslation(const Math::Vector2<T>& translation); |
||||
|
||||
/** @brief Object rotation */ |
||||
Math::Complex<T> rotation() const { return _rotation; } |
||||
|
||||
/**
|
||||
* @brief Set rotation |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Rotation is always applied after scaling and before translation. |
||||
* Expects that the quaternion is normalized. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& setRotation(const Math::Complex<T>& rotation); |
||||
|
||||
/** @brief Object scaling */ |
||||
Math::Vector2<T> scaling() const { return _scaling; } |
||||
|
||||
/**
|
||||
* @brief Set scaling |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Scaling is always applied first, before rotation and translation. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& setScaling(const Math::Vector2<T>& scaling); |
||||
|
||||
/** @copydoc AbstractTranslationRotationScaling2D::resetTransformation() */ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& resetTransformation() { |
||||
return setTransformation({}); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Translate object |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Note that translation is always applied last, after rotation and |
||||
* scaling. |
||||
* @see @ref translateLocal(), @ref Math::Vector2::xAxis(), |
||||
* @ref Math::Vector2::yAxis() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& translate(const Math::Vector2<T>& vector) { |
||||
return setTranslation(vector + _translation); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Translate object as a local transformation |
||||
* |
||||
* Equivalent to the above, as translation is commutative. Note that |
||||
* translation is always applied last, after rotation and scaling. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& translateLocal(const Math::Vector2<T>& vector) { |
||||
return setTranslation(_translation + vector); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object using a complex number |
||||
* @param complex Normalized complex number |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Note that rotation is always applied after scaling and before |
||||
* translation. Expects that the complex number is normalized. |
||||
* @see @ref rotate(Math::Rad<T>), |
||||
* @ref rotateLocal(const Math::Complex<T>&) |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& rotate(const Math::Complex<T>& complex) { |
||||
return setRotation(complex*_rotation); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object using a complex number as a local transformation |
||||
* |
||||
* Equivalent to the above, as 2D rotation is commutative. Note that |
||||
* rotation is always applied after scaling and before translation. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& rotateLocal(const Math::Complex<T>& complex) { |
||||
return setRotation(_rotation*complex); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object |
||||
* @param angle Angle (counterclockwise) |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Same as calling @ref rotate(const Math::Complex<T>&) with |
||||
* @ref Math::Complex::rotation(). Note that rotation is always applied after |
||||
* scaling and before translation. |
||||
* @see @ref rotateLocal() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& rotate(Math::Rad<T> angle) { |
||||
return rotate(Math::Complex<T>::rotation(angle)); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object as a local transformation |
||||
* |
||||
* Similar to the above, except that the rotation is applied before all |
||||
* other rotations. Note that rotation is always applied after scaling |
||||
* and before translation. Same as calling |
||||
* @ref rotateLocal(const Math::Complex<T>&) with |
||||
* @ref Math::Complex::rotation(). |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& rotateLocal(Math::Rad<T> angle) { |
||||
return rotateLocal(Math::Complex<T>::rotation(angle)); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Scale object |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Note that scaling is always applied first, before rotation and |
||||
* translation. |
||||
* @see @ref scaleLocal(), @ref Math::Vector2::xScale(), |
||||
* @ref Math::Vector2::yScale() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& scale(const Math::Vector2<T>& vector) { |
||||
return setScaling(vector*_scaling); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Scale object as a local transformation |
||||
* |
||||
* Equivalent to the above, as scaling is commutative. Note that |
||||
* scaling is always first, before rotation and translation. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation2D<T>>& scaleLocal(const Math::Vector2<T>& vector) { |
||||
return setScaling(_scaling*vector); |
||||
} |
||||
|
||||
protected: |
||||
/* Allow construction only from Object */ |
||||
explicit BasicTranslationRotationScalingTransformation2D() = default; |
||||
|
||||
private: |
||||
void doResetTransformation() override final { resetTransformation(); } |
||||
|
||||
void doTranslate(const Math::Vector2<T>& vector) override final { translate(vector); } |
||||
void doTranslateLocal(const Math::Vector2<T>& vector) override final { translateLocal(vector); } |
||||
|
||||
void doRotate(Math::Rad<T> angle) override final { |
||||
rotate(angle); |
||||
} |
||||
void doRotateLocal(Math::Rad<T> angle) override final { |
||||
rotateLocal(angle); |
||||
} |
||||
|
||||
void doScale(const Math::Vector2<T>& vector) override final { scale(vector); } |
||||
void doScaleLocal(const Math::Vector2<T>& vector) override final { scaleLocal(vector); } |
||||
|
||||
Math::Vector2<T> _translation; |
||||
Math::Complex<T> _rotation; |
||||
Math::Vector2<T> _scaling{T(1)}; |
||||
}; |
||||
|
||||
/**
|
||||
@brief Two-dimensional transformation for float scenes implemented using translation, rotation and scaling |
||||
|
||||
@see @ref TranslationRotationScalingTransformation3D |
||||
*/ |
||||
typedef BasicTranslationRotationScalingTransformation2D<Float> TranslationRotationScalingTransformation2D; |
||||
|
||||
template<class T> Math::Matrix3<T> BasicTranslationRotationScalingTransformation2D<T>::transformation() const { |
||||
return Math::Matrix3<T>::from(_rotation.toMatrix(), _translation)* |
||||
Math::Matrix3<T>::scaling(_scaling); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation2D<T>>& BasicTranslationRotationScalingTransformation2D<T>::setTransformation(const Math::Matrix3<T>& 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<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->isScene()) { |
||||
_translation = transformation.translation(); |
||||
_rotation = Math::Complex<T>::fromMatrix(transformation.rotationShear()); |
||||
_scaling = transformation.scaling(); |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>&>(*this); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation2D<T>>& BasicTranslationRotationScalingTransformation2D<T>::setTranslation(const Math::Vector2<T>& translation) { |
||||
/* 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<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->isScene()) { |
||||
_translation = translation; |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>&>(*this); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation2D<T>>& BasicTranslationRotationScalingTransformation2D<T>::setRotation(const Math::Complex<T>& rotation) { |
||||
/* 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<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->isScene()) { |
||||
_rotation = rotation; |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>&>(*this); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation2D<T>>& BasicTranslationRotationScalingTransformation2D<T>::setScaling(const Math::Vector2<T>& scaling) { |
||||
/* 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<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->isScene()) { |
||||
_scaling = scaling; |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation2D<T>>&>(*this); |
||||
} |
||||
|
||||
namespace Implementation { |
||||
|
||||
template<class T> struct Transformation<BasicTranslationRotationScalingTransformation2D<T>> { |
||||
constexpr static Math::Matrix3<T> fromMatrix(const Math::Matrix3<T>& matrix) { |
||||
return matrix; |
||||
} |
||||
|
||||
constexpr static Math::Matrix3<T> toMatrix(const Math::Matrix3<T>& transformation) { |
||||
return transformation; |
||||
} |
||||
|
||||
static Math::Matrix3<T> compose(const Math::Matrix3<T>& parent, const Math::Matrix3<T>& child) { |
||||
return parent*child; |
||||
} |
||||
|
||||
static Math::Matrix3<T> inverted(const Math::Matrix3<T>& transformation) { |
||||
return transformation.inverted(); |
||||
} |
||||
}; |
||||
|
||||
} |
||||
|
||||
#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__) |
||||
extern template class MAGNUM_SCENEGRAPH_EXPORT Object<BasicTranslationRotationScalingTransformation2D<Float>>; |
||||
#endif |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,410 @@
|
||||
#ifndef Magnum_SceneGraph_TranslationRotationScalingTransformation3D_h |
||||
#define Magnum_SceneGraph_TranslationRotationScalingTransformation3D_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class @ref Magnum::SceneGraph::BasicTranslationRotationScalingTransformation3D, typedef @ref Magnum::SceneGraph::TranslationRotationScalingTransformation3D |
||||
*/ |
||||
|
||||
#include "Magnum/Math/Matrix4.h" |
||||
#include "Magnum/Math/Quaternion.h" |
||||
#include "Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h" |
||||
#include "Magnum/SceneGraph/Object.h" |
||||
|
||||
namespace Magnum { namespace SceneGraph { |
||||
|
||||
/**
|
||||
@brief Three-dimensional transformation implemented using translation, rotation and scaling |
||||
|
||||
Similar to @ref BasicMatrixTransformation3D, but stores translation, rotation |
||||
and scaling separately. This makes it more suitable for e.g. animation, where |
||||
there are usually separate animation tracks for translation, rotation and |
||||
scaling. This separation also imposes some constraints --- for given object, |
||||
scaling is always applied first, rotation second and translation last. In |
||||
particular, unlike with matrix-based transformation implementation, it's not |
||||
possible to rotate a translated object, for example --- one has to apply the |
||||
rotation first and then translate using a rotated vector. |
||||
@see @ref scenegraph, @ref TranslationRotationScalingTransformation3D, |
||||
@ref BasicTranslationRotationScalingTransformation2D |
||||
*/ |
||||
template<class T> class BasicTranslationRotationScalingTransformation3D: public AbstractBasicTranslationRotationScaling3D<T> { |
||||
public: |
||||
/** @brief Underlying transformation type */ |
||||
typedef Math::Matrix4<T> DataType; |
||||
|
||||
/** @brief Object transformation */ |
||||
Math::Matrix4<T> transformation() const; |
||||
|
||||
/**
|
||||
* @brief Set transformation |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Expects that the transformation doesn't contain shear or reflection. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& setTransformation(const Math::Matrix4<T>& transformation); |
||||
|
||||
/** @brief Object translation */ |
||||
Math::Vector3<T> translation() const { return _translation; } |
||||
|
||||
/**
|
||||
* @brief Set translation |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Translation is always applied last, after rotation and scaling. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& setTranslation(const Math::Vector3<T>& translation); |
||||
|
||||
/** @brief Object rotation */ |
||||
Math::Quaternion<T> rotation() const { return _rotation; } |
||||
|
||||
/**
|
||||
* @brief Set rotation |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Rotation is always applied after scaling and before translation. |
||||
* Expects that the quaternion is normalized. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& setRotation(const Math::Quaternion<T>& rotation); |
||||
|
||||
/** @brief Object scaling */ |
||||
Math::Vector3<T> scaling() const { return _scaling; } |
||||
|
||||
/**
|
||||
* @brief Set scaling |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Scaling is always applied first, before rotation and translation. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& setScaling(const Math::Vector3<T>& scaling); |
||||
|
||||
/** @copydoc AbstractTranslationRotationScaling3D::resetTransformation() */ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& resetTransformation() { |
||||
return setTransformation({}); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Translate object |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Note that translation is always applied last, after rotation and |
||||
* scaling. |
||||
* @see @ref translateLocal(), @ref Math::Vector3::xAxis(), |
||||
* @ref Math::Vector3::yAxis(), @ref Math::Vector3::zAxis() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& translate(const Math::Vector3<T>& vector) { |
||||
return setTranslation(vector + _translation); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Translate object as a local transformation |
||||
* |
||||
* Equivalent to the above, as translation is commutative. Note that |
||||
* translation is always applied last, after rotation and scaling. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& translateLocal(const Math::Vector3<T>& vector) { |
||||
return setTranslation(_translation + vector); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object using a quaternion |
||||
* @param quaternion Normalized quaternion |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Note that rotation is always applied after scaling and before |
||||
* translation. Expects that the quaternion is normalized. |
||||
* @see @ref rotate(Math::Rad<T>, const Math::Vector3<T>&), |
||||
* @ref rotateLocal(const Math::Quaternion<T>&), @ref rotateX(), |
||||
* @ref rotateY(), @ref rotateZ(), @ref Math::Vector3::xAxis(), |
||||
* @ref Math::Vector3::yAxis(), @ref Math::Vector3::zAxis() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotate(const Math::Quaternion<T>& quaternion) { |
||||
return setRotation(quaternion*_rotation); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object using a quaternion as a local transformation |
||||
* |
||||
* Similar to the above, except that the rotation is applied before all |
||||
* other rotations. Note that rotation is always applied after scaling |
||||
* and before translation. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateLocal(const Math::Quaternion<T>& quaternion) { |
||||
return setRotation(_rotation*quaternion); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object |
||||
* @param angle Angle (counterclockwise) |
||||
* @param normalizedAxis Normalized rotation axis |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Same as calling @ref rotate(const Math::Quaternion<T>&) |
||||
* with @ref Quaternion::rotation(). Note that rotation is always |
||||
* applied after scaling and before translation. |
||||
* @see @ref rotateLocal(), @ref rotateX(), @ref rotateY(), |
||||
* @ref rotateZ(), @ref Math::Vector3::xAxis(), |
||||
* @ref Math::Vector3::yAxis(), @ref Math::Vector3::zAxis() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotate(Math::Rad<T> angle, const Math::Vector3<T>& normalizedAxis) { |
||||
return rotate(Math::Quaternion<T>::rotation(angle, normalizedAxis)); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object as a local transformation |
||||
* |
||||
* Similar to the above, except that the rotation is applied before all |
||||
* other rotations. Note that rotation is always applied after scaling |
||||
* and before translation. Same as calling |
||||
* @ref rotateLocal(const Math::Quaternion<T>&) with |
||||
* @ref Math::Quaternion::rotation(). |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateLocal(Math::Rad<T> angle, const Math::Vector3<T>& normalizedAxis) { |
||||
return rotateLocal(Math::Quaternion<T>::rotation(angle, normalizedAxis)); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object around X axis |
||||
* @param angle Angle (counterclockwise) |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Same as calling @ref rotate() with @ref Math::Vector3::xAxis() as an |
||||
* axis. |
||||
* @see @ref rotateXLocal() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateX(Math::Rad<T> angle) { |
||||
return rotate(angle, Math::Vector3<T>::xAxis()); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object around X axis as a local transformation |
||||
* |
||||
* Similar to the above, except that the rotation is applied before all |
||||
* other rotations. Note that rotation is always applied after scaling |
||||
* and before translation. Same as calling @ref rotateLocal() with |
||||
* @ref Math::Vector3::xAxis() as an axis. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateXLocal(Math::Rad<T> angle) { |
||||
return rotateLocal(angle, Math::Vector3<T>::xAxis()); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object around Y axis |
||||
* @param angle Angle (counterclockwise) |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Same as calling @ref rotate() with @ref Math::Vector3::yAxis() as an |
||||
* axis. |
||||
* @see @ref rotateYLocal() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateY(Math::Rad<T> angle) { |
||||
return rotate(angle, Math::Vector3<T>::yAxis()); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object around Y axis as a local transformation |
||||
* |
||||
* Similar to the above, except that the rotation is applied before all |
||||
* other rotations. Note that rotation is always applied after scaling |
||||
* and before translation. Same as calling @ref rotateLocal() with |
||||
* @ref Math::Vector3::yAxis() as an axis. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateYLocal(Math::Rad<T> angle) { |
||||
return rotateLocal(angle, Math::Vector3<T>::yAxis()); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object around Z axis |
||||
* @param angle Angle (counterclockwise) |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Same as calling @ref rotate() with @ref Math::Vector3::yAxis() as an |
||||
* axis. |
||||
* @see @ref rotateZLocal() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateZ(Math::Rad<T> angle) { |
||||
return rotate(angle, Math::Vector3<T>::zAxis()); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object around Z axis as a local transformation |
||||
* |
||||
* Similar to the above, except that the rotation is applied before all |
||||
* other rotations. Note that rotation is always applied after scaling |
||||
* and before translation. Same as calling @ref rotateLocal() with |
||||
* @ref Math::Vector3::zAxis() as an axis. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& rotateZLocal(Math::Rad<T> angle) { |
||||
return rotateLocal(angle, Math::Vector3<T>::zAxis()); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Scale object |
||||
* @return Reference to self (for method chaining) |
||||
* |
||||
* Note that scaling is always applied first, before rotation and |
||||
* translation. |
||||
* @see @ref scaleLocal(), @ref Math::Vector3::xScale(), |
||||
* @ref Math::Vector3::yScale(), @ref Math::Vector3::zScale() |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& scale(const Math::Vector3<T>& vector) { |
||||
return setScaling(vector*_scaling); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Scale object as a local transformation |
||||
* |
||||
* Equivalent to the above, as scaling is commutative. Note that |
||||
* scaling is always first, before rotation and translation. |
||||
*/ |
||||
Object<BasicTranslationRotationScalingTransformation3D<T>>& scaleLocal(const Math::Vector3<T>& vector) { |
||||
return setScaling(_scaling*vector); |
||||
} |
||||
|
||||
protected: |
||||
/* Allow construction only from Object */ |
||||
explicit BasicTranslationRotationScalingTransformation3D() = default; |
||||
|
||||
private: |
||||
void doResetTransformation() override final { resetTransformation(); } |
||||
|
||||
void doTranslate(const Math::Vector3<T>& vector) override final { translate(vector); } |
||||
void doTranslateLocal(const Math::Vector3<T>& vector) override final { translateLocal(vector); } |
||||
|
||||
void doRotate(Math::Rad<T> angle, const Math::Vector3<T>& normalizedAxis) override final { |
||||
rotate(angle, normalizedAxis); |
||||
} |
||||
void doRotateLocal(Math::Rad<T> angle, const Math::Vector3<T>& normalizedAxis) override final { |
||||
rotateLocal(angle, normalizedAxis); |
||||
} |
||||
|
||||
void doRotateX(Math::Rad<T> angle) override final { rotateX(angle); } |
||||
void doRotateXLocal(Math::Rad<T> angle) override final { rotateXLocal(angle); } |
||||
|
||||
void doRotateY(Math::Rad<T> angle) override final { rotateY(angle); } |
||||
void doRotateYLocal(Math::Rad<T> angle) override final { rotateYLocal(angle); } |
||||
|
||||
void doRotateZ(Math::Rad<T> angle) override final { rotateZ(angle); } |
||||
void doRotateZLocal(Math::Rad<T> angle) override final { rotateZLocal(angle); } |
||||
|
||||
void doScale(const Math::Vector3<T>& vector) override final { scale(vector); } |
||||
void doScaleLocal(const Math::Vector3<T>& vector) override final { scaleLocal(vector); } |
||||
|
||||
Math::Vector3<T> _translation; |
||||
Math::Quaternion<T> _rotation; |
||||
Math::Vector3<T> _scaling{T(1)}; |
||||
}; |
||||
|
||||
/**
|
||||
@brief Three-dimensional transformation for float scenes implemented using translation, rotation and scaling |
||||
|
||||
@see @ref TranslationRotationScalingTransformation2D |
||||
*/ |
||||
typedef BasicTranslationRotationScalingTransformation3D<Float> TranslationRotationScalingTransformation3D; |
||||
|
||||
template<class T> Math::Matrix4<T> BasicTranslationRotationScalingTransformation3D<T>::transformation() const { |
||||
return Math::Matrix4<T>::from(_rotation.toMatrix(), _translation)* |
||||
Math::Matrix4<T>::scaling(_scaling); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation3D<T>>& BasicTranslationRotationScalingTransformation3D<T>::setTransformation(const Math::Matrix4<T>& 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<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->isScene()) { |
||||
_translation = transformation.translation(); |
||||
_rotation = Math::Quaternion<T>::fromMatrix(transformation.rotationShear()); |
||||
_scaling = transformation.scaling(); |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>&>(*this); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation3D<T>>& BasicTranslationRotationScalingTransformation3D<T>::setTranslation(const Math::Vector3<T>& translation) { |
||||
/* 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<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->isScene()) { |
||||
_translation = translation; |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>&>(*this); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation3D<T>>& BasicTranslationRotationScalingTransformation3D<T>::setRotation(const Math::Quaternion<T>& rotation) { |
||||
/* 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<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->isScene()) { |
||||
_rotation = rotation; |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>&>(*this); |
||||
} |
||||
|
||||
template<class T> Object<BasicTranslationRotationScalingTransformation3D<T>>& BasicTranslationRotationScalingTransformation3D<T>::setScaling(const Math::Vector3<T>& scaling) { |
||||
/* 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<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->isScene()) { |
||||
_scaling = scaling; |
||||
static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>*>(this)->setDirty(); |
||||
} |
||||
|
||||
return static_cast<Object<BasicTranslationRotationScalingTransformation3D<T>>&>(*this); |
||||
} |
||||
|
||||
namespace Implementation { |
||||
|
||||
template<class T> struct Transformation<BasicTranslationRotationScalingTransformation3D<T>> { |
||||
constexpr static Math::Matrix4<T> fromMatrix(const Math::Matrix4<T>& matrix) { |
||||
return matrix; |
||||
} |
||||
|
||||
constexpr static Math::Matrix4<T> toMatrix(const Math::Matrix4<T>& transformation) { |
||||
return transformation; |
||||
} |
||||
|
||||
static Math::Matrix4<T> compose(const Math::Matrix4<T>& parent, const Math::Matrix4<T>& child) { |
||||
return parent*child; |
||||
} |
||||
|
||||
static Math::Matrix4<T> inverted(const Math::Matrix4<T>& transformation) { |
||||
return transformation.inverted(); |
||||
} |
||||
}; |
||||
|
||||
} |
||||
|
||||
#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__) |
||||
extern template class MAGNUM_SCENEGRAPH_EXPORT Object<BasicTranslationRotationScalingTransformation3D<Float>>; |
||||
#endif |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue