mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 06:22:54 +08:00
Add .animate syntax
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from manimlib.mobject.mobject import Mobject
|
from manimlib.mobject.mobject import Mobject, _AnimationBuilder
|
||||||
from manimlib.utils.config_ops import digest_config
|
from manimlib.utils.config_ops import digest_config
|
||||||
from manimlib.utils.rate_functions import smooth
|
from manimlib.utils.rate_functions import smooth
|
||||||
from manimlib.utils.simple_functions import clip
|
from manimlib.utils.simple_functions import clip
|
||||||
@ -159,3 +159,13 @@ class Animation(object):
|
|||||||
|
|
||||||
def is_remover(self):
|
def is_remover(self):
|
||||||
return self.remover
|
return self.remover
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_animation(anim):
|
||||||
|
if isinstance(anim, _AnimationBuilder):
|
||||||
|
return anim.build()
|
||||||
|
|
||||||
|
if isinstance(anim, Animation):
|
||||||
|
return anim
|
||||||
|
|
||||||
|
raise TypeError(f"Object {anim} cannot be converted to an animation")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from manimlib.animation.animation import Animation
|
from manimlib.animation.animation import Animation, prepare_animation
|
||||||
from manimlib.mobject.mobject import Group
|
from manimlib.mobject.mobject import Group
|
||||||
from manimlib.utils.bezier import integer_interpolate
|
from manimlib.utils.bezier import integer_interpolate
|
||||||
from manimlib.utils.bezier import interpolate
|
from manimlib.utils.bezier import interpolate
|
||||||
@ -29,7 +29,7 @@ class AnimationGroup(Animation):
|
|||||||
|
|
||||||
def __init__(self, *animations, **kwargs):
|
def __init__(self, *animations, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
self.animations = animations
|
self.animations = [prepare_animation(anim) for anim in animations]
|
||||||
if self.group is None:
|
if self.group is None:
|
||||||
self.group = Group(*remove_list_redundancies(
|
self.group = Group(*remove_list_redundancies(
|
||||||
[anim.mobject for anim in animations]
|
[anim.mobject for anim in animations]
|
||||||
|
@ -149,6 +149,12 @@ class MoveToTarget(Transform):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class _MethodAnimation(MoveToTarget):
|
||||||
|
def __init__(self, mobject, methods):
|
||||||
|
self.methods = methods
|
||||||
|
super().__init__(mobject)
|
||||||
|
|
||||||
|
|
||||||
class ApplyMethod(Transform):
|
class ApplyMethod(Transform):
|
||||||
def __init__(self, method, *args, **kwargs):
|
def __init__(self, method, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -80,6 +80,11 @@ class Mobject(object):
|
|||||||
if self.depth_test:
|
if self.depth_test:
|
||||||
self.apply_depth_test()
|
self.apply_depth_test()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def animate(self):
|
||||||
|
# Borrowed from https://github.com/ManimCommunity/manim/
|
||||||
|
return _AnimationBuilder(self)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.__class__.__name__
|
return self.__class__.__name__
|
||||||
|
|
||||||
@ -1571,3 +1576,51 @@ class Point(Mobject):
|
|||||||
|
|
||||||
def set_location(self, new_loc):
|
def set_location(self, new_loc):
|
||||||
self.set_points(np.array(new_loc, ndmin=2, dtype=float))
|
self.set_points(np.array(new_loc, ndmin=2, dtype=float))
|
||||||
|
|
||||||
|
|
||||||
|
class _AnimationBuilder:
|
||||||
|
def __init__(self, mobject):
|
||||||
|
self.mobject = mobject
|
||||||
|
self.overridden_animation = None
|
||||||
|
self.mobject.generate_target()
|
||||||
|
self.is_chaining = False
|
||||||
|
self.methods = []
|
||||||
|
|
||||||
|
def __getattr__(self, method_name):
|
||||||
|
method = getattr(self.mobject.target, method_name)
|
||||||
|
self.methods.append(method)
|
||||||
|
has_overridden_animation = hasattr(method, "_override_animate")
|
||||||
|
|
||||||
|
if (self.is_chaining and has_overridden_animation) or self.overridden_animation:
|
||||||
|
raise NotImplementedError(
|
||||||
|
"Method chaining is currently not supported for "
|
||||||
|
"overridden animations"
|
||||||
|
)
|
||||||
|
|
||||||
|
def update_target(*method_args, **method_kwargs):
|
||||||
|
if has_overridden_animation:
|
||||||
|
self.overridden_animation = method._override_animate(
|
||||||
|
self.mobject, *method_args, **method_kwargs
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
method(*method_args, **method_kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
self.is_chaining = True
|
||||||
|
return update_target
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
from manimlib.animation.transform import _MethodAnimation
|
||||||
|
|
||||||
|
if self.overridden_animation:
|
||||||
|
return self.overridden_animation
|
||||||
|
|
||||||
|
return _MethodAnimation(self.mobject, self.methods)
|
||||||
|
|
||||||
|
|
||||||
|
def override_animate(method):
|
||||||
|
def decorator(animation_method):
|
||||||
|
method._override_animate = animation_method
|
||||||
|
return animation_method
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
@ -10,7 +10,7 @@ import numpy as np
|
|||||||
import time
|
import time
|
||||||
from IPython.terminal.embed import InteractiveShellEmbed
|
from IPython.terminal.embed import InteractiveShellEmbed
|
||||||
|
|
||||||
from manimlib.animation.animation import Animation
|
from manimlib.animation.animation import prepare_animation
|
||||||
from manimlib.animation.transform import MoveToTarget
|
from manimlib.animation.transform import MoveToTarget
|
||||||
from manimlib.mobject.mobject import Point
|
from manimlib.mobject.mobject import Point
|
||||||
from manimlib.camera.camera import Camera
|
from manimlib.camera.camera import Camera
|
||||||
@ -348,10 +348,7 @@ class Scene(object):
|
|||||||
state["method_args"] = []
|
state["method_args"] = []
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if isinstance(arg, Animation):
|
if inspect.ismethod(arg):
|
||||||
compile_method(state)
|
|
||||||
animations.append(arg)
|
|
||||||
elif inspect.ismethod(arg):
|
|
||||||
compile_method(state)
|
compile_method(state)
|
||||||
state["curr_method"] = arg
|
state["curr_method"] = arg
|
||||||
elif state["curr_method"] is not None:
|
elif state["curr_method"] is not None:
|
||||||
@ -362,7 +359,13 @@ class Scene(object):
|
|||||||
you meant to pass in as a Scene.play argument
|
you meant to pass in as a Scene.play argument
|
||||||
""")
|
""")
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid play arguments")
|
try:
|
||||||
|
anim = prepare_animation(arg)
|
||||||
|
except TypeError:
|
||||||
|
raise TypeError(f"Unexpected argument {arg} passed to Scene.play()")
|
||||||
|
|
||||||
|
compile_method(state)
|
||||||
|
animations.append(anim)
|
||||||
compile_method(state)
|
compile_method(state)
|
||||||
|
|
||||||
for animation in animations:
|
for animation in animations:
|
||||||
|
Reference in New Issue
Block a user