Skip to content

Fix :meth:VMobject.pointwise_become_partial failing when vmobject is self #4193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions manim/mobject/types/vectorized_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand All @@ -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,
)
Expand Down
37 changes: 37 additions & 0 deletions tests/module/mobject/geometry/test_unit_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
import numpy as np

from manim import (
DEGREES,
LEFT,
RIGHT,
BackgroundRectangle,
Circle,
Line,
Polygram,
Sector,
Square,
Expand Down Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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)