Loading anim/include/anim/interpolator.hpp +8 −5 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ std::vector<scalar> cardanoSolve(scalar a, scalar b, scalar c, scalar d); vec2 evaluateBezierDerivative(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar t); vec2 evaluateBezier (const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar t); scalar solveBezierCardano (const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX); scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX); scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX, scalar initialGuess); } // namespace helpers Loading Loading @@ -128,14 +128,16 @@ struct BezierInterpolator : public Interpolator<T> { scalar t = p0.x + normalizedTime * (p3.x - p0.x); if constexpr (Method == NEWTON_RAPHSON) { return helpers::solveBezierNewtonRaphson(p0, p1, p2, p3, t); m_tSolved = helpers::solveBezierNewtonRaphson(p0, p1, p2, p3, t, m_tSolved); } else if constexpr (Method == CARDANO) { return helpers::solveBezierCardano(p0, p1, p2, p3, t); m_tSolved = helpers::solveBezierCardano(p0, p1, p2, p3, t); } else { throw std::runtime_error("Unknown Bezier method!"); } return helpers::evaluateBezier(p0, p1, p2, p3, m_tSolved).y; } T interpolate(const Keyframe<T>& start, const Keyframe<T>& end, scalar normalizedTime) const override Loading Loading @@ -171,8 +173,8 @@ struct BezierInterpolator : public Interpolator<T> { std::array<vec2, 2> getControlPoints(const Keyframe<T>& start, const Keyframe<T>& end) const { return { vec2{ start.time() + m_handles.leftHandle.x, start.value/* <scalar> */() + m_handles.leftHandle.y }, vec2{ end.time() + m_handles.rightHandle.x, end.value/* <scalar> */() + m_handles.rightHandle.y } vec2{ start.time() + m_handles.leftHandle.x, start.value() + m_handles.leftHandle.y }, vec2{ end.time() + m_handles.rightHandle.x, end.value() + m_handles.rightHandle.y } }; } Loading @@ -183,6 +185,7 @@ struct BezierInterpolator : public Interpolator<T> { private: BezierHandles m_handles; mutable scalar m_tSolved = 0.5_s; }; // Concrete interpolator for ease in/out Loading anim/src/interpolator.cpp +4 −6 Original line number Diff line number Diff line Loading @@ -95,13 +95,13 @@ scalar solveBezierCardano( } } return static_cast<scalar>(evaluateBezier(p0, p1, p2, p3, tSolved).y); return tSolved; } scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX) { scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX, scalar initialGuess) { // Newton-Raphson iteration to find the t value for desired x const int MAX_ITERATIONS = 8; scalar currentT = 0.5_s; scalar currentT = initialGuess; for (int i = 0; i < MAX_ITERATIONS; i++) { vec2 point = evaluateBezier(p0, p1, p2, p3, currentT); Loading @@ -118,9 +118,7 @@ scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, currentT = currentT - f / df; currentT = clamp(currentT, 0.0_s, 1.0_s); } vec2 finalPoint = evaluateBezier(p0, p1, p2, p3, currentT); return finalPoint.y; return currentT; } } // namespace helpers Loading Loading
anim/include/anim/interpolator.hpp +8 −5 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ std::vector<scalar> cardanoSolve(scalar a, scalar b, scalar c, scalar d); vec2 evaluateBezierDerivative(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar t); vec2 evaluateBezier (const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar t); scalar solveBezierCardano (const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX); scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX); scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX, scalar initialGuess); } // namespace helpers Loading Loading @@ -128,14 +128,16 @@ struct BezierInterpolator : public Interpolator<T> { scalar t = p0.x + normalizedTime * (p3.x - p0.x); if constexpr (Method == NEWTON_RAPHSON) { return helpers::solveBezierNewtonRaphson(p0, p1, p2, p3, t); m_tSolved = helpers::solveBezierNewtonRaphson(p0, p1, p2, p3, t, m_tSolved); } else if constexpr (Method == CARDANO) { return helpers::solveBezierCardano(p0, p1, p2, p3, t); m_tSolved = helpers::solveBezierCardano(p0, p1, p2, p3, t); } else { throw std::runtime_error("Unknown Bezier method!"); } return helpers::evaluateBezier(p0, p1, p2, p3, m_tSolved).y; } T interpolate(const Keyframe<T>& start, const Keyframe<T>& end, scalar normalizedTime) const override Loading Loading @@ -171,8 +173,8 @@ struct BezierInterpolator : public Interpolator<T> { std::array<vec2, 2> getControlPoints(const Keyframe<T>& start, const Keyframe<T>& end) const { return { vec2{ start.time() + m_handles.leftHandle.x, start.value/* <scalar> */() + m_handles.leftHandle.y }, vec2{ end.time() + m_handles.rightHandle.x, end.value/* <scalar> */() + m_handles.rightHandle.y } vec2{ start.time() + m_handles.leftHandle.x, start.value() + m_handles.leftHandle.y }, vec2{ end.time() + m_handles.rightHandle.x, end.value() + m_handles.rightHandle.y } }; } Loading @@ -183,6 +185,7 @@ struct BezierInterpolator : public Interpolator<T> { private: BezierHandles m_handles; mutable scalar m_tSolved = 0.5_s; }; // Concrete interpolator for ease in/out Loading
anim/src/interpolator.cpp +4 −6 Original line number Diff line number Diff line Loading @@ -95,13 +95,13 @@ scalar solveBezierCardano( } } return static_cast<scalar>(evaluateBezier(p0, p1, p2, p3, tSolved).y); return tSolved; } scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX) { scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, scalar targetX, scalar initialGuess) { // Newton-Raphson iteration to find the t value for desired x const int MAX_ITERATIONS = 8; scalar currentT = 0.5_s; scalar currentT = initialGuess; for (int i = 0; i < MAX_ITERATIONS; i++) { vec2 point = evaluateBezier(p0, p1, p2, p3, currentT); Loading @@ -118,9 +118,7 @@ scalar solveBezierNewtonRaphson(const vec2& p0, const vec2& p1, const vec2& p2, currentT = currentT - f / df; currentT = clamp(currentT, 0.0_s, 1.0_s); } vec2 finalPoint = evaluateBezier(p0, p1, p2, p3, currentT); return finalPoint.y; return currentT; } } // namespace helpers Loading