Rewrite manim.utils.bezier.get_quadratic_approximation_of_cubic()
to produce curves which can be animated smoothly
#3829
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Overview: What does this pull request change?
Motivation and Explanation: Why and how do your changes improve the library?
The current implementation splits the cubic Bézier at its inflection point (if it exists, otherwise simply
t = 0.5
). This sounds quite right: the curvature changes at the inflection point, something which can't be captured by a single quadratic Bézier, so we split the curve into two at that point in order to approximate each curvature with different curves.However:
BezierScene.mp4
As you can see, the speed of the point (1st derivative of the Béziers) is discontinuous when transitioning from one quadratic to the other.
This is problematic for 2 reasons:
Create
,Write
orDrawBorderThenFill
won't draw the resultantVMobject
as smoothly as it could (the drawing speed might suddenly change)... even if it the original cubic spline was actually smooth.OpenGLVMobject.make_smooth()
is called, it interpolates the curve anchors with a smooth cubic spline, and then proceeds to approximate it with quadratic Béziers by callingget_quadratic...()
. So,OpenGLVMobject.make_smooth()
promises to transform the Mobject into a smooth curve, butget_quadratic...()
breaks that promise.Therefore I propose an alternate implementation: instead of forcing a split at a specific point on the curve, I explicitly require that the curves and their 1st derivatives are continuous. (See the docstring of
get_quadratic...()
for more details on the mathematical process)With this implementation, the result is as follows:
BezierScene.mp4
Another example with more exotic curves (the spline is, however, not smooth, so the speeds at the green points aren't continuous:
BezierScene.mp4
BezierScene.mp4
Notice that the resultant curve might be slightly more off than the original approximation. The original seems more proper for static images where it's enough that the tangents are continuous (the speed directions are the same, rather than the speeds themselves). However, Manim is mainly an animation library, so it's necessary that the speeds are also continuous in this case.
Links to added or changed documentation pages
https://manimce--3829.org.readthedocs.build/en/3829/reference/manim.utils.bezier.html#manim.utils.bezier.get_quadratic_approximation_of_cubic
Further Information and Comments
The code I used:
Reviewer Checklist