3b1b-manim/animation/simple_animations.py

247 lines
7.6 KiB
Python
Raw Normal View History

2015-06-10 22:00:35 -07:00
import numpy as np
import itertools as it
from helpers import *
from mobject import Mobject
from mobject.vectorized_mobject import VMobject
from mobject.tex_mobject import TextMobject
from animation import Animation
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,
"rate_func" : None,
2015-11-09 10:34:00 -08:00
"in_place" : True,
}
def update_submobject(self, submobject, starting_mobject, alpha):
submobject.points = starting_submobject.points
2015-06-10 22:00:35 -07:00
def update_mobject(self, alpha):
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
method(alpha*self.radians, axes = axes)
class ShowPartial(Animation):
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
def get_bounds(self, alpha):
raise Exception("Not Implemented")
class ShowCreation(ShowPartial):
def get_bounds(self, alpha):
return (0, alpha)
2016-04-19 00:20:19 -07:00
class ShowCreationPerSubmobject(ShowCreation):
CONFIG = {
2016-04-20 19:24:54 -07:00
"submobject_mode" : "one_at_a_time",
2016-04-23 23:36:05 -07:00
"run_time" : 1
2016-04-19 00:20:19 -07:00
}
2016-04-20 19:24:54 -07:00
class Write(ShowCreation):
CONFIG = {
"run_time" : 3,
"rate_func" : None,
"submobject_mode" : "lagged_start",
}
def __init__(self, mob_or_text, **kwargs):
if isinstance(mob_or_text, str):
mobject = TextMobject(mob_or_text)
else:
mobject = mob_or_text
ShowCreation.__init__(self, mobject, **kwargs)
2016-04-20 19:24:54 -07:00
class ShowPassingFlash(ShowPartial):
2016-02-27 16:32:53 -08:00
CONFIG = {
"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)
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):
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)
Animation.__init__(self, mobject, **kwargs)
2015-06-10 22:00:35 -07:00
def update_submobject(self, submob, start, alpha):
submob.points = start.points
2015-06-10 22:00:35 -07:00
def update_mobject(self, alpha):
Animation.update_mobject(self, alpha)
submob.apply_function(self.function_at_time_t(alpha))
2016-07-18 11:50:26 -07:00
2015-06-10 22:00:35 -07: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
}
def __init__(self, function, mobject, **kwargs):
2016-01-15 11:45:30 -08:00
digest_config(self, kwargs, locals())
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)
self.mobject.apply_function(
2016-04-30 15:08:53 -07:00
lambda p : p + dt*self.function(p)
)
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):
n = self.path.get_num_points()-1
point = self.path.points[int(alpha*n)]
self.mobject.shift(point-self.mobject.get_center())
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):
digest_config(self, kwargs, locals())
Animation.__init__(self, mobject, **kwargs)
def update_mobject(self, alpha):
self.update_function(self.mobject)
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)
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
)
### 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)
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()
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()
)
2015-06-19 08:31:02 -07:00
class DelayByOrder(Animation):
"""
Modifier of animation.
2015-06-10 22:00:35 -07:00
Warning: This will not work on all animation types.
"""
2016-02-27 16:32:53 -08:00
CONFIG = {
"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
]))
Animation.__init__(self, animation.mobject, **kwargs)
self.name = str(self) + str(self.animation)
2015-06-10 22:00:35 -07: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)
self.anims = animations
mobject = animations[0].mobject
Animation.__init__(self, mobject, run_time = run_time, **kwargs)
def __str__(self):
return self.__class__.__name__ + \
"".join(map(str, self.anims))
def update(self, alpha):
scaled_alpha = alpha*self.num_anims
self.mobject = self.anims
for index in range(len(self.anims)):
self.anims[index].update(scaled_alpha - index)
2015-06-10 22:00:35 -07:00