Skip to content

Commit

Permalink
treat cubic curve as quad when control point equals endpoint
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
bodymovin and bodymovin committed Apr 2, 2024
1 parent 820ce85 commit 40cc4f8
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
473dbcb5ccba6d5cb077f762ac7094ca492d6319
522a31bc24b4f8179b9a4f27d9a8154af385767a
27 changes: 23 additions & 4 deletions src/math/contour_measure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,27 @@ static ContourMeasure::PosTan eval_quad(const Vec2D pts[], float t)
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);

Expand Down Expand Up @@ -139,11 +160,9 @@ void ContourMeasure::Segment::extract(RawPath* dst,
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)
Expand Down

0 comments on commit 40cc4f8

Please sign in to comment.