From 55a723a2848c8ea666f3bb40b4482ae77bf2e6a8 Mon Sep 17 00:00:00 2001 From: Sridhar Ramesh Date: Mon, 29 Jan 2018 13:34:06 -0800 Subject: [PATCH] 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) --- animation/simple_animations.py | 67 +++++++++++++++++++++++++--------- mobject/mobject.py | 5 ++- scene/scene.py | 7 ++-- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/animation/simple_animations.py b/animation/simple_animations.py index 566cd9f7..d2086ffe 100644 --- a/animation/simple_animations.py +++ b/animation/simple_animations.py @@ -10,6 +10,8 @@ from animation import Animation from animation import sync_animation_run_times_and_rate_funcs from transform import Transform +from traceback import * + class Rotating(Animation): CONFIG = { "axis" : OUT, @@ -408,9 +410,8 @@ class Succession(Animation): run_time = kwargs.pop("run_time") else: 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.last_index = 0 #Have to keep track of this run_time, because Scene.play #might very well mess with it. self.original_run_time = run_time @@ -420,29 +421,55 @@ class Succession(Animation): critical_times = np.concatenate(([0], np.cumsum(self.run_times))) self.critical_alphas = map (lambda x : np.true_divide(x, run_time), critical_times) - mobject = Group(*[anim.mobject for anim in self.animations]) - Animation.__init__(self, mobject, run_time = run_time, **kwargs) + # self.scene_mobjects_at_time[i] is the scene's mobjects at start of self.animations[i] + # 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): - for anim in reversed(self.animations): - anim.update(0) + self.current_alpha = 0 + self.current_anim_index = 0 #TODO: What if self.num_anims == 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): - 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)): - sub_alpha = inverse_interpolate( - self.critical_alphas[i], - self.critical_alphas[i + 1], - alpha - ) - if sub_alpha < 0: - return + # At this point, we should have self.critical_alphas[i] <= alpha <= self.critical_alphas[i +1] - sub_alpha = clamp(0, 1, sub_alpha) # Could possibly adopt a non-clamping convention here - self.animations[i].update(sub_alpha) + self.jump_to_start_of_anim(i) + 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): + # 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: anim.clean_up(*args, **kwargs) @@ -460,3 +487,7 @@ class AnimationGroup(Animation): def update_mobject(self, alpha): for anim in self.sub_anims: anim.update(alpha) + + def clean_up(self, *args, **kwargs): + for anim in self.sub_anims: + anim.clean_up(*args, **kwargs) \ No newline at end of file diff --git a/mobject/mobject.py b/mobject/mobject.py index f079b330..b824d7c7 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -7,10 +7,11 @@ from colour import Color from helpers import * +from container import * #TODO: Explain array_attrs -class Mobject(object): +class Mobject(Container): """ Mathematical Object """ @@ -22,7 +23,7 @@ class Mobject(object): "target" : None, } def __init__(self, *submobjects, **kwargs): - digest_config(self, kwargs) + Container.__init__(self, *submobjects, **kwargs) if not all(map(lambda m : isinstance(m, Mobject), submobjects)): raise Exception("All submobjects must be of type Mobject") self.submobjects = list(submobjects) diff --git a/scene/scene.py b/scene/scene.py index fbf2d2ff..e4a9bec9 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -20,8 +20,9 @@ from animation import Animation from animation.animation import sync_animation_run_times_and_rate_funcs from animation.transform import MoveToTarget from animation.continual_animation import ContinualAnimation +from container import * -class Scene(object): +class Scene(Container): CONFIG = { "camera_class" : Camera, "camera_config" : {}, @@ -40,9 +41,9 @@ class Scene(object): "skip_to_animation_number" : None, } 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.mobjects = [] + self.mobjects = [] #TODO: fiddle with this line... to match name used in Container self.continual_animations = [] self.foreground_mobjects = [] self.num_plays = 0