treat cubic curve as quad when control point equals endpoint using a follow path with oriented mode on, if the target path's last two points were a cubic bezier and a straight line, we were not calculating correctly the tangent at distance 100%. That would cause the object with the follow path constraint to shift direction in the last position. This PR fixes the issue by changing how that edge case works and calculates the tangent as a quadratic bezier curve instead. fixes #6969 Diffs= 522a31bc2 treat cubic curve as quad when control point equals endpoint (#6919) Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head index ca28551..bd039cb 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -473dbcb5ccba6d5cb077f762ac7094ca492d6319 +522a31bc24b4f8179b9a4f27d9a8154af385767a
diff --git a/src/math/contour_measure.cpp b/src/math/contour_measure.cpp index 0aa804a..57c833c 100644 --- a/src/math/contour_measure.cpp +++ b/src/math/contour_measure.cpp
@@ -66,6 +66,27 @@ static ContourMeasure::PosTan eval_cubic(const Vec2D pts[], float t) { assert(t >= 0 && t <= 1); + // When t==0 and t==1, the most accurate way to find tangents is by differencing. + if (t == 0 || t == 1) + { + if (t == 0) + { + return {pts[0], + (pts[0] != pts[1] ? pts[1] + : pts[1] != pts[2] ? pts[2] + : pts[3]) - + pts[0] + + }; + } + else + { + return {pts[3], + pts[3] - (pts[3] != pts[2] ? pts[2] + : pts[2] != pts[1] ? pts[1] + : pts[0])}; + } + } const EvalCubic eval(pts); @@ -139,11 +160,9 @@ ContourMeasure::PosTan ContourMeasure::getPosTan(float distance) const { // specal-case end of the contour - if (distance >= m_length) + if (distance > m_length) { - size_t N = m_points.size(); - assert(N > 1); - return {m_points[N - 1], (m_points[N - 1] - m_points[N - 2]).normalized()}; + distance = m_length; } if (distance < 0)