You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When creating Arcs for large angles, the control point calculation gives noticeably inaccurate results. Even for the built-in circle drawn with 8 arcs anchored on the circle, e.g. the point at theta = tau/16 (halfway through the first arc) falls short by more than 1% by my calculation.
The calculation of the control points is to blame. The formula can be improved to give much more accurate circular arcs.
In `manim.mobject.geometry.arc`, the internal calculation of control points looks like (click to expand):
def _set_pre_positioned_points(self):
anchors = np.array(
[
np.cos(a) * RIGHT + np.sin(a) * UP
for a in np.linspace(
self.start_angle,
self.start_angle + self.angle,
self.num_components,
)
],
)
# Figure out which control points will give the
# Appropriate tangent lines to the circle
d_theta = self.angle / (self.num_components - 1.0)
tangent_vectors = np.zeros(anchors.shape)
# Rotate all 90 degrees, via (x, y) -> (-y, x)
tangent_vectors[:, 1] = anchors[:, 0]
tangent_vectors[:, 0] = -anchors[:, 1]
# Use tangent vectors to deduce anchors
handles1 = anchors[:-1] + (d_theta / 3) * tangent_vectors[:-1]
handles2 = anchors[1:] - (d_theta / 3) * tangent_vectors[1:]
self.set_anchors_and_handles(anchors[:-1], handles1, handles2, anchors[1:])
The d_theta / 3 factor on the second-last and third-last lines should instead be 4/3 * np.tan(d_theta/4). This value approaches d_theta / 3 in the limit as d_theta goes to 0, but is way off for larger values. The resulting approximation aligns the midpoint of the Bezier curve with the corresponding circular arc.
As noted in the latter link, the result can be improved further; however, the benefits are much smaller, the necessary control point values are quite close, and there is no explicit formula given (only the results for an angle of tau/4). (Also, seeking the absolute best possible approximation in terms of the absolute deviation from the circle, will result in cusps at the handle points.)
Expected behavior
Circular arcs should appear circular even for large spans, and should not require subdivision into smaller arcs to achieve a good approximation. The reproduction code below results in a noticeably compressed ellipse (by a factor of pi/4, in fact).
How to reproduce the issue
frommanimimport*c=Circle(num_components=3) # two arcsScene().add(c).render(preview=True)
Additional media files
Images/GIFs
I get a result like so:
With an improved calculation, much better results are possible. Here are examples from my own code, working directly in Cairo, showing the results with Manim's formula vs. the improved formula (for a circle made with three arcs). The shape goes from noticeably "wobbly" to indistinguishable from correct (at least at 256x256 circle size).
The text was updated successfully, but these errors were encountered:
Using 4/3 * np.tan(d_theta/4) seems pretty fine to me! 👍
Going even further, as suggested by the other methods in the pages you linked, is very complex and impractical. Plus, as you mentioned, it results in much smaller gains which aren't really noticeable.
Description of bug / unexpected behavior
When creating Arcs for large angles, the control point calculation gives noticeably inaccurate results. Even for the built-in circle drawn with 8 arcs anchored on the circle, e.g. the point at theta = tau/16 (halfway through the first arc) falls short by more than 1% by my calculation.
The calculation of the control points is to blame. The formula can be improved to give much more accurate circular arcs.
In `manim.mobject.geometry.arc`, the internal calculation of control points looks like (click to expand):
The
d_theta / 3
factor on the second-last and third-last lines should instead be4/3 * np.tan(d_theta/4)
. This value approachesd_theta / 3
in the limit asd_theta
goes to 0, but is way off for larger values. The resulting approximation aligns the midpoint of the Bezier curve with the corresponding circular arc.Citations for this calculation:
https://stackoverflow.com/questions/1734745
https://spencermortensen.com/articles/bezier-circle/
As noted in the latter link, the result can be improved further; however, the benefits are much smaller, the necessary control point values are quite close, and there is no explicit formula given (only the results for an angle of tau/4). (Also, seeking the absolute best possible approximation in terms of the absolute deviation from the circle, will result in cusps at the handle points.)
Expected behavior
Circular arcs should appear circular even for large spans, and should not require subdivision into smaller arcs to achieve a good approximation. The reproduction code below results in a noticeably compressed ellipse (by a factor of pi/4, in fact).
How to reproduce the issue
Additional media files
Images/GIFs
I get a result like so:
With an improved calculation, much better results are possible. Here are examples from my own code, working directly in Cairo, showing the results with Manim's formula vs. the improved formula (for a circle made with three arcs). The shape goes from noticeably "wobbly" to indistinguishable from correct (at least at 256x256 circle size).
The text was updated successfully, but these errors were encountered: