diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 2cd7aff807..b8ca5c31fd 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -327,6 +327,43 @@ def __init__( self.clear_points() self.add(*dashes) + def _reset_dashes_from_endpoints( + self, start: Point3DLike, end: Point3DLike + ) -> None: + underlying = Line(np.asarray(start, dtype=float), np.asarray(end, dtype=float)) + underlying.match_style(self) + for attr in ("path_arc", "buff"): + if hasattr(self, attr): + setattr(underlying, attr, getattr(self, attr)) + if underlying.path_arc != 0: + underlying.generate_points() + num_dashes = max( + 2, + int( + np.ceil( + (underlying.get_length() / self.dash_length) * self.dashed_ratio + ) + ), + ) + dashes = DashedVMobject( + underlying, + num_dashes=num_dashes, + dashed_ratio=self.dashed_ratio, + ) + self.set_submobjects(list(dashes.submobjects)) + + def put_start_and_end_on( + self, + start: Point3DLike, + end: Point3DLike, + ) -> Self: + start_arr = np.asarray(start, dtype=float) + end_arr = np.asarray(end, dtype=float) + if np.allclose(start_arr, end_arr): + return super().put_start_and_end_on(start, end) + self._reset_dashes_from_endpoints(start, end) + return self + def _calculate_num_dashes(self) -> int: """Returns the number of dashes in the dashed line. diff --git a/tests/module/mobject/types/vectorized_mobject/test_dashed_vmobject.py b/tests/module/mobject/types/vectorized_mobject/test_dashed_vmobject.py index 499d017e45..35a83cfb8f 100644 --- a/tests/module/mobject/types/vectorized_mobject/test_dashed_vmobject.py +++ b/tests/module/mobject/types/vectorized_mobject/test_dashed_vmobject.py @@ -1,4 +1,6 @@ -from manim import ORIGIN, UR, Arrow, DashedLine, DashedVMobject, VGroup +import pytest + +from manim import ORIGIN, RIGHT, UR, Arrow, DashedLine, DashedVMobject, VGroup from manim.mobject.geometry.tips import ArrowTip, StealthTip @@ -57,3 +59,15 @@ def test_become_nonzero_to_zero_dashed_line_does_not_crash(): normal = DashedLine(ORIGIN, 2 * UR) zero = DashedLine(ORIGIN, ORIGIN) normal.become(zero) + + +def test_dashed_line_recomputes_dashes_on_put_start_and_end_on(): + """Regression test for https://github.com/ManimCommunity/manim/issues/3989.""" + line = DashedLine(ORIGIN, RIGHT) + initial_dash_length = line.submobjects[0].get_length() + initial_num_dashes = len(line.submobjects) + line.put_start_and_end_on(ORIGIN, 5 * RIGHT) + assert len(line.submobjects) > initial_num_dashes + assert line.submobjects[0].get_length() == pytest.approx( + initial_dash_length, rel=0.05 + )