2015-06-10 22:00:35 -07:00
|
|
|
import numpy as np
|
|
|
|
import itertools as it
|
|
|
|
|
|
|
|
from helpers import *
|
|
|
|
|
2016-01-12 11:50:58 -08:00
|
|
|
from mobject import Mobject
|
2016-07-19 11:08:31 -07:00
|
|
|
from mobject.vectorized_mobject import VMobject
|
2016-07-19 14:37:18 -07:00
|
|
|
from mobject.tex_mobject import TextMobject
|
2015-10-27 21:00:50 -07:00
|
|
|
from animation import Animation
|
2015-08-08 20:42:34 -07:00
|
|
|
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
class Rotating(Animation):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2015-11-09 10:34:00 -08:00
|
|
|
"axes" : [RIGHT, UP],
|
|
|
|
"axis" : None,
|
|
|
|
"radians" : 2*np.pi,
|
|
|
|
"run_time" : 20.0,
|
2016-01-12 11:50:58 -08:00
|
|
|
"rate_func" : None,
|
2015-11-09 10:34:00 -08:00
|
|
|
"in_place" : True,
|
2015-09-28 16:25:18 -07:00
|
|
|
}
|
2016-10-25 17:35:16 -07:00
|
|
|
def update_submobject(self, submobject, starting_submobject, alpha):
|
|
|
|
submobject.points = np.array(starting_submobject.points)
|
2016-07-22 15:50:52 -07:00
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
def update_mobject(self, alpha):
|
2016-07-22 15:50:52 -07:00
|
|
|
Animation.update_mobject(self, alpha)
|
2015-11-09 10:34:00 -08:00
|
|
|
axes = [self.axis] if self.axis is not None else self.axes
|
|
|
|
if self.in_place:
|
|
|
|
method = self.mobject.rotate_in_place
|
|
|
|
else:
|
|
|
|
method = self.mobject.rotate
|
2016-01-07 16:24:33 -08:00
|
|
|
method(alpha*self.radians, axes = axes)
|
2015-08-12 14:24:36 -07:00
|
|
|
|
2015-08-08 20:42:34 -07:00
|
|
|
|
2016-02-15 21:08:47 -08:00
|
|
|
class ShowPartial(Animation):
|
2016-07-22 15:50:52 -07:00
|
|
|
def update_submobject(self, submobject, starting_submobject, alpha):
|
|
|
|
submobject.pointwise_become_partial(
|
|
|
|
starting_submobject, *self.get_bounds(alpha)
|
2015-12-23 11:30:22 -08:00
|
|
|
)
|
2015-12-22 11:03:14 -08:00
|
|
|
|
2016-02-15 21:08:47 -08:00
|
|
|
def get_bounds(self, alpha):
|
|
|
|
raise Exception("Not Implemented")
|
|
|
|
|
|
|
|
|
|
|
|
class ShowCreation(ShowPartial):
|
2016-04-19 00:20:19 -07:00
|
|
|
CONFIG = {
|
2016-04-20 19:24:54 -07:00
|
|
|
"submobject_mode" : "one_at_a_time",
|
2016-04-19 00:20:19 -07:00
|
|
|
}
|
2016-07-25 16:04:54 -07:00
|
|
|
def get_bounds(self, alpha):
|
|
|
|
return (0, alpha)
|
2016-04-19 00:20:19 -07:00
|
|
|
|
2016-08-22 21:22:21 -07:00
|
|
|
class Uncreate(ShowCreation):
|
|
|
|
CONFIG = {
|
|
|
|
"rate_func" : lambda t : smooth(1-t),
|
|
|
|
"remover" : True
|
|
|
|
}
|
|
|
|
|
2016-04-20 19:24:54 -07:00
|
|
|
class Write(ShowCreation):
|
|
|
|
CONFIG = {
|
|
|
|
"rate_func" : None,
|
|
|
|
"submobject_mode" : "lagged_start",
|
|
|
|
}
|
2016-07-19 14:37:18 -07:00
|
|
|
def __init__(self, mob_or_text, **kwargs):
|
2016-09-10 15:21:03 -07:00
|
|
|
digest_config(self, kwargs)
|
2016-07-19 14:37:18 -07:00
|
|
|
if isinstance(mob_or_text, str):
|
|
|
|
mobject = TextMobject(mob_or_text)
|
|
|
|
else:
|
|
|
|
mobject = mob_or_text
|
2016-09-10 17:35:15 -07:00
|
|
|
if "run_time" not in kwargs:
|
2016-07-26 12:32:51 -07:00
|
|
|
self.establish_run_time(mobject)
|
2016-09-10 17:35:15 -07:00
|
|
|
if "lag_factor" not in kwargs:
|
2016-09-23 17:26:56 -07:00
|
|
|
self.lag_factor = max(self.run_time - 1, 2)
|
2016-07-19 14:37:18 -07:00
|
|
|
ShowCreation.__init__(self, mobject, **kwargs)
|
2016-04-20 19:24:54 -07:00
|
|
|
|
2016-07-26 12:32:51 -07:00
|
|
|
def establish_run_time(self, mobject):
|
|
|
|
num_subs = len(mobject.family_members_with_points())
|
|
|
|
if num_subs < 5:
|
|
|
|
self.run_time = 1
|
|
|
|
elif num_subs < 15:
|
|
|
|
self.run_time = 2
|
|
|
|
else:
|
|
|
|
self.run_time = 3
|
|
|
|
|
|
|
|
|
2016-02-15 21:08:47 -08:00
|
|
|
class ShowPassingFlash(ShowPartial):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-02-15 21:08:47 -08:00
|
|
|
"time_width" : 0.1
|
|
|
|
}
|
|
|
|
def get_bounds(self, alpha):
|
|
|
|
alpha *= (1+self.time_width)
|
|
|
|
alpha -= self.time_width/2
|
|
|
|
lower = max(0, alpha - self.time_width/2)
|
|
|
|
upper = min(1, alpha + self.time_width/2)
|
|
|
|
return (lower, upper)
|
|
|
|
|
|
|
|
|
2016-07-12 15:16:20 -07:00
|
|
|
class MoveAlongPath(Animation):
|
|
|
|
def __init__(self, mobject, vmobject, **kwargs):
|
|
|
|
digest_config(self, kwargs, locals())
|
|
|
|
Animation.__init__(self, mobject, **kwargs)
|
|
|
|
|
|
|
|
def update_mobject(self, alpha):
|
|
|
|
self.mobject.shift(
|
|
|
|
self.vmobject.point_from_proportion(alpha) - \
|
|
|
|
self.mobject.get_center()
|
|
|
|
)
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
class Homotopy(Animation):
|
2016-09-07 22:04:24 -07:00
|
|
|
CONFIG = {
|
2016-11-07 11:05:41 -08:00
|
|
|
"run_time" : 3,
|
|
|
|
"apply_function_kwargs" : {},
|
2016-09-07 22:04:24 -07:00
|
|
|
}
|
2015-10-28 16:03:33 -07:00
|
|
|
def __init__(self, homotopy, mobject, **kwargs):
|
2015-06-10 22:00:35 -07:00
|
|
|
"""
|
|
|
|
Homotopy a function from (x, y, z, t) to (x', y', z')
|
|
|
|
"""
|
2016-07-18 11:50:26 -07:00
|
|
|
def function_at_time_t(t):
|
|
|
|
return lambda p : homotopy(p[0], p[1], p[2], t)
|
|
|
|
self.function_at_time_t = function_at_time_t
|
|
|
|
digest_config(self, kwargs)
|
2015-10-28 16:03:33 -07:00
|
|
|
Animation.__init__(self, mobject, **kwargs)
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2016-07-22 15:50:52 -07:00
|
|
|
def update_submobject(self, submob, start, alpha):
|
|
|
|
submob.points = start.points
|
2016-11-07 11:05:41 -08:00
|
|
|
submob.apply_function(
|
|
|
|
self.function_at_time_t(alpha),
|
|
|
|
**self.apply_function_kwargs
|
|
|
|
)
|
2016-07-22 15:50:52 -07:00
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
def update_mobject(self, alpha):
|
2016-07-22 15:50:52 -07:00
|
|
|
Animation.update_mobject(self, alpha)
|
2016-09-07 22:04:24 -07:00
|
|
|
|
2016-07-18 11:50:26 -07:00
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2016-01-12 11:50:58 -08:00
|
|
|
class PhaseFlow(Animation):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-04-30 15:08:53 -07:00
|
|
|
"virtual_time" : 1,
|
|
|
|
"rate_func" : None,
|
2016-01-15 11:45:30 -08:00
|
|
|
}
|
2016-01-12 11:50:58 -08:00
|
|
|
def __init__(self, function, mobject, **kwargs):
|
2016-01-15 11:45:30 -08:00
|
|
|
digest_config(self, kwargs, locals())
|
2016-01-12 11:50:58 -08:00
|
|
|
Animation.__init__(self, mobject, **kwargs)
|
|
|
|
|
|
|
|
def update_mobject(self, alpha):
|
|
|
|
if hasattr(self, "last_alpha"):
|
2016-04-30 15:08:53 -07:00
|
|
|
dt = self.virtual_time*(alpha-self.last_alpha)
|
2016-01-12 11:50:58 -08:00
|
|
|
self.mobject.apply_function(
|
2016-04-30 15:08:53 -07:00
|
|
|
lambda p : p + dt*self.function(p)
|
2016-01-12 11:50:58 -08:00
|
|
|
)
|
|
|
|
self.last_alpha = alpha
|
|
|
|
|
2016-03-21 19:29:12 -07:00
|
|
|
class MoveAlongPath(Animation):
|
|
|
|
def __init__(self, mobject, path, **kwargs):
|
|
|
|
digest_config(self, kwargs, locals())
|
|
|
|
Animation.__init__(self, mobject, **kwargs)
|
|
|
|
|
|
|
|
def update_mobject(self, alpha):
|
2016-10-25 17:35:16 -07:00
|
|
|
point = self.path.point_from_proportion(alpha)
|
|
|
|
self.mobject.move_to(point)
|
2016-03-21 19:29:12 -07:00
|
|
|
|
2016-07-19 14:37:18 -07:00
|
|
|
class UpdateFromFunc(Animation):
|
|
|
|
"""
|
|
|
|
update_function of the form func(mobject), presumably
|
|
|
|
to be used when the state of one mobject is dependent
|
|
|
|
on another simultaneously animated mobject
|
|
|
|
"""
|
|
|
|
def __init__(self, mobject, update_function, **kwargs):
|
2016-07-19 11:08:31 -07:00
|
|
|
digest_config(self, kwargs, locals())
|
2016-07-19 14:37:18 -07:00
|
|
|
Animation.__init__(self, mobject, **kwargs)
|
2016-07-19 11:08:31 -07:00
|
|
|
|
|
|
|
def update_mobject(self, alpha):
|
2016-07-19 14:37:18 -07:00
|
|
|
self.update_function(self.mobject)
|
2016-07-19 11:08:31 -07:00
|
|
|
|
|
|
|
|
2016-07-19 14:37:18 -07:00
|
|
|
class MaintainPositionRelativeTo(Animation):
|
|
|
|
CONFIG = {
|
|
|
|
"tracked_critical_point" : ORIGIN
|
|
|
|
}
|
|
|
|
def __init__(self, mobject, tracked_mobject, **kwargs):
|
|
|
|
digest_config(self, kwargs, locals())
|
|
|
|
tcp = self.tracked_critical_point
|
|
|
|
self.diff = mobject.get_critical_point(tcp) - \
|
|
|
|
tracked_mobject.get_critical_point(tcp)
|
|
|
|
Animation.__init__(self, mobject, **kwargs)
|
2016-07-19 11:08:31 -07:00
|
|
|
|
2016-07-19 14:37:18 -07:00
|
|
|
def update_mobject(self, alpha):
|
|
|
|
self.mobject.shift(
|
|
|
|
self.tracked_mobject.get_critical_point(self.tracked_critical_point) - \
|
|
|
|
self.mobject.get_critical_point(self.tracked_critical_point) + \
|
|
|
|
self.diff
|
|
|
|
)
|
2016-07-19 11:08:31 -07:00
|
|
|
|
|
|
|
|
2016-01-12 11:50:58 -08:00
|
|
|
### Animation modifiers ###
|
|
|
|
|
|
|
|
class ApplyToCenters(Animation):
|
|
|
|
def __init__(self, AnimationClass, mobjects, **kwargs):
|
2016-04-30 15:08:53 -07:00
|
|
|
full_kwargs = AnimationClass.CONFIG
|
|
|
|
full_kwargs.update(kwargs)
|
|
|
|
full_kwargs["mobject"] = Mobject(*[
|
|
|
|
mob.get_point_mobject()
|
|
|
|
for mob in mobjects
|
|
|
|
])
|
|
|
|
self.centers_container = AnimationClass(**full_kwargs)
|
|
|
|
full_kwargs.pop("mobject")
|
|
|
|
Animation.__init__(self, Mobject(*mobjects), **full_kwargs)
|
2016-01-12 11:50:58 -08:00
|
|
|
self.name = str(self) + AnimationClass.__name__
|
|
|
|
|
|
|
|
def update_mobject(self, alpha):
|
|
|
|
self.centers_container.update_mobject(alpha)
|
2016-04-30 15:08:53 -07:00
|
|
|
center_mobs = self.centers_container.mobject.split()
|
2016-01-12 11:50:58 -08:00
|
|
|
mobjects = self.mobject.split()
|
2016-04-30 15:08:53 -07:00
|
|
|
for center_mob, mobject in zip(center_mobs, mobjects):
|
|
|
|
mobject.shift(
|
|
|
|
center_mob.get_center()-mobject.get_center()
|
|
|
|
)
|
2016-01-12 11:50:58 -08:00
|
|
|
|
|
|
|
|
2015-06-19 08:31:02 -07:00
|
|
|
|
2016-01-07 16:24:33 -08:00
|
|
|
class DelayByOrder(Animation):
|
|
|
|
"""
|
|
|
|
Modifier of animation.
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2016-01-07 16:24:33 -08:00
|
|
|
Warning: This will not work on all animation types.
|
|
|
|
"""
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-01-07 16:24:33 -08:00
|
|
|
"max_power" : 5
|
|
|
|
}
|
|
|
|
def __init__(self, animation, **kwargs):
|
|
|
|
digest_locals(self)
|
|
|
|
self.num_mobject_points = animation.mobject.get_num_points()
|
|
|
|
kwargs.update(dict([
|
|
|
|
(attr, getattr(animation, attr))
|
2016-02-27 18:50:33 -08:00
|
|
|
for attr in Animation.CONFIG
|
2016-01-07 16:24:33 -08:00
|
|
|
]))
|
|
|
|
Animation.__init__(self, animation.mobject, **kwargs)
|
2016-01-12 11:50:58 -08:00
|
|
|
self.name = str(self) + str(self.animation)
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2016-01-07 16:24:33 -08:00
|
|
|
def update_mobject(self, alpha):
|
|
|
|
dim = self.mobject.DIM
|
|
|
|
alpha_array = np.array([
|
|
|
|
[alpha**power]*dim
|
|
|
|
for n in range(self.num_mobject_points)
|
|
|
|
for prop in [(n+1.0)/self.num_mobject_points]
|
|
|
|
for power in [1+prop*(self.max_power-1)]
|
|
|
|
])
|
|
|
|
self.animation.update_mobject(alpha_array)
|
|
|
|
|
|
|
|
|
|
|
|
class Succession(Animation):
|
|
|
|
def __init__(self, *animations, **kwargs):
|
|
|
|
if "run_time" in kwargs:
|
|
|
|
run_time = kwargs.pop("run_time")
|
|
|
|
else:
|
|
|
|
run_time = sum([anim.run_time for anim in animations])
|
|
|
|
self.num_anims = len(animations)
|
2016-11-15 20:08:28 -08:00
|
|
|
self.anims = (animations)
|
|
|
|
mobject = Mobject(*[anim.mobject for anim in self.anims])
|
|
|
|
self.last_index = 0
|
2016-01-07 16:24:33 -08:00
|
|
|
Animation.__init__(self, mobject, run_time = run_time, **kwargs)
|
|
|
|
|
2016-11-15 20:08:28 -08:00
|
|
|
def update_mobject(self, alpha):
|
2016-01-07 16:24:33 -08:00
|
|
|
scaled_alpha = alpha*self.num_anims
|
2016-11-15 20:08:28 -08:00
|
|
|
index = min(int(scaled_alpha), len(self.anims)-1)
|
|
|
|
curr_anim = self.anims[index]
|
|
|
|
if index != self.last_index:
|
|
|
|
last_anim = self.anims[self.last_index]
|
|
|
|
last_anim.clean_up()
|
|
|
|
if last_anim.mobject is curr_anim.mobject:
|
|
|
|
self.anims[index].starting_mobject = curr_anim.mobject.copy()
|
|
|
|
self.anims[index].update_mobject(scaled_alpha - index)
|
|
|
|
self.last_index = index
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
|
|
|
|
|