mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 08:54:38 +08:00
Fixed bugs in Succession and AnimationGroup, and also created purely virtual Container class from which both Scene and MObject derive (conceptually unifying their remove/add methods)
This commit is contained in:
@ -10,6 +10,8 @@ from animation import Animation
|
|||||||
from animation import sync_animation_run_times_and_rate_funcs
|
from animation import sync_animation_run_times_and_rate_funcs
|
||||||
from transform import Transform
|
from transform import Transform
|
||||||
|
|
||||||
|
from traceback import *
|
||||||
|
|
||||||
class Rotating(Animation):
|
class Rotating(Animation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"axis" : OUT,
|
"axis" : OUT,
|
||||||
@ -408,9 +410,8 @@ class Succession(Animation):
|
|||||||
run_time = kwargs.pop("run_time")
|
run_time = kwargs.pop("run_time")
|
||||||
else:
|
else:
|
||||||
run_time = sum(self.run_times)
|
run_time = sum(self.run_times)
|
||||||
self.num_anims = len(animations)
|
self.num_anims = len(animations) #TODO: If this is zero, some special handling below
|
||||||
self.animations = animations
|
self.animations = animations
|
||||||
self.last_index = 0
|
|
||||||
#Have to keep track of this run_time, because Scene.play
|
#Have to keep track of this run_time, because Scene.play
|
||||||
#might very well mess with it.
|
#might very well mess with it.
|
||||||
self.original_run_time = run_time
|
self.original_run_time = run_time
|
||||||
@ -420,29 +421,55 @@ class Succession(Animation):
|
|||||||
critical_times = np.concatenate(([0], np.cumsum(self.run_times)))
|
critical_times = np.concatenate(([0], np.cumsum(self.run_times)))
|
||||||
self.critical_alphas = map (lambda x : np.true_divide(x, run_time), critical_times)
|
self.critical_alphas = map (lambda x : np.true_divide(x, run_time), critical_times)
|
||||||
|
|
||||||
mobject = Group(*[anim.mobject for anim in self.animations])
|
# self.scene_mobjects_at_time[i] is the scene's mobjects at start of self.animations[i]
|
||||||
Animation.__init__(self, mobject, run_time = run_time, **kwargs)
|
# self.scene_mobjects_at_time[i + 1] is the scene mobjects at end of self.animations[i]
|
||||||
|
self.scene_mobjects_at_time = [None for i in range(self.num_anims + 1)]
|
||||||
|
self.scene_mobjects_at_time[0] = Group()
|
||||||
|
for i in range(self.num_anims):
|
||||||
|
self.scene_mobjects_at_time[i + 1] = self.scene_mobjects_at_time[i].copy()
|
||||||
|
self.animations[i].clean_up(self.scene_mobjects_at_time[i + 1])
|
||||||
|
print "Here's scene_mobjects_at_time[]: "
|
||||||
|
for g in self.scene_mobjects_at_time:
|
||||||
|
print str(g.submobjects)
|
||||||
|
|
||||||
def rewind_to_start(self):
|
self.current_alpha = 0
|
||||||
for anim in reversed(self.animations):
|
self.current_anim_index = 0 #TODO: What if self.num_anims == 0?
|
||||||
anim.update(0)
|
|
||||||
|
self.mobject = Group()
|
||||||
|
self.jump_to_start_of_anim(0)
|
||||||
|
Animation.__init__(self, self.mobject, run_time = run_time, **kwargs)
|
||||||
|
|
||||||
|
def jump_to_start_of_anim(self, index):
|
||||||
|
self.current_anim_index = index
|
||||||
|
self.current_alpha = self.critical_alphas[index]
|
||||||
|
|
||||||
|
self.mobject.remove(*self.mobject.submobjects) # Should probably have a cleaner "remove_all" method…
|
||||||
|
self.mobject.add(self.animations[index].mobject)
|
||||||
|
for m in self.scene_mobjects_at_time[index].submobjects:
|
||||||
|
self.mobject.add(m)
|
||||||
|
|
||||||
|
self.animations[index].update(0)
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
self.rewind_to_start()
|
i = 0
|
||||||
|
while self.critical_alphas[i + 1] < alpha:
|
||||||
|
i = i + 1
|
||||||
|
# TODO: Special handling if alpha < 0 or alpha > 1, to use
|
||||||
|
# first or last sub-animation
|
||||||
|
|
||||||
for i in range(len(self.animations)):
|
# At this point, we should have self.critical_alphas[i] <= alpha <= self.critical_alphas[i +1]
|
||||||
sub_alpha = inverse_interpolate(
|
|
||||||
self.critical_alphas[i],
|
|
||||||
self.critical_alphas[i + 1],
|
|
||||||
alpha
|
|
||||||
)
|
|
||||||
if sub_alpha < 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
sub_alpha = clamp(0, 1, sub_alpha) # Could possibly adopt a non-clamping convention here
|
self.jump_to_start_of_anim(i)
|
||||||
self.animations[i].update(sub_alpha)
|
sub_alpha = inverse_interpolate(
|
||||||
|
self.critical_alphas[i],
|
||||||
|
self.critical_alphas[i + 1],
|
||||||
|
alpha
|
||||||
|
)
|
||||||
|
self.animations[i].update(sub_alpha)
|
||||||
|
|
||||||
def clean_up(self, *args, **kwargs):
|
def clean_up(self, *args, **kwargs):
|
||||||
|
# We clean up as though we've played ALL animations, even if
|
||||||
|
# clean_up is called in middle of things
|
||||||
for anim in self.animations:
|
for anim in self.animations:
|
||||||
anim.clean_up(*args, **kwargs)
|
anim.clean_up(*args, **kwargs)
|
||||||
|
|
||||||
@ -460,3 +487,7 @@ class AnimationGroup(Animation):
|
|||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
for anim in self.sub_anims:
|
for anim in self.sub_anims:
|
||||||
anim.update(alpha)
|
anim.update(alpha)
|
||||||
|
|
||||||
|
def clean_up(self, *args, **kwargs):
|
||||||
|
for anim in self.sub_anims:
|
||||||
|
anim.clean_up(*args, **kwargs)
|
@ -7,10 +7,11 @@ from colour import Color
|
|||||||
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
|
from container import *
|
||||||
|
|
||||||
#TODO: Explain array_attrs
|
#TODO: Explain array_attrs
|
||||||
|
|
||||||
class Mobject(object):
|
class Mobject(Container):
|
||||||
"""
|
"""
|
||||||
Mathematical Object
|
Mathematical Object
|
||||||
"""
|
"""
|
||||||
@ -22,7 +23,7 @@ class Mobject(object):
|
|||||||
"target" : None,
|
"target" : None,
|
||||||
}
|
}
|
||||||
def __init__(self, *submobjects, **kwargs):
|
def __init__(self, *submobjects, **kwargs):
|
||||||
digest_config(self, kwargs)
|
Container.__init__(self, *submobjects, **kwargs)
|
||||||
if not all(map(lambda m : isinstance(m, Mobject), submobjects)):
|
if not all(map(lambda m : isinstance(m, Mobject), submobjects)):
|
||||||
raise Exception("All submobjects must be of type Mobject")
|
raise Exception("All submobjects must be of type Mobject")
|
||||||
self.submobjects = list(submobjects)
|
self.submobjects = list(submobjects)
|
||||||
|
@ -20,8 +20,9 @@ from animation import Animation
|
|||||||
from animation.animation import sync_animation_run_times_and_rate_funcs
|
from animation.animation import sync_animation_run_times_and_rate_funcs
|
||||||
from animation.transform import MoveToTarget
|
from animation.transform import MoveToTarget
|
||||||
from animation.continual_animation import ContinualAnimation
|
from animation.continual_animation import ContinualAnimation
|
||||||
|
from container import *
|
||||||
|
|
||||||
class Scene(object):
|
class Scene(Container):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_class" : Camera,
|
"camera_class" : Camera,
|
||||||
"camera_config" : {},
|
"camera_config" : {},
|
||||||
@ -40,9 +41,9 @@ class Scene(object):
|
|||||||
"skip_to_animation_number" : None,
|
"skip_to_animation_number" : None,
|
||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, kwargs)
|
Container.__init__(self, **kwargs) # Perhaps allow passing in a non-empty *mobjects parameter?
|
||||||
self.camera = self.camera_class(**self.camera_config)
|
self.camera = self.camera_class(**self.camera_config)
|
||||||
self.mobjects = []
|
self.mobjects = [] #TODO: fiddle with this line... to match name used in Container
|
||||||
self.continual_animations = []
|
self.continual_animations = []
|
||||||
self.foreground_mobjects = []
|
self.foreground_mobjects = []
|
||||||
self.num_plays = 0
|
self.num_plays = 0
|
||||||
|
Reference in New Issue
Block a user