2015-06-10 22:00:35 -07:00
|
|
|
from PIL import Image
|
|
|
|
from colour import Color
|
|
|
|
import numpy as np
|
|
|
|
import warnings
|
|
|
|
import time
|
|
|
|
import os
|
|
|
|
import progressbar
|
|
|
|
import inspect
|
2015-12-16 19:49:21 -08:00
|
|
|
from copy import deepcopy
|
2015-06-10 22:00:35 -07:00
|
|
|
|
|
|
|
from helpers import *
|
2015-11-23 10:34:42 -08:00
|
|
|
from mobject import Mobject
|
2015-06-10 22:00:35 -07:00
|
|
|
|
|
|
|
class Animation(object):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2015-09-28 16:25:18 -07:00
|
|
|
"run_time" : DEFAULT_ANIMATION_RUN_TIME,
|
2016-01-01 14:51:16 -08:00
|
|
|
"rate_func" : smooth,
|
2015-09-28 16:25:18 -07:00
|
|
|
"name" : None,
|
2016-07-19 11:07:26 -07:00
|
|
|
#Does this animation add or remove a mobject form the screen
|
|
|
|
"remover" : False,
|
2016-07-22 15:50:52 -07:00
|
|
|
#Options are lagged_start, smoothed_lagged_start,
|
|
|
|
#one_at_a_time, all_at_once
|
2016-09-07 22:04:24 -07:00
|
|
|
"submobject_mode" : "all_at_once",
|
2016-08-22 21:22:21 -07:00
|
|
|
"lag_factor" : 2,
|
2015-09-28 16:25:18 -07:00
|
|
|
}
|
|
|
|
def __init__(self, mobject, **kwargs):
|
2015-10-20 21:55:46 -07:00
|
|
|
mobject = instantiate(mobject)
|
|
|
|
assert(isinstance(mobject, Mobject))
|
2015-10-28 16:03:33 -07:00
|
|
|
digest_config(self, kwargs, locals())
|
2015-11-02 19:09:55 -08:00
|
|
|
self.starting_mobject = self.mobject.copy()
|
2016-01-01 14:51:16 -08:00
|
|
|
if self.rate_func is None:
|
|
|
|
self.rate_func = (lambda x : x)
|
2015-09-28 16:25:18 -07:00
|
|
|
if self.name is None:
|
|
|
|
self.name = self.__class__.__name__ + str(self.mobject)
|
2015-09-25 19:43:53 -07:00
|
|
|
self.update(0)
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2016-07-22 11:22:31 -07:00
|
|
|
def update_config(self, **kwargs):
|
|
|
|
digest_config(self, kwargs)
|
2016-08-03 16:51:16 -07:00
|
|
|
if "rate_func" in kwargs and kwargs["rate_func"] is None:
|
|
|
|
self.rate_func = (lambda x : x)
|
2016-07-22 11:22:31 -07:00
|
|
|
return self
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
2015-12-16 19:49:21 -08:00
|
|
|
def copy(self):
|
|
|
|
return deepcopy(self)
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
def update(self, alpha):
|
|
|
|
if alpha < 0:
|
2015-06-27 04:49:10 -07:00
|
|
|
alpha = 0.0
|
2015-06-10 22:00:35 -07:00
|
|
|
if alpha > 1:
|
2015-06-27 04:49:10 -07:00
|
|
|
alpha = 1.0
|
2016-01-01 14:51:16 -08:00
|
|
|
self.update_mobject(self.rate_func(alpha))
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2016-07-22 15:50:52 -07:00
|
|
|
def update_mobject(self, alpha):
|
|
|
|
families = self.get_all_families_zipped()
|
|
|
|
for i, mobs in enumerate(families):
|
|
|
|
sub_alpha = self.get_sub_alpha(alpha, i, len(families))
|
|
|
|
self.update_submobject(*list(mobs) + [sub_alpha])
|
|
|
|
return self
|
|
|
|
|
|
|
|
def update_submobject(self, submobject, starting_sumobject, alpha):
|
|
|
|
#Typically ipmlemented by subclass
|
|
|
|
pass
|
|
|
|
|
2017-02-13 18:43:55 -08:00
|
|
|
def get_all_mobjects(self):
|
2016-07-22 15:50:52 -07:00
|
|
|
"""
|
|
|
|
Ordering must match the ording of arguments to update_submobject
|
|
|
|
"""
|
2017-02-13 18:43:55 -08:00
|
|
|
return self.mobject, self.starting_mobject
|
|
|
|
|
|
|
|
def get_all_families_zipped(self):
|
|
|
|
return zip(*map(
|
|
|
|
Mobject.family_members_with_points,
|
|
|
|
self.get_all_mobjects()
|
|
|
|
))
|
2016-07-22 15:50:52 -07:00
|
|
|
|
|
|
|
def get_sub_alpha(self, alpha, index, num_submobjects):
|
|
|
|
if self.submobject_mode in ["lagged_start", "smoothed_lagged_start"]:
|
|
|
|
prop = float(index)/num_submobjects
|
|
|
|
if self.submobject_mode is "smoothed_lagged_start":
|
|
|
|
prop = smooth(prop)
|
2016-08-22 21:22:21 -07:00
|
|
|
lf = self.lag_factor
|
|
|
|
return np.clip(lf*alpha - (lf-1)*prop, 0, 1)
|
2016-07-22 15:50:52 -07:00
|
|
|
elif self.submobject_mode == "one_at_a_time":
|
|
|
|
lower = float(index)/num_submobjects
|
|
|
|
upper = float(index+1)/num_submobjects
|
|
|
|
return np.clip((alpha-lower)/(upper-lower), 0, 1)
|
|
|
|
elif self.submobject_mode == "all_at_once":
|
|
|
|
return alpha
|
|
|
|
raise Exception("Invalid submobject mode")
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
def filter_out(self, *filter_functions):
|
|
|
|
self.filter_functions += filter_functions
|
|
|
|
return self
|
|
|
|
|
|
|
|
def set_run_time(self, time):
|
|
|
|
self.run_time = time
|
|
|
|
return self
|
|
|
|
|
2016-07-21 15:16:32 -07:00
|
|
|
def get_run_time(self):
|
|
|
|
return self.run_time
|
|
|
|
|
2016-01-01 14:51:16 -08:00
|
|
|
def set_rate_func(self, rate_func):
|
|
|
|
if rate_func is None:
|
|
|
|
rate_func = lambda x : x
|
|
|
|
self.rate_func = rate_func
|
2015-06-10 22:00:35 -07:00
|
|
|
return self
|
|
|
|
|
2016-07-21 15:16:32 -07:00
|
|
|
def get_rate_func(self):
|
|
|
|
return self.rate_func
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
def set_name(self, name):
|
|
|
|
self.name = name
|
2016-07-22 15:50:52 -07:00
|
|
|
return self
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2016-07-19 11:07:26 -07:00
|
|
|
def is_remover(self):
|
|
|
|
return self.remover
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
def clean_up(self):
|
2015-06-19 08:31:02 -07:00
|
|
|
self.update(1)
|
2015-06-10 22:00:35 -07:00
|
|
|
|
|
|
|
|
2015-06-27 04:49:10 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
|