From b3208e8f75bdd5512ddb5070a491f078c4d52c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 27 Apr 2018 23:04:06 +0200 Subject: [PATCH] doc: compiling Transformations page code snippets. --- doc/snippets/CMakeLists.txt | 1 + doc/snippets/MagnumMath.cpp | 211 ++++++++++++++++++++++++++++++++++++ doc/transformations.dox | 108 +++--------------- 3 files changed, 230 insertions(+), 90 deletions(-) create mode 100644 doc/snippets/MagnumMath.cpp diff --git a/doc/snippets/CMakeLists.txt b/doc/snippets/CMakeLists.txt index 7f26cb198..15a5d5ed3 100644 --- a/doc/snippets/CMakeLists.txt +++ b/doc/snippets/CMakeLists.txt @@ -36,6 +36,7 @@ endif() add_library(snippets STATIC plugins.cpp Magnum.cpp + MagnumMath.cpp MagnumMeshTools.cpp MagnumShaders.cpp MagnumText.cpp) diff --git a/doc/snippets/MagnumMath.cpp b/doc/snippets/MagnumMath.cpp new file mode 100644 index 000000000..d485bbe7d --- /dev/null +++ b/doc/snippets/MagnumMath.cpp @@ -0,0 +1,211 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + 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 "Magnum/Magnum.h" +#include "Magnum/Math/DualComplex.h" +#include "Magnum/Math/DualQuaternion.h" +#include "Magnum/Math/Algorithms/GramSchmidt.h" + +using namespace Magnum; +using namespace Magnum::Math::Literals; + +int main() { +{ +/* [transformations-rotation2D] */ +auto a = Matrix3::rotation(23.0_degf); +auto b = Complex::rotation(Rad(Constants::piHalf())); +auto c = DualComplex::rotation(-1.57_radf); +/* [transformations-rotation2D] */ +static_cast(a); +static_cast(b); +static_cast(c); +} + +{ +Rad angle; +/* [transformations-rotation3D] */ +auto a = Quaternion::rotation(60.0_degf, Vector3::xAxis()); +auto b = DualQuaternion::rotation(-1.0_degf, Vector3(1.0f, 0.5f, 3.0f).normalized()); +auto c = Matrix4::rotationZ(angle); +/* [transformations-rotation3D] */ +static_cast(a); +static_cast(b); +static_cast(c); +} + +{ +/* [transformations-translation2D] */ +auto a = Matrix3::translation(Vector2::xAxis(-5.0f)); +auto b = DualComplex::translation({-1.0f, 0.5f}); +/* [transformations-translation2D] */ +static_cast(a); +static_cast(b); +} + +{ +Vector3 vector; +/* [transformations-translation3D] */ +auto a = Matrix4::translation(vector); +auto b = DualQuaternion::translation(Vector3::zAxis(1.3f)); +/* [transformations-translation3D] */ +static_cast(a); +static_cast(b); +} + +{ +/* [transformations-scaling] */ +auto a = Matrix3::scaling(Vector2::xScale(2.0f)); +auto b = Matrix4::scaling({2.0f, -2.0f, 1.5f}); +auto c = Matrix4::scaling(Vector3(10.0f)); +/* [transformations-scaling] */ +static_cast(a); +static_cast(b); +static_cast(c); +} + +{ +Vector3 axis; +/* [transformations-reflection] */ +auto a = Matrix3::reflection(Vector2::yAxis()); +auto b = Matrix4::reflection(axis.normalized()); +/* [transformations-reflection] */ +static_cast(a); +static_cast(b); +} + +{ +/* [transformations-projection] */ +auto a = Matrix3::projection({4.0f, 3.0f}); +auto b = Matrix4::orthographicProjection({4.0f, 3.0f}, 0.001f, 100.0f); +auto c = Matrix4::perspectiveProjection(35.0_degf, 1.333f, 0.001f, 100.0f); +/* [transformations-projection] */ +static_cast(a); +static_cast(b); +static_cast(c); +} + +{ +/* [transformations-composing] */ +auto a = DualComplex::translation(Vector2::yAxis(2.0f))* + DualComplex::rotation(25.0_degf); +auto b = Matrix4::translation(Vector3::yAxis(5.0f))* + Matrix4::rotationY(25.0_degf); +/* [transformations-composing] */ +static_cast(a); +static_cast(b); +} + +{ +/* [transformations-transform2D] */ +auto transformation = Matrix3::rotation(-30.0_degf)*Matrix3::scaling(Vector2(3.0f)); +Vector2 transformed = transformation.transformVector({1.5f, -7.9f}); +/* [transformations-transform2D] */ +static_cast(transformed); +} + +{ +/* [transformations-transform3D] */ +auto transformation = DualQuaternion::rotation(-30.0_degf, Vector3::xAxis())* + DualQuaternion::translation(Vector3::yAxis(3.0f)); +Vector3 transformed = transformation.transformPointNormalized({1.5f, 3.0f, -7.9f}); +/* [transformations-transform3D] */ +static_cast(transformed); +} + +{ +/* [transformations-properties] */ +Matrix4 transformation; +Matrix3x3 rotationScaling = transformation.rotationScaling(); +Vector3 up = transformation.up(); +Vector3 right = transformation.right(); + +Matrix3 b; +Matrix2x2 rotation = b.rotation(); +Float xTranslation = b.translation().x(); +/* [transformations-properties] */ + +/* [transformations-recreate] */ +Matrix3 c = Matrix3::from(rotation, {1.0f, 3.0f}); +/* [transformations-recreate] */ +static_cast(rotationScaling); +static_cast(up); +static_cast(right); +static_cast(xTranslation); +static_cast(c); +} + +{ +/* [transformations-properties-complex-quat] */ +DualComplex a; +Rad rotationAngle = a.rotation().angle(); +Vector2 translation = a.translation(); + +Quaternion b; +Vector3 rotationAxis = b.axis(); +/* [transformations-properties-complex-quat] */ +static_cast(rotationAngle); +static_cast(translation); +static_cast(rotationAxis); +} + +{ +/* [transformations-properties-complex-quat-to-matrix] */ +Quaternion a; +auto rotation = Matrix4::from(a.toMatrix(), {}); + +DualComplex b; +Matrix3 transformation = b.toMatrix(); +/* [transformations-properties-complex-quat-to-matrix] */ +static_cast(rotation); +static_cast(transformation); +} + +{ +/* [transformations-properties-complex-quat-from-matrix] */ +Matrix3 rotation; +auto a = Complex::fromMatrix(rotation.rotationScaling()); + +Matrix4 transformation; +auto b = DualQuaternion::fromMatrix(transformation); +/* [transformations-properties-complex-quat-from-matrix] */ +static_cast(a); +static_cast(b); +} + +{ +/* [transformations-normalization-matrix] */ +Matrix4 transformation; +Math::Algorithms::gramSchmidtOrthonormalizeInPlace(transformation); +/* [transformations-normalization-matrix] */ +} + +{ +/* [transformations-normalization-quat] */ +DualQuaternion transformation; +transformation = transformation.normalized(); +/* [transformations-normalization-quat] */ +} + +} diff --git a/doc/transformations.dox b/doc/transformations.dox index bdbc87f31..6bbb253b2 100644 --- a/doc/transformations.dox +++ b/doc/transformations.dox @@ -87,11 +87,7 @@ you don't need to worry about them in initialization. and rotation transformation can be created by calling @ref Matrix3::rotation(), @ref Complex::rotation() or @ref DualComplex::rotation(), for example: -@code{.cpp} -auto a = Matrix3::rotation(23.0_degf); -auto b = Complex::rotation(Rad(Constants::piHalf())); -auto c = DualComplex::rotation(-1.57_radf); -@endcode +@snippet MagnumMath.cpp transformations-rotation2D 3D rotation is represented by angle and (three-dimensional) axis. The rotation can be created by calling @ref Matrix4::rotation(), @ref Quaternion::rotation() @@ -102,11 +98,7 @@ Matrix representation has also @ref Matrix4::rotationX(), @ref Matrix4::rotationY() and @ref Matrix4::rotationZ() which are faster than using the generic function for rotation around primary axes. Examples: -@code{.cpp} -auto a = Quaternion::rotation(60.0_degf, Vector3::xAxis()); -auto b = DualQuaternion::rotation(-1.0_degf, Vector3(1.0f, 0.5f, 3.0f).normalized()); -auto c = Matrix4::rotationZ(angle); -@endcode +@snippet MagnumMath.cpp transformations-rotation3D Rotations are always around origin. Rotation about arbitrary point can be done by applying translation to have the point at origin, performing the rotation and @@ -120,19 +112,13 @@ then translating back. Read below for more information. @ref Vector2::xAxis() or @ref Vector2::yAxis() to translate only along given axis. Examples: -@code{.cpp} -auto a = Matrix3::translation(Vector2::xAxis(-5.0f)); -auto b = DualComplex::translation({-1.0f, 0.5f}); -@endcode +@snippet MagnumMath.cpp transformations-translation2D 3D translation is defined by three-dimensional vector and can be created with @ref Matrix4::translation() or @ref DualQuaternion::translation(). You can use @ref Vector3::xAxis() and friends also here. Examples: -@code{.cpp} -auto a = Matrix4::translation(vector); -auto b = DualQuaternion::translation(Vector3::zAxis(1.3f)); -@endcode +@snippet MagnumMath.cpp transformations-translation3D @subsection transformations-scaling Scaling and reflection @@ -143,11 +129,7 @@ or their 2D counterparts to scale along one axis and leave the rest unchanged or call explicit one-parameter vector constructor to scale uniformly on all axes. Examples: -@code{.cpp} -auto a = Matrix3::scaling(Vector2::xScale(2.0f)); -auto b = Matrix4::scaling({2.0f, -2.0f, 1.5f}); -auto c = Matrix4::scaling(Vector3(10.0f)); -@endcode +@snippet MagnumMath.cpp transformations-scaling Reflections are defined by normal along which to reflect (i.e., two- or three-dimensional vector of unit length) and they are also represented by @@ -155,10 +137,7 @@ matrices. Reflection is created with @ref Matrix3::reflection() or @ref Matrix4::reflection(). You can use @ref Vector3::xAxis() and friends also here. Examples: -@code{.cpp} -auto a = Matrix3::reflection(Vector2::yAxis()); -auto b = Matrix4::reflection(axis.normalized()); -@endcode +@snippet MagnumMath.cpp transformations-reflection Scaling and reflection is also done relative to origin, you can use method mentioned above to scale or reflect around arbitrary point. @@ -179,11 +158,7 @@ unit cube, and perspective projection. Perspective projection is created with aspect ratio and distance to near and far plane of view frustum or by size of near plane, its distance and distance to far plane. Some examples: -@code{.cpp} -auto a = Matrix3::projection({4.0f, 3.0f}); -auto b = Matrix4::orthographicProjection({4.0f, 3.0f, 100.0f}); -auto c = Matrix4::perspectiveProjection(35.0_degf, 1.333f, 0.001f, 100.0f); -@endcode +@snippet MagnumMath.cpp transformations-projection @section transformations-composing Composing and inverting transformations @@ -194,12 +169,7 @@ transformation on the right-hand side of multiplication is applied first, the transformation on the left-hand side is applied second. For example, rotation followed by translation is done like this: -@code{.cpp} -auto a = DualComplex::translation(Vector2::yAxis(2.0f))* - DualComplex::rotation(25.0_degf); -auto b = Matrix4::translation(Vector3::yAxis(5.0f))* - Matrix4::rotationY(25.0_degf); -@endcode +@snippet MagnumMath.cpp transformations-composing Inverse transformation can be computed using @ref Matrix3::inverted(), @ref Matrix4::inverted(), @ref Complex::inverted(), @ref Quaternion::inverted(), @@ -221,21 +191,14 @@ using @ref Matrix4::transformVector() and @ref Quaternion::transformVector(). For transformation with normalized quaternion you can use faster alternative @ref Quaternion::transformVectorNormalized(). Example: -@code{.cpp} -auto transformation = Matrix3::rotation(-30.0_degf)*Matrix3::scaling(Vector2(3.0f)); -Vector2 transformed = transformation.transformVector({1.5f, -7.9f}); -@endcode +@snippet MagnumMath.cpp transformations-transform2D Point transformation involves also translation, in 2D is done with @ref Matrix3::transformPoint() and @ref DualComplex::transformPoint(), in 3D with @ref Matrix4::transformPoint() and @ref DualQuaternion::transformPoint(). Also here you can use faster alternative @ref DualQuaternion::transformPointNormalized(): -@code{.cpp} -auto transformation = DualQuaternion::rotation(-30.0_degf, Vector3::xAxis())* - DualQuaternion::translation(Vector3::yAxis(3.0f)); -Vector3 transformed = transformation.transformPointNormalized({1.5f, 3.0f, -7.9f}); -@endcode +@snippet MagnumMath.cpp transformations-transform3D @section transformations-properties Transformation properties and conversion @@ -243,16 +206,7 @@ It is possible to extract some transformation properties from transformation matrices, particularly translation vector, rotation/scaling part of the matrix (or pure rotation if the matrix has uniform scaling) and also base vectors: -@code{.cpp} -Matrix4 a; -auto rotationScaling = transformation.rotationScaling(); -Vector3 up = transformation.up(); -Vector3 right = transformation.right(); - -Matrix3 b; -auto rotation = b.rotation(); -Float xTranslation = b.translation().x(); -@endcode +@snippet MagnumMath.cpp transformations-properties Extracting scaling and rotation from arbitrary transformation matrices is harder and can be done using @ref Math::Algorithms::svd(). Extracting rotation @@ -262,9 +216,7 @@ complex number or quaternion, see below. You can also recreate transformation matrix from rotation and translation parts: -@code{.cpp} -Matrix3 c = Matrix3::from(rotation, {1.0f, 3.0f}); -@endcode +@snippet MagnumMath.cpp transformations-recreate Complex numbers and quaternions are far better in this regard and they allow you to extract rotation angle using @ref Complex::angle() or @@ -273,40 +225,21 @@ Their dual versions allow to extract both rotation and translation part using @ref DualComplex::rotation() const, @ref DualQuaternion::rotation() const, @ref DualComplex::translation() const and @ref DualQuaternion::translation() const. -@code{.cpp} -DualComplex a; -Rad rotationAngle = a.rotation().angle(); -Vector2 translation = a.translation(); - -Quaternion b; -Vector3 rotationAxis = b.axis(); -@endcode +@snippet MagnumMath.cpp transformations-properties-complex-quat You can convert Complex and Quaternion to rotation matrix using @ref Complex::toMatrix() and @ref Quaternion::toMatrix() or their dual version to rotation and translation matrix using @ref DualComplex::toMatrix() and @ref DualQuaternion::toMatrix(): -@code{.cpp} -Quaternion a; -auto rotation = Matrix4::from(a.toMatrix(), {}); - -DualComplex b; -Matrix3 transformation = b.toMatrix(); -@endcode +@snippet MagnumMath.cpp transformations-properties-complex-quat-to-matrix Conversion the other way around is possible only from rotation matrices using @ref Complex::fromMatrix() or @ref Quaternion::fromMatrix() and from rotation and translation matrices using @ref DualComplex::fromMatrix() and @ref DualQuaternion::fromMatrix(): -@code{.cpp} -Matrix3 rotation; -auto a = Complex::fromMatrix(rotation.rotationScaling()); - -Matrix4 transformation; -auto b = DualQuaternion::fromMatrix(transformation); -@endcode +@snippet MagnumMath.cpp transformations-properties-complex-quat-from-matrix @section transformations-interpolation Transformation interpolation @@ -326,10 +259,7 @@ can be reorthogonalized using @ref Math::Algorithms::gramSchmidtOrthogonalize() scaling). You can also use @ref Math::Algorithms::svd() to more precisely (but way more slowly) account for the drift. Example: -@code{.cpp} -Matrix4 transformation; -Math::Algorithms::gramSchmidtOrthonormalizeInPlace(transformation); -@endcode +@snippet MagnumMath.cpp transformations-normalization-matrix For quaternions and complex number this problem can be solved far more easily using @ref Complex::normalized(), @ref Quaternion::normalized(), @@ -337,9 +267,7 @@ using @ref Complex::normalized(), @ref Quaternion::normalized(), Transformation quaternions and complex numbers are always of unit length, thus normalizing them reduces the drift. -@code{.cpp} -DualQuaternion transformation; -transformation = transformation.normalized(); -@endcode +@snippet MagnumMath.cpp transformations-normalization-quat + */ }