From b9f6c13cebdf229037328c6aece500097cb5600d Mon Sep 17 00:00:00 2001 From: Jason Grace <110117391+JasonGrace2282@users.noreply.github.com> Date: Sun, 19 Nov 2023 03:20:59 -0500 Subject: [PATCH] Allow accessing ghost vectors in :class:`.LinearTransformationScene` (#3435) * Fix CSV reader adding empty files Fixes issue #3311 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Added LinearTransformationScene.ghost_vectors * Added test and prevented empty VGroups as ghost vectors * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fixed typo in example * Added ability to join together multiple renders * Revert "Added ability to join together multiple renders" (wrong branch) This reverts commit dee29c390f433bb3964c13b2f6ccc991c18db925. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- manim/scene/vector_space_scene.py | 18 ++++++++++++++--- tests/test_linear_transformation_scene.py | 24 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/test_linear_transformation_scene.py diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index f651c2c86a..d39ce32895 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -572,7 +572,7 @@ def __init__(self, **kwargs): self, show_coordinates=True, leave_ghost_vectors=True, - *kwargs + **kwargs ) def construct(self): @@ -616,6 +616,8 @@ def __init__( }, } + self.ghost_vectors = VGroup() + self.foreground_plane_kwargs = { "x_range": np.array([-config["frame_width"], config["frame_width"], 1.0]), "y_range": np.array([-config["frame_width"], config["frame_width"], 1.0]), @@ -741,6 +743,13 @@ def add_moving_mobject( mobject.target = target_mobject self.add_special_mobjects(self.moving_mobjects, mobject) + def get_ghost_vectors(self) -> VGroup: + """ + Returns all ghost vectors ever added to ``self``. Each element is a ``VGroup`` of + two ghost vectors. + """ + return self.ghost_vectors + def get_unit_square( self, color: str = YELLOW, opacity: float = 0.3, stroke_width: float = 3 ): @@ -996,8 +1005,11 @@ def get_piece_movement(self, pieces: list | tuple | np.ndarray): """ start = VGroup(*pieces) target = VGroup(*(mob.target for mob in pieces)) - if self.leave_ghost_vectors: - self.add(start.copy().fade(0.7)) + # don't add empty VGroups + if self.leave_ghost_vectors and start.submobjects: + # start.copy() gives a VGroup of Vectors + self.ghost_vectors.add(start.copy().fade(0.7)) + self.add(self.ghost_vectors[-1]) return Transform(start, target, lag_ratio=0) def get_moving_mobject_movement(self, func: Callable[[np.ndarray], np.ndarray]): diff --git a/tests/test_linear_transformation_scene.py b/tests/test_linear_transformation_scene.py new file mode 100644 index 0000000000..c45e3f6997 --- /dev/null +++ b/tests/test_linear_transformation_scene.py @@ -0,0 +1,24 @@ +from manim import RIGHT, UP, LinearTransformationScene, Vector, VGroup + +__module_test__ = "vector_space_scene" + + +def test_ghost_vectors_len_and_types(): + scene = LinearTransformationScene() + scene.leave_ghost_vectors = True + + # prepare vectors (they require a vmobject as their target) + v1, v2 = Vector(RIGHT), Vector(RIGHT) + v1.target, v2.target = Vector(UP), Vector(UP) + + # ghost_vector addition is in this method + scene.get_piece_movement((v1, v2)) + + ghosts = scene.get_ghost_vectors() + assert len(ghosts) == 1 + # check if there are two vectors in the ghost vector VGroup + assert len(ghosts[0]) == 2 + + # check types of ghost vectors + assert isinstance(ghosts, VGroup) and isinstance(ghosts[0], VGroup) + assert all(isinstance(x, Vector) for x in ghosts[0])