From b59b8d431ef4455fb36f53a2649ce6a74ecbe89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 24 Aug 2016 23:28:17 +0200 Subject: [PATCH] Math: make Bezier::subdivide() return a pair and test it. --- src/Magnum/Math/Bezier.h | 16 ++++----- src/Magnum/Math/Test/BezierTest.cpp | 51 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/Magnum/Math/Bezier.h b/src/Magnum/Math/Bezier.h index ea1783638..9588b13ed 100644 --- a/src/Magnum/Math/Bezier.h +++ b/src/Magnum/Math/Bezier.h @@ -96,21 +96,19 @@ template class Bezier { template constexpr explicit Bezier(const Bezier& other) noexcept: Bezier{typename Implementation::GenerateSequence::Type(), other} {} /** - * @brief Subdivide the curve - * @param t The interpolation factor + * @brief Subdivide the curve at given position * - * 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). + * Returns two Bézier curves following the original curve, split at + * given interpolation factor. Uses the [De Casteljau's algorithm](https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm). + * @see @ref value() */ - std::array, 2> subdivide(Float t) const { + std::pair, Bezier> subdivide(Float t) const { const auto iPoints = calculateIntermediatePoints(t); Bezier left, right; - for(std::size_t i = 0; i <= order; ++i) { + for(std::size_t i = 0; i <= order; ++i) left[i] = iPoints[0][i]; - } - for(std::size_t i = 0, j = order; i <= order; --j, ++i) { + for(std::size_t i = 0, j = order; i <= order; --j, ++i) right[i] = iPoints[i][j]; - } return {left, right}; } diff --git a/src/Magnum/Math/Test/BezierTest.cpp b/src/Magnum/Math/Test/BezierTest.cpp index bf9387bab..1d4bfbf7e 100644 --- a/src/Magnum/Math/Test/BezierTest.cpp +++ b/src/Magnum/Math/Test/BezierTest.cpp @@ -57,6 +57,9 @@ struct BezierTest : Corrade::TestSuite::Tester { void valueLinear(); void valueQuadratic(); void valueCubic(); + void subdivideLinear(); + void subdivideQuadratic(); + void subdivideCubic(); void debug(); void configuration(); @@ -76,6 +79,9 @@ BezierTest::BezierTest() { &BezierTest::valueLinear, &BezierTest::valueQuadratic, &BezierTest::valueCubic, + &BezierTest::subdivideLinear, + &BezierTest::subdivideQuadratic, + &BezierTest::subdivideCubic, &BezierTest::debug, &BezierTest::configuration}); @@ -172,6 +178,51 @@ void BezierTest::valueCubic() { CORRADE_VERIFY(bezier.value(0.2f) != Math::lerp(bezier[0], bezier[3], 0.2f)); } +void BezierTest::subdivideLinear() { + LinearBezier2D bezier{Vector2{0.0f, 0.0f}, Vector2{20.0f, 4.0f}}; + + LinearBezier2D left, right; + std::tie(left, right) = bezier.subdivide(0.25f); + + CORRADE_COMPARE(left[0], bezier[0]); + CORRADE_COMPARE(left[1], right[0]); + CORRADE_COMPARE(right[1], bezier[1]); + CORRADE_COMPARE(left.value(0.8f), bezier.value(0.2f)); + CORRADE_COMPARE(right.value(0.33333f), bezier.value(0.5f)); + CORRADE_COMPARE(left, (LinearBezier2D{Vector2{0.0f, 0.0f}, Vector2{5.0f, 1.0f}})); + CORRADE_COMPARE(right, (LinearBezier2D{Vector2{5.0f, 1.0f}, Vector2{20.0f, 4.0f}})); +} + +void BezierTest::subdivideQuadratic() { + QuadraticBezier2D bezier{Vector2{0.0f, 0.0f}, Vector2{10.0f, 15.0f}, Vector2{20.0f, 4.0f}}; + + QuadraticBezier2D left, right; + std::tie(left, right) = bezier.subdivide(0.25f); + + CORRADE_COMPARE(left[0], bezier[0]); + CORRADE_COMPARE(left[2], right[0]); + CORRADE_COMPARE(right[2], bezier[2]); + CORRADE_COMPARE(left.value(0.8f), bezier.value(0.2f)); + CORRADE_COMPARE(right.value(0.33333f), bezier.value(0.5f)); + CORRADE_COMPARE(left, (QuadraticBezier2D{Vector2{0.0f, 0.0f}, Vector2{2.5f, 3.75f}, Vector2{5.0f, 5.875f}})); + CORRADE_COMPARE(right, (QuadraticBezier2D{Vector2{5.0f, 5.875f}, Vector2{12.5f, 12.25f}, Vector2{20.0f, 4.0f}})); +} + +void BezierTest::subdivideCubic() { + CubicBezier2D bezier{Vector2{0.0f, 0.0f}, Vector2{10.0f, 15.0f}, Vector2{20.0f, 4.0f}, Vector2{5.0f, -20.0f}}; + + CubicBezier2D left, right; + std::tie(left, right) = bezier.subdivide(0.25f); + + CORRADE_COMPARE(left[0], bezier[0]); + CORRADE_COMPARE(left[3], right[0]); + CORRADE_COMPARE(right[3], bezier[3]); + CORRADE_COMPARE(left.value(0.8f), bezier.value(0.2f)); + CORRADE_COMPARE(right.value(0.33333f), bezier.value(0.5f)); + CORRADE_COMPARE(left, (CubicBezier2D{Vector2{0.0f, 0.0f}, Vector2{2.5f, 3.75f}, Vector2{5.0f, 5.875f}, Vector2{7.10938f, 6.57812f}})); + CORRADE_COMPARE(right, (CubicBezier2D{Vector2{7.10938f, 6.57812f}, Vector2{13.4375f, 8.6875f}, Vector2{16.25f, -2.0f}, Vector2{5.0f, -20.0f}})); +} + void BezierTest::debug() { std::ostringstream out; Debug(&out) << CubicBezier2D{Vector2{0.0f, 1.0f}, Vector2{1.5f, -0.3f}, Vector2{2.1f, 0.5f}, Vector2{0.0f, 2.0f}};