2019-02-11 13:17:23 -08:00
|
|
|
import inspect
|
2019-02-11 14:08:48 -08:00
|
|
|
|
2019-02-11 13:17:23 -08:00
|
|
|
from manimlib.constants import DEGREES
|
|
|
|
from manimlib.constants import RIGHT
|
|
|
|
from manimlib.mobject.mobject import Mobject
|
2020-02-18 22:32:15 -08:00
|
|
|
from manimlib.utils.simple_functions import clip
|
2019-02-11 13:17:23 -08:00
|
|
|
|
|
|
|
|
2019-02-15 15:16:11 -08:00
|
|
|
def assert_is_mobject_method(method):
|
2019-02-11 13:17:23 -08:00
|
|
|
assert(inspect.ismethod(method))
|
2019-02-11 13:04:52 -08:00
|
|
|
mobject = method.__self__
|
2019-02-11 13:17:23 -08:00
|
|
|
assert(isinstance(mobject, Mobject))
|
2019-02-15 15:16:11 -08:00
|
|
|
|
|
|
|
|
|
|
|
def always(method, *args, **kwargs):
|
|
|
|
assert_is_mobject_method(method)
|
|
|
|
mobject = method.__self__
|
2019-02-11 13:04:52 -08:00
|
|
|
func = method.__func__
|
|
|
|
mobject.add_updater(lambda m: func(m, *args, **kwargs))
|
2019-02-15 15:16:11 -08:00
|
|
|
return mobject
|
|
|
|
|
|
|
|
|
|
|
|
def f_always(method, *arg_generators, **kwargs):
|
|
|
|
"""
|
2019-03-30 13:22:24 -07:00
|
|
|
More functional version of always, where instead
|
2019-02-15 15:16:11 -08:00
|
|
|
of taking in args, it takes in functions which ouput
|
|
|
|
the relevant arguments.
|
|
|
|
"""
|
|
|
|
assert_is_mobject_method(method)
|
|
|
|
mobject = method.__self__
|
|
|
|
func = method.__func__
|
|
|
|
|
|
|
|
def updater(mob):
|
|
|
|
args = [
|
|
|
|
arg_generator()
|
|
|
|
for arg_generator in arg_generators
|
|
|
|
]
|
|
|
|
func(mob, *args, **kwargs)
|
|
|
|
|
|
|
|
mobject.add_updater(updater)
|
|
|
|
return mobject
|
2019-02-11 13:04:52 -08:00
|
|
|
|
|
|
|
|
2019-02-11 12:58:52 -08:00
|
|
|
def always_redraw(func):
|
2018-10-05 17:17:55 -07:00
|
|
|
mob = func()
|
|
|
|
mob.add_updater(lambda m: mob.become(func()))
|
|
|
|
return mob
|
2019-02-11 13:17:23 -08:00
|
|
|
|
|
|
|
|
|
|
|
def always_shift(mobject, direction=RIGHT, rate=0.1):
|
|
|
|
mobject.add_updater(
|
|
|
|
lambda m, dt: m.shift(dt * rate * direction)
|
|
|
|
)
|
2019-02-11 13:37:07 -08:00
|
|
|
return mobject
|
2019-02-11 13:17:23 -08:00
|
|
|
|
|
|
|
|
|
|
|
def always_rotate(mobject, rate=20 * DEGREES, **kwargs):
|
|
|
|
mobject.add_updater(
|
|
|
|
lambda m, dt: m.rotate(dt * rate, **kwargs)
|
|
|
|
)
|
2019-02-11 13:37:07 -08:00
|
|
|
return mobject
|
2019-02-11 14:08:48 -08:00
|
|
|
|
|
|
|
|
2019-02-11 14:28:45 -08:00
|
|
|
def turn_animation_into_updater(animation, cycle=False, **kwargs):
|
2019-02-11 14:08:48 -08:00
|
|
|
"""
|
2019-02-11 14:28:45 -08:00
|
|
|
Add an updater to the animation's mobject which applies
|
|
|
|
the interpolation and update functions of the animation
|
|
|
|
|
|
|
|
If cycle is True, this repeats over and over. Otherwise,
|
|
|
|
the updater will be popped uplon completion
|
2019-02-11 14:08:48 -08:00
|
|
|
"""
|
|
|
|
mobject = animation.mobject
|
2019-02-11 14:28:45 -08:00
|
|
|
animation.update_config(**kwargs)
|
2019-02-11 14:08:48 -08:00
|
|
|
animation.suspend_mobject_updating = False
|
|
|
|
animation.begin()
|
|
|
|
animation.total_time = 0
|
|
|
|
|
|
|
|
def update(m, dt):
|
2019-02-11 14:28:45 -08:00
|
|
|
run_time = animation.get_run_time()
|
2019-04-02 17:43:18 -07:00
|
|
|
time_ratio = animation.total_time / run_time
|
2019-02-11 14:28:45 -08:00
|
|
|
if cycle:
|
2019-04-02 17:43:18 -07:00
|
|
|
alpha = time_ratio % 1
|
|
|
|
else:
|
2020-02-18 22:32:15 -08:00
|
|
|
alpha = clip(time_ratio, 0, 1)
|
2019-04-02 17:43:18 -07:00
|
|
|
if alpha >= 1:
|
|
|
|
animation.finish()
|
|
|
|
m.remove_updater(update)
|
|
|
|
return
|
2019-02-11 14:28:45 -08:00
|
|
|
animation.interpolate(alpha)
|
|
|
|
animation.update_mobjects(dt)
|
|
|
|
animation.total_time += dt
|
2019-02-11 14:08:48 -08:00
|
|
|
|
|
|
|
mobject.add_updater(update)
|
|
|
|
return mobject
|
2019-02-11 14:28:45 -08:00
|
|
|
|
|
|
|
|
|
|
|
def cycle_animation(animation, **kwargs):
|
|
|
|
return turn_animation_into_updater(
|
|
|
|
animation, cycle=True, **kwargs
|
|
|
|
)
|