Commit 1b7ab224 authored by Lázár Bence Kis's avatar Lázár Bence Kis
Browse files

Newton-Raphson uses the previous result as its initial guess

parent 7096d0dc
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -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

@@ -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
@@ -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 }
        };
    }

@@ -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
+4 −6
Original line number Diff line number Diff line
@@ -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);
@@ -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