diff --git a/manim/mobject/types/vectorized_mobject.py b/manim/mobject/types/vectorized_mobject.py index fcb393f00b..806804708f 100644 --- a/manim/mobject/types/vectorized_mobject.py +++ b/manim/mobject/types/vectorized_mobject.py @@ -1932,12 +1932,18 @@ def pointwise_become_partial( upper_index, upper_residue = integer_interpolate(0, num_curves, b) nppc = self.n_points_per_curve + + # Copy vmobject.points if vmobject is self to prevent unintended in-place modification + vmobject_points = ( + vmobject.points.copy() if self is vmobject else vmobject.points + ) + # If both indices coincide, get a part of a single Bézier curve. if lower_index == upper_index: # Look at the "lower_index"-th Bézier curve and select its part from # t=lower_residue to t=upper_residue. self.points = partial_bezier_points( - vmobject.points[nppc * lower_index : nppc * (lower_index + 1)], + vmobject_points[nppc * lower_index : nppc * (lower_index + 1)], lower_residue, upper_residue, ) @@ -1947,19 +1953,19 @@ def pointwise_become_partial( # Look at the "lower_index"-th Bezier curve and select its part from # t=lower_residue to t=1. This is the first curve in self.points. self.points[:nppc] = partial_bezier_points( - vmobject.points[nppc * lower_index : nppc * (lower_index + 1)], + vmobject_points[nppc * lower_index : nppc * (lower_index + 1)], lower_residue, 1, ) # If there are more curves between the "lower_index"-th and the # "upper_index"-th Béziers, add them all to self.points. - self.points[nppc:-nppc] = vmobject.points[ + self.points[nppc:-nppc] = vmobject_points[ nppc * (lower_index + 1) : nppc * upper_index ] # Look at the "upper_index"-th Bézier curve and select its part from # t=0 to t=upper_residue. This is the last curve in self.points. self.points[-nppc:] = partial_bezier_points( - vmobject.points[nppc * upper_index : nppc * (upper_index + 1)], + vmobject_points[nppc * upper_index : nppc * (upper_index + 1)], 0, upper_residue, ) diff --git a/tests/module/mobject/geometry/test_unit_geometry.py b/tests/module/mobject/geometry/test_unit_geometry.py index b8594260b6..210af0fdf5 100644 --- a/tests/module/mobject/geometry/test_unit_geometry.py +++ b/tests/module/mobject/geometry/test_unit_geometry.py @@ -5,8 +5,12 @@ import numpy as np from manim import ( + DEGREES, + LEFT, + RIGHT, BackgroundRectangle, Circle, + Line, Polygram, Sector, Square, @@ -142,3 +146,36 @@ def test_changing_Square_side_length_updates_the_square_appropriately(): def test_Square_side_length_consistent_after_scale_and_rotation(): sq = Square(side_length=1).scale(3).rotate(np.pi / 4) assert np.isclose(sq.side_length, 3) + + +def test_line_with_buff_and_path_arc(): + line = Line(LEFT, RIGHT, path_arc=60 * DEGREES, buff=0.3) + expected_points = np.array( + [ + [-0.7299265, -0.12999304, 0.0], + [-0.6605293, -0.15719695, 0.0], + [-0.58965623, -0.18050364, 0.0], + [-0.51763809, -0.19980085, 0.0], + [-0.51763809, -0.19980085, 0.0], + [-0.43331506, -0.22239513, 0.0], + [-0.34760317, -0.23944429, 0.0], + [-0.26105238, -0.25083892, 0.0], + [-0.26105238, -0.25083892, 0.0], + [-0.1745016, -0.26223354, 0.0], + [-0.08729763, -0.26794919, 0.0], + [0.0, -0.26794919, 0.0], + [0.0, -0.26794919, 0.0], + [0.08729763, -0.26794919, 0.0], + [0.1745016, -0.26223354, 0.0], + [0.26105238, -0.25083892, 0.0], + [0.26105238, -0.25083892, 0.0], + [0.34760317, -0.23944429, 0.0], + [0.43331506, -0.22239513, 0.0], + [0.51763809, -0.19980085, 0.0], + [0.51763809, -0.19980085, 0.0], + [0.58965623, -0.18050364, 0.0], + [0.6605293, -0.15719695, 0.0], + [0.7299265, -0.12999304, 0.0], + ] + ) + np.testing.assert_allclose(line.points, expected_points) diff --git a/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py b/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py index 23d5e008d8..ded0507877 100644 --- a/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py +++ b/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py @@ -526,3 +526,25 @@ def test_proportion_from_point(): abc.scale(0.8) props = [abc.proportion_from_point(p) for p in abc.get_vertices()] np.testing.assert_allclose(props, [0, 1 / 3, 2 / 3]) + + +def test_pointwise_become_partial_where_vmobject_is_self(): + sq = Square() + sq.pointwise_become_partial(vmobject=sq, a=0.2, b=0.7) + expected_points = np.array( + [ + [-0.6, 1.0, 0.0], + [-0.73333333, 1.0, 0.0], + [-0.86666667, 1.0, 0.0], + [-1.0, 1.0, 0.0], + [-1.0, 1.0, 0.0], + [-1.0, 0.33333333, 0.0], + [-1.0, -0.33333333, 0.0], + [-1.0, -1.0, 0.0], + [-1.0, -1.0, 0.0], + [-0.46666667, -1.0, 0.0], + [0.06666667, -1.0, 0.0], + [0.6, -1.0, 0.0], + ] + ) + np.testing.assert_allclose(sq.points, expected_points)