From 8bf1f5e5d8b85a26110280a02e63e48948c774b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 24 Aug 2016 15:47:50 +0200 Subject: [PATCH] =?UTF-8?q?Math:=20Minor=20B=C3=A9zier=20cleanup=20and=20d?= =?UTF-8?q?ocumentation=20improvements.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed the points() access function, as it has no real value. --- src/Magnum/Math/Bezier.h | 136 +++++++++++++++++++--------- src/Magnum/Math/Test/BezierTest.cpp | 38 ++++---- src/Magnum/Math/Test/CMakeLists.txt | 3 +- 3 files changed, 114 insertions(+), 63 deletions(-) diff --git a/src/Magnum/Math/Bezier.h b/src/Magnum/Math/Bezier.h index b9ed69cca..5358d247e 100644 --- a/src/Magnum/Math/Bezier.h +++ b/src/Magnum/Math/Bezier.h @@ -1,6 +1,5 @@ #ifndef Magnum_Math_Bezier_h #define Magnum_Math_Bezier_h - /* This file is part of Magnum. @@ -28,46 +27,59 @@ */ /** @file - * @brief Class @ref Magnum::Math::Bezier + * @brief Class @ref Magnum::Math::Bezier, alias @ref Magnum::Math::QuadraticBezier, @ref Magnum::Math::QuadraticBezier2D, @ref Magnum::Math::QuadraticBezier3D, @ref Magnum::Math::CubicBezier, @ref Magnum::Math::CubicBezier2D, @ref Magnum::Math::CubicBezier3D */ #include -#include "Vector.h" +#include "Magnum/Math/Vector.h" namespace Magnum { namespace Math { + /** -@brief Bezier -@tparam order Order of Bezier curve -@tparam dimensions Dimensions of the control points +@brief Bézier curve +@tparam order Order of Bézier curve +@tparam dimensions Dimensions of control points @tparam T Underlying data type -See Bezier Curve. +Implementation of M-order N-dimensional +[Bézier Curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve). +@see @ref QuadraticBezier, @ref CubicBezier, @ref QuadraticBezier2D, + @ref QuadraticBezier3D, @ref CubicBezier2D, @ref CubicBezier3D */ template class Bezier { - public: + typedef T Type; /**< @brief Underlying data type */ - /** @brief Default constructor */ - constexpr /*implicit*/ Bezier(ZeroInitT = ZeroInit): _points{} {} + enum: UnsignedInt { + Order = order, /**< Order of Bézier curve */ + Dimensions = dimensions /**< Dimensions of control points */ + }; - /** @brief Construct Bezier without initializing the contents */ - explicit Bezier(NoInitT) {} + /** + * @brief Default constructor + * + * Construct the curve with all control points being zero vectors. + */ + constexpr /*implicit*/ Bezier(ZeroInitT = ZeroInit) noexcept: _data{} {} - /** @brief Construct Bezier curve with the given array of control points */ - template constexpr Bezier(Vector first, U... next):_points{first, next...} { - static_assert(sizeof...(U) + 1 == order + 1, "Bezier : Wrong number of arguments"); + /** @brief Construct Bézier without initializing the contents */ + explicit Bezier(NoInitT) noexcept {} + + /** @brief Construct Bézier curve with given array of control points */ + template constexpr Bezier(const Vector& first, U... next) noexcept: _data{first, next...} { + static_assert(sizeof...(U) + 1 == order + 1, "Wrong number of arguments"); } /** - * @brief Divides a Bezier curve into two curves of same order having their own control points. - * De Casteljau's algorithm is used. + * @brief Subdivide the curve * @param t The interpolation factor * - * @return Array of two Bezier curves of the same order + * Divides the curve into two Bézier curves of same order having their + * own control points. Uses the [De Casteljau's algorithm](https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm). */ std::array, 2> subdivide(Float t) const { - auto iPoints = calculateIntermediatePoints(t); + const auto iPoints = calculateIntermediatePoints(t); Bezier left, right; for(std::size_t i = 0; i <= order; ++i) { left[i] = iPoints[0][i]; @@ -79,43 +91,31 @@ template class Bezier { } /** - * @brief Finds the point in the curve for a given interpolation factor - * De Casteljau's algorithm is used. + * @brief Interpolate the curve * @param t The interpolation factor + * + * Finds the point in the curve for a given interpolation factor. Uses + * the [De Casteljau's algorithm](https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm). */ Vector lerp(Float t) const { - auto iPoints = calculateIntermediatePoints(t); + const auto iPoints = calculateIntermediatePoints(t); return iPoints[0][order]; } /** - * @brief Control points of Bezier - * @return One-dimensional array of `size` length. - * - * @see @ref operator[]() - */ - Vector* points() { return _points; } - constexpr const Vector* points() const { return _points; } /**< @overload */ - - /** - * @brief Value at given position + * @brief Control point access * - * @see @ref points() + * @p i should not be larger than @ref Order. */ - Vector& operator[](std::size_t pos) { return _points[pos]; } - constexpr Vector operator[](std::size_t pos) const { return _points[pos]; } /**< @overload */ + Vector& operator[](std::size_t i) { return _data[i]; } + constexpr Vector operator[](std::size_t i) const { return _data[i]; } /**< @overload */ private: - - /** - * @brief Calculates and returns all intermediate points generated when using De Casteljau's algorithm - * @param t The interpolation factor - * - */ + /* Calculates and returns all intermediate points generated when using De Casteljau's algorithm */ std::array, order + 1> calculateIntermediatePoints(Float t) const { std::array, order + 1> iPoints; for(std::size_t i = 0; i <= order; ++i) { - iPoints[i][0] = _points[i]; + iPoints[i][0] = _data[i]; } for(std::size_t r = 1; r <= order; ++r) { for(std::size_t i = 0; i <= order - r; ++i) { @@ -125,16 +125,64 @@ template class Bezier { return iPoints; } - Vector _points[order + 1]; + Vector _data[order + 1]; }; +/** +@brief Quadratic Bézier curve + +Convenience alternative to `Bezier<2, dimensions, T>`. See @ref Bezier for more +information. +@see @ref QuadraticBezier2D, @ref QuadraticBezier3D +*/ template using QuadraticBezier = Bezier<2, dimensions, T>; -template using CubicBezier = Bezier<3, dimensions, T>; + +/** +@brief Two-dimensional quadratic Bézier curve + +Convenience alternative to `QuadraticBezier<2, T>`. See @ref QuadraticBezier +and @ref Bezier for more information. +@see @ref QuadraticBezier3D +*/ template using QuadraticBezier2D = QuadraticBezier<2, T>; + +/** +@brief Three-dimensional quadratic Bézier curve + +Convenience alternative to `QuadraticBezier<3, T>`. See @ref QuadraticBezier +and @ref Bezier for more information. +@see @ref QuadraticBezier2D +*/ template using QuadraticBezier3D = QuadraticBezier<3, T>; + +/** +@brief Cubic Bézier curve + +Convenience alternative to `Bezier<3, dimensions, T>`. See @ref Bezier for more +information. +@see @ref CubicBezier2D, @ref CubicBezier3D +*/ +template using CubicBezier = Bezier<3, dimensions, T>; + +/** +@brief Two-dimensional cubic Bézier curve + +Convenience alternative to `CubicBezier<2, T>`. See @ref CubicBezier +and @ref Bezier for more information. +@see @ref CubicBezier3D +*/ template using CubicBezier2D = CubicBezier<2, T>; + +/** +@brief Three-dimensional cubic Bézier curve + +Convenience alternative to `CubicBezier<3, T>`. See @ref CubicBezier +and @ref Bezier for more information. +@see @ref CubicBezier2D +*/ template using CubicBezier3D = CubicBezier<3, T>; }} + #endif diff --git a/src/Magnum/Math/Test/BezierTest.cpp b/src/Magnum/Math/Test/BezierTest.cpp index da4368f01..456f81d77 100644 --- a/src/Magnum/Math/Test/BezierTest.cpp +++ b/src/Magnum/Math/Test/BezierTest.cpp @@ -25,55 +25,57 @@ */ #include + #include "Magnum/Math/Bezier.h" +#include "Magnum/Math/Vector2.h" #include "Magnum/Math/Functions.h" - namespace Magnum { namespace Math { namespace Test { -typedef Math::Vector<2, Float> Vector2; +typedef Math::Vector2 Vector2; +typedef Math::QuadraticBezier2D QuadraticBezier2D; +typedef Math::CubicBezier2D CubicBezier2D; struct BezierTest : Corrade::TestSuite::Tester { explicit BezierTest(); void implicitConstructor(); - void quadratic(); - - void cubic(); + void lerpQuadratic(); + void lerpCubic(); }; BezierTest::BezierTest() { addTests({&BezierTest::implicitConstructor, - &BezierTest::quadratic, - &BezierTest::cubic}); + + &BezierTest::lerpQuadratic, + &BezierTest::lerpCubic}); } void BezierTest::implicitConstructor() { - QuadraticBezier2D bezier; - Vector2 zero; + QuadraticBezier2D bezier; for(int i = 0; i < 3; ++i) { - CORRADE_COMPARE(bezier[i], zero); + CORRADE_COMPARE(bezier[i], Vector2{}); } } -void BezierTest::quadratic() { +void BezierTest::lerpQuadratic() { Vector2 p0(0.0f, 0.0f), p1(10.0f, 15.0f), p2(20.0f, 4.0f); - QuadraticBezier2D bezier(p0, p1, p2); + QuadraticBezier2D bezier(p0, p1, p2); for(Float t = 0.0; t <= 1.0f; t += 0.01f) { Vector2 expected = Math::pow<2>(1 - t)*p0 + 2*(1 - t)*t*p1 + Math::pow<2>(t)*p2; CORRADE_COMPARE(bezier.lerp(t), expected); } } -void BezierTest::cubic() { +void BezierTest::lerpCubic() { Vector2 p0(0.0f, 0.0f), p1(10.0f, 15.0f), p2(20.0f, 4.0f), p3(5.0f, -20.0f); - CubicBezier2D bezier(p0, p1, p2, p3); + CubicBezier2D bezier(p0, p1, p2, p3); for(Float t = 0.0; t <= 1.0f; t += 0.01f) { - Vector2 expected = Math::pow<3>(1 - t)*p0 - + 3*Math::pow<2>(1 - t)*t*p1 - + 3*(1 - t)*Math::pow<2>(t)*p2 - + Math::pow<3>(t)*p3; + Vector2 expected = Math::pow<3>(1 - t)*p0 + + 3*Math::pow<2>(1 - t)*t*p1 + + 3*(1 - t)*Math::pow<2>(t)*p2 + + Math::pow<3>(t)*p3; CORRADE_COMPARE(bezier.lerp(t), expected); } } diff --git a/src/Magnum/Math/Test/CMakeLists.txt b/src/Magnum/Math/Test/CMakeLists.txt index 39fd953fb..9f93ec1e1 100644 --- a/src/Magnum/Math/Test/CMakeLists.txt +++ b/src/Magnum/Math/Test/CMakeLists.txt @@ -43,7 +43,6 @@ corrade_add_test(MathMatrix4Test Matrix4Test.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathSwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathUnitTest UnitTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathAngleTest AngleTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test(MathBezierTest BezierTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathRangeTest RangeTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathDualTest DualTest.cpp LIBRARIES MagnumMathTestLib) @@ -52,6 +51,8 @@ corrade_add_test(MathDualComplexTest DualComplexTest.cpp LIBRARIES MagnumMathTes corrade_add_test(MathQuaternionTest QuaternionTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathDualQuaternionTest DualQuaternionTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathBezierTest BezierTest.cpp LIBRARIES MagnumMathTestLib) + set_property(TARGET MathVectorTest MathMatrixTest