2022-02-15 18:39:45 +08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-01-05 18:01:23 -08:00
|
|
|
import numpy as np
|
|
|
|
|
2019-02-09 09:08:57 -08:00
|
|
|
from manimlib.animation.animation import Animation
|
|
|
|
from manimlib.animation.transform import Transform
|
2020-06-07 12:23:08 -07:00
|
|
|
from manimlib.constants import ORIGIN
|
2022-04-12 19:19:59 +08:00
|
|
|
from manimlib.mobject.mobject import Group
|
2022-12-30 13:53:32 -08:00
|
|
|
from manimlib.mobject.types.vectorized_mobject import VMobject
|
|
|
|
from manimlib.mobject.types.vectorized_mobject import VGroup
|
2019-02-09 09:08:57 -08:00
|
|
|
from manimlib.utils.bezier import interpolate
|
2019-03-22 11:50:16 -07:00
|
|
|
from manimlib.utils.rate_functions import there_and_back
|
2019-02-09 09:08:57 -08:00
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
from typing import TYPE_CHECKING
|
2022-02-16 21:08:25 +08:00
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
if TYPE_CHECKING:
|
2022-12-14 11:27:00 -08:00
|
|
|
from typing import Callable
|
2022-02-15 18:39:45 +08:00
|
|
|
from manimlib.mobject.mobject import Mobject
|
2022-04-12 19:19:59 +08:00
|
|
|
from manimlib.scene.scene import Scene
|
2022-12-30 13:53:12 -08:00
|
|
|
from manimlib.typing import Vect3
|
2022-02-15 18:39:45 +08:00
|
|
|
|
2019-02-09 09:08:57 -08:00
|
|
|
|
2019-02-11 22:30:51 -08:00
|
|
|
|
2020-12-04 08:14:15 -08:00
|
|
|
class Fade(Transform):
|
2022-02-15 18:39:45 +08:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
mobject: Mobject,
|
|
|
|
shift: np.ndarray = ORIGIN,
|
|
|
|
scale: float = 1,
|
|
|
|
**kwargs
|
|
|
|
):
|
2020-12-04 08:14:15 -08:00
|
|
|
self.shift_vect = shift
|
|
|
|
self.scale_factor = scale
|
2020-06-07 12:23:08 -07:00
|
|
|
super().__init__(mobject, **kwargs)
|
|
|
|
|
2019-02-09 09:08:57 -08:00
|
|
|
|
2020-12-04 08:14:15 -08:00
|
|
|
class FadeIn(Fade):
|
2022-02-15 18:39:45 +08:00
|
|
|
def create_target(self) -> Mobject:
|
2019-02-09 09:36:37 -08:00
|
|
|
return self.mobject
|
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def create_starting_mobject(self) -> Mobject:
|
2019-02-09 10:09:45 -08:00
|
|
|
start = super().create_starting_mobject()
|
2020-06-07 12:23:08 -07:00
|
|
|
start.set_opacity(0)
|
2020-12-04 08:14:15 -08:00
|
|
|
start.scale(1.0 / self.scale_factor)
|
|
|
|
start.shift(-self.shift_vect)
|
2019-02-09 10:09:45 -08:00
|
|
|
return start
|
2019-02-09 09:08:57 -08:00
|
|
|
|
|
|
|
|
2020-12-04 08:14:15 -08:00
|
|
|
class FadeOut(Fade):
|
2022-12-14 11:27:00 -08:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
mobject: Mobject,
|
2022-12-30 13:53:12 -08:00
|
|
|
shift: Vect3 = ORIGIN,
|
2022-12-14 11:27:00 -08:00
|
|
|
remover: bool = True,
|
|
|
|
final_alpha_value: float = 0.0, # Put it back in original state when done,
|
|
|
|
**kwargs
|
|
|
|
):
|
|
|
|
super().__init__(
|
2022-12-14 16:27:25 -08:00
|
|
|
mobject, shift,
|
2022-12-14 11:27:00 -08:00
|
|
|
remover=remover,
|
|
|
|
final_alpha_value=final_alpha_value,
|
|
|
|
**kwargs
|
|
|
|
)
|
2020-12-04 08:14:15 -08:00
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def create_target(self) -> Mobject:
|
2020-12-04 08:14:15 -08:00
|
|
|
result = self.mobject.copy()
|
|
|
|
result.set_opacity(0)
|
|
|
|
result.shift(self.shift_vect)
|
|
|
|
result.scale(self.scale_factor)
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
2019-03-19 22:28:13 -07:00
|
|
|
class FadeInFromPoint(FadeIn):
|
2022-12-30 13:53:12 -08:00
|
|
|
def __init__(self, mobject: Mobject, point: Vect3, **kwargs):
|
2021-01-05 18:01:23 -08:00
|
|
|
super().__init__(
|
|
|
|
mobject,
|
|
|
|
shift=mobject.get_center() - point,
|
|
|
|
scale=np.inf,
|
|
|
|
**kwargs,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class FadeOutToPoint(FadeOut):
|
2022-12-30 13:53:12 -08:00
|
|
|
def __init__(self, mobject: Mobject, point: Vect3, **kwargs):
|
2021-01-05 18:01:23 -08:00
|
|
|
super().__init__(
|
|
|
|
mobject,
|
|
|
|
shift=point - mobject.get_center(),
|
|
|
|
scale=0,
|
|
|
|
**kwargs,
|
|
|
|
)
|
2019-03-19 22:28:13 -07:00
|
|
|
|
|
|
|
|
2021-01-03 16:53:49 -08:00
|
|
|
class FadeTransform(Transform):
|
2022-12-14 11:27:00 -08:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
mobject: Mobject,
|
|
|
|
target_mobject: Mobject,
|
|
|
|
stretch: bool = True,
|
|
|
|
dim_to_match: int = 1,
|
|
|
|
**kwargs
|
|
|
|
):
|
2021-01-03 16:53:49 -08:00
|
|
|
self.to_add_on_completion = target_mobject
|
2022-12-14 11:27:00 -08:00
|
|
|
self.stretch = stretch
|
|
|
|
self.dim_to_match = dim_to_match
|
|
|
|
|
2022-12-30 13:53:32 -08:00
|
|
|
group_type = Group
|
|
|
|
if isinstance(mobject, VMobject) and isinstance(target_mobject, VMobject):
|
|
|
|
group_type = VGroup
|
|
|
|
|
2021-01-03 17:57:43 -08:00
|
|
|
mobject.save_state()
|
2022-12-30 13:53:32 -08:00
|
|
|
super().__init__(group_type(mobject, target_mobject.copy()), **kwargs)
|
2021-01-03 16:53:49 -08:00
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def begin(self) -> None:
|
2021-01-03 16:53:49 -08:00
|
|
|
self.ending_mobject = self.mobject.copy()
|
|
|
|
Animation.begin(self)
|
|
|
|
# Both 'start' and 'end' consists of the source and target mobjects.
|
|
|
|
# At the start, the traget should be faded replacing the source,
|
|
|
|
# and at the end it should be the other way around.
|
|
|
|
start, end = self.starting_mobject, self.ending_mobject
|
|
|
|
for m0, m1 in ((start[1], start[0]), (end[0], end[1])):
|
|
|
|
self.ghost_to(m0, m1)
|
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def ghost_to(self, source: Mobject, target: Mobject) -> None:
|
2021-01-03 16:53:49 -08:00
|
|
|
source.replace(target, stretch=self.stretch, dim_to_match=self.dim_to_match)
|
|
|
|
source.set_opacity(0)
|
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def get_all_mobjects(self) -> list[Mobject]:
|
2021-01-03 16:53:49 -08:00
|
|
|
return [
|
|
|
|
self.mobject,
|
|
|
|
self.starting_mobject,
|
|
|
|
self.ending_mobject,
|
|
|
|
]
|
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def get_all_families_zipped(self) -> zip[tuple[Mobject]]:
|
2021-01-03 16:53:49 -08:00
|
|
|
return Animation.get_all_families_zipped(self)
|
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def clean_up_from_scene(self, scene: Scene) -> None:
|
2021-01-03 16:53:49 -08:00
|
|
|
Animation.clean_up_from_scene(self, scene)
|
|
|
|
scene.remove(self.mobject)
|
2021-01-03 17:57:43 -08:00
|
|
|
self.mobject[0].restore()
|
2021-01-03 16:53:49 -08:00
|
|
|
scene.add(self.to_add_on_completion)
|
|
|
|
|
|
|
|
|
|
|
|
class FadeTransformPieces(FadeTransform):
|
2022-02-15 18:39:45 +08:00
|
|
|
def begin(self) -> None:
|
2021-01-12 11:09:53 -10:00
|
|
|
self.mobject[0].align_family(self.mobject[1])
|
2021-01-03 16:53:49 -08:00
|
|
|
super().begin()
|
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def ghost_to(self, source: Mobject, target: Mobject) -> None:
|
2021-01-03 16:53:49 -08:00
|
|
|
for sm0, sm1 in zip(source.get_family(), target.get_family()):
|
|
|
|
super().ghost_to(sm0, sm1)
|
2019-02-09 09:08:57 -08:00
|
|
|
|
|
|
|
|
|
|
|
class VFadeIn(Animation):
|
|
|
|
"""
|
2019-02-09 10:09:45 -08:00
|
|
|
VFadeIn and VFadeOut only work for VMobjects,
|
2019-02-09 09:08:57 -08:00
|
|
|
"""
|
2022-12-14 11:27:00 -08:00
|
|
|
def __init__(self, vmobject: VMobject, suspend_mobject_updating: bool = False, **kwargs):
|
|
|
|
super().__init__(
|
|
|
|
vmobject,
|
|
|
|
suspend_mobject_updating=suspend_mobject_updating,
|
|
|
|
**kwargs
|
|
|
|
)
|
2019-02-09 09:08:57 -08:00
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def interpolate_submobject(
|
|
|
|
self,
|
|
|
|
submob: VMobject,
|
|
|
|
start: VMobject,
|
|
|
|
alpha: float
|
|
|
|
) -> None:
|
2019-02-09 10:09:45 -08:00
|
|
|
submob.set_stroke(
|
|
|
|
opacity=interpolate(0, start.get_stroke_opacity(), alpha)
|
2019-02-09 09:08:57 -08:00
|
|
|
)
|
2019-02-09 10:09:45 -08:00
|
|
|
submob.set_fill(
|
|
|
|
opacity=interpolate(0, start.get_fill_opacity(), alpha)
|
2019-02-09 09:08:57 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class VFadeOut(VFadeIn):
|
2022-12-14 11:27:00 -08:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
vmobject: VMobject,
|
|
|
|
remover: bool = True,
|
|
|
|
final_alpha_value: float = 0.0,
|
|
|
|
**kwargs
|
|
|
|
):
|
|
|
|
super().__init__(
|
|
|
|
vmobject,
|
|
|
|
remover=remover,
|
|
|
|
final_alpha_value=final_alpha_value,
|
|
|
|
**kwargs
|
|
|
|
)
|
2019-02-09 09:08:57 -08:00
|
|
|
|
2022-02-15 18:39:45 +08:00
|
|
|
def interpolate_submobject(
|
|
|
|
self,
|
|
|
|
submob: VMobject,
|
|
|
|
start: VMobject,
|
|
|
|
alpha: float
|
|
|
|
) -> None:
|
2019-02-09 10:56:51 -08:00
|
|
|
super().interpolate_submobject(submob, start, 1 - alpha)
|
2019-03-22 11:50:16 -07:00
|
|
|
|
|
|
|
|
|
|
|
class VFadeInThenOut(VFadeIn):
|
2022-12-14 11:27:00 -08:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
vmobject: VMobject,
|
|
|
|
rate_func: Callable[[float], float] = there_and_back,
|
|
|
|
remover: bool = True,
|
|
|
|
final_alpha_value: float = 0.5,
|
|
|
|
**kwargs
|
|
|
|
):
|
|
|
|
super().__init__(
|
|
|
|
vmobject,
|
|
|
|
rate_func=rate_func,
|
|
|
|
remover=remover,
|
|
|
|
final_alpha_value=final_alpha_value,
|
|
|
|
**kwargs
|
|
|
|
)
|