diff --git a/manim/animation/fading.py b/manim/animation/fading.py index 99b9bfe195..61e6625edd 100644 --- a/manim/animation/fading.py +++ b/manim/animation/fading.py @@ -20,10 +20,9 @@ def construct(self): ] import numpy as np -from typing_extensions import Any +from typing import Any, Union from manim.mobject.opengl.opengl_mobject import OpenGLMobject - from ..animation.transform import Transform from ..constants import ORIGIN from ..mobject.mobject import Group, Mobject @@ -56,25 +55,44 @@ def __init__( scale: float = 1, **kwargs: Any, ) -> None: + if not mobjects: - raise ValueError("At least one mobject must be passed.") + raise ValueError("At least one mobject must be provided for fading.") + + for mob in mobjects: + if not isinstance(mob, Mobject): + raise TypeError(f"Expected Mobject instances, got {type(mob)}") + mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects) self.point_target = False + if shift is None: if target_position is not None: if isinstance(target_position, (Mobject, OpenGLMobject)): target_position = target_position.get_center() - shift = target_position - mobject.get_center() + elif not isinstance(target_position, np.ndarray): + raise TypeError( + "target_position must be a Mobject or np.ndarray" + ) + shift = np.array(target_position) - mobject.get_center() self.point_target = True else: shift = ORIGIN + else: + if not isinstance(shift, np.ndarray): + raise TypeError("shift must be of type np.ndarray") + + if not isinstance(scale, (int, float)): + raise TypeError("scale must be a number") + self.shift_vector = shift self.scale_factor = scale + super().__init__(mobject, **kwargs) def _create_faded_mobject(self, fadeIn: bool) -> Mobject: - """Create a faded, shifted and scaled copy of the mobject. + """Create a faded, shifted and scaled copy of the mobject. Parameters ---------- @@ -86,16 +104,24 @@ def _create_faded_mobject(self, fadeIn: bool) -> Mobject: Mobject The faded, shifted and scaled copy of the mobject. """ - faded_mobject: Mobject = self.mobject.copy() # type: ignore[assignment] + + faded_mobject = self.mobject.copy() # type: ignore[assignment] + + if not isinstance(faded_mobject, Mobject): + raise RuntimeError("Failed to create faded mobject copy.") + faded_mobject.fade(1) + direction_modifier = -1 if fadeIn and not self.point_target else 1 + faded_mobject.shift(self.shift_vector * direction_modifier) faded_mobject.scale(self.scale_factor) + return faded_mobject class FadeIn(_Fade): - r"""Fade in :class:`~.Mobject` s. + r"""Fade in :class:`~.Mobject` s. Parameters ---------- @@ -143,7 +169,7 @@ def create_starting_mobject(self) -> Mobject: class FadeOut(_Fade): - r"""Fade out :class:`~.Mobject` s. + r"""Fade out :class:`~.Mobject` s. Parameters ---------- @@ -187,5 +213,9 @@ def create_target(self) -> Mobject: return self._create_faded_mobject(fadeIn=False) def clean_up_from_scene(self, scene: Scene) -> None: + """Remove the mobject from the scene after fading out.""" super().clean_up_from_scene(scene) - self.interpolate(0) + try: + self.interpolate(0) + except Exception as e: + raise RuntimeError(f"Error during cleanup interpolation: {e}")