2015-06-10 22:00:35 -07:00
|
|
|
import numpy as np
|
|
|
|
import itertools as it
|
|
|
|
import inspect
|
|
|
|
import copy
|
|
|
|
import warnings
|
|
|
|
|
|
|
|
from helpers import *
|
|
|
|
|
2015-10-27 21:00:50 -07:00
|
|
|
from animation import Animation
|
2016-01-07 16:24:33 -08:00
|
|
|
from simple_animations import DelayByOrder
|
2016-07-18 11:50:26 -07:00
|
|
|
from mobject import Mobject, Point, VMobject
|
2015-10-12 19:39:46 -07:00
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
class Transform(Animation):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-04-17 19:29:27 -07:00
|
|
|
"path_arc" : 0,
|
|
|
|
"path_func" : None,
|
2015-09-28 16:25:18 -07:00
|
|
|
}
|
|
|
|
def __init__(self, mobject, ending_mobject, **kwargs):
|
2016-01-09 20:07:03 -08:00
|
|
|
#Copy ending_mobject so as to not mess with caller
|
2016-04-14 19:30:47 -07:00
|
|
|
ending_mobject = ending_mobject.copy()
|
2015-10-28 16:03:33 -07:00
|
|
|
digest_config(self, kwargs, locals())
|
2016-04-10 12:34:28 -07:00
|
|
|
mobject.align_data(ending_mobject)
|
2016-04-17 19:29:27 -07:00
|
|
|
self.init_path_func()
|
2015-09-25 19:43:53 -07:00
|
|
|
|
2015-09-28 16:25:18 -07:00
|
|
|
Animation.__init__(self, mobject, **kwargs)
|
|
|
|
self.name += "To" + str(ending_mobject)
|
2016-04-10 12:34:28 -07:00
|
|
|
self.mobject.stroke_width = ending_mobject.stroke_width
|
2015-10-09 19:53:38 -07:00
|
|
|
|
2016-07-22 11:22:31 -07:00
|
|
|
def update_config(self, **kwargs):
|
|
|
|
Animation.update_config(self, **kwargs)
|
|
|
|
if "path_arc" in kwargs:
|
|
|
|
self.path_func = path_along_arc(kwargs["path_arc"])
|
|
|
|
|
2016-04-17 19:29:27 -07:00
|
|
|
def init_path_func(self):
|
|
|
|
if self.path_func is not None:
|
|
|
|
return
|
|
|
|
if self.path_arc == 0:
|
|
|
|
self.path_func = straight_path
|
|
|
|
else:
|
|
|
|
self.path_func = path_along_arc(self.path_arc)
|
|
|
|
|
2016-07-22 15:50:52 -07:00
|
|
|
def get_all_families_zipped(self):
|
|
|
|
return zip(*map(
|
2015-12-22 11:02:58 -08:00
|
|
|
Mobject.submobject_family,
|
2015-11-02 14:09:49 -08:00
|
|
|
[self.mobject, self.starting_mobject, self.ending_mobject]
|
2016-07-22 15:50:52 -07:00
|
|
|
))
|
|
|
|
|
|
|
|
def update_submobject(self, submob, start, end, alpha):
|
|
|
|
submob.interpolate(start, end, alpha, self.path_func)
|
|
|
|
return self
|
2016-04-10 12:34:28 -07:00
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2015-08-07 18:10:00 -07:00
|
|
|
class ClockwiseTransform(Transform):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-04-17 19:29:27 -07:00
|
|
|
"path_arc" : -np.pi
|
2015-09-28 16:25:18 -07:00
|
|
|
}
|
2015-06-13 19:00:23 -07:00
|
|
|
|
2015-08-07 18:10:00 -07:00
|
|
|
class CounterclockwiseTransform(Transform):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-04-17 19:29:27 -07:00
|
|
|
"path_arc" : np.pi
|
2015-09-28 16:25:18 -07:00
|
|
|
}
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2015-12-19 13:06:09 -08:00
|
|
|
class GrowFromCenter(Transform):
|
|
|
|
def __init__(self, mobject, **kwargs):
|
2016-01-04 10:12:46 -08:00
|
|
|
target = mobject.copy()
|
|
|
|
point = Point(mobject.get_center())
|
|
|
|
mobject.replace(point)
|
|
|
|
mobject.highlight(point.get_color())
|
|
|
|
Transform.__init__(self, mobject, target, **kwargs)
|
2015-12-19 13:06:09 -08:00
|
|
|
|
|
|
|
class SpinInFromNothing(GrowFromCenter):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-01-01 14:51:16 -08:00
|
|
|
"path_func" : counterclockwise_path()
|
2015-09-28 16:25:18 -07:00
|
|
|
}
|
2015-06-10 22:00:35 -07:00
|
|
|
|
2015-12-25 08:26:51 -08:00
|
|
|
class ShrinkToCenter(Transform):
|
|
|
|
def __init__(self, mobject, **kwargs):
|
|
|
|
Transform.__init__(
|
|
|
|
self, mobject,
|
|
|
|
Point(mobject.get_center()),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
class ApplyMethod(Transform):
|
2016-07-22 15:50:52 -07:00
|
|
|
CONFIG = {
|
|
|
|
"submobject_mode" : "all_at_once"
|
|
|
|
}
|
2015-06-10 22:00:35 -07:00
|
|
|
def __init__(self, method, *args, **kwargs):
|
|
|
|
"""
|
|
|
|
Method is a method of Mobject. *args is for the method,
|
|
|
|
**kwargs is for the transform itself.
|
|
|
|
|
|
|
|
Relies on the fact that mobject methods return the mobject
|
|
|
|
"""
|
2016-07-22 15:50:52 -07:00
|
|
|
if not inspect.ismethod(method):
|
|
|
|
raise Exception(
|
|
|
|
"Whoops, looks like you accidentally invoked " + \
|
|
|
|
"the method you want to animate"
|
|
|
|
)
|
2015-10-20 21:55:46 -07:00
|
|
|
assert(isinstance(method.im_self, Mobject))
|
2015-06-10 22:00:35 -07:00
|
|
|
Transform.__init__(
|
|
|
|
self,
|
|
|
|
method.im_self,
|
|
|
|
copy.deepcopy(method)(*args),
|
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
|
2016-07-21 11:00:45 -07:00
|
|
|
class FadeOut(Transform):
|
2016-07-19 11:08:58 -07:00
|
|
|
CONFIG = {
|
|
|
|
"remover" : True,
|
|
|
|
}
|
2016-01-07 16:24:33 -08:00
|
|
|
def __init__(self, mobject, **kwargs):
|
2016-07-21 11:00:45 -07:00
|
|
|
target = mobject.copy()
|
|
|
|
target.fade(1)
|
|
|
|
if isinstance(mobject, VMobject):
|
|
|
|
target.set_stroke(width = 0)
|
|
|
|
target.set_fill(opacity = 0)
|
|
|
|
Transform.__init__(self, mobject, target, **kwargs)
|
2016-01-07 16:24:33 -08:00
|
|
|
|
2016-07-21 11:00:45 -07:00
|
|
|
def clean_up(self):
|
2016-07-19 11:08:58 -07:00
|
|
|
self.update(0)
|
|
|
|
|
2016-01-07 16:24:33 -08:00
|
|
|
class FadeIn(Transform):
|
|
|
|
def __init__(self, mobject, **kwargs):
|
|
|
|
target = mobject.copy()
|
|
|
|
mobject.fade(1)
|
2016-07-18 11:50:26 -07:00
|
|
|
if isinstance(mobject, VMobject):
|
|
|
|
mobject.set_stroke(width = 0)
|
2016-01-07 16:24:33 -08:00
|
|
|
Transform.__init__(self, mobject, target, **kwargs)
|
2016-07-22 15:50:52 -07:00
|
|
|
|
2016-01-07 16:24:33 -08:00
|
|
|
|
|
|
|
class ShimmerIn(DelayByOrder):
|
|
|
|
def __init__(self, mobject, **kwargs):
|
|
|
|
mobject.sort_points(lambda p : np.dot(p, DOWN+RIGHT))
|
|
|
|
DelayByOrder.__init__(self, FadeIn(mobject, **kwargs))
|
|
|
|
|
|
|
|
|
2015-10-27 21:00:50 -07:00
|
|
|
class Rotate(ApplyMethod):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2015-11-09 10:34:00 -08:00
|
|
|
"in_place" : False,
|
|
|
|
}
|
|
|
|
def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs):
|
2016-07-15 18:16:06 -07:00
|
|
|
kwargs["path_arc"] = angle
|
2015-11-09 10:34:00 -08:00
|
|
|
digest_config(self, kwargs, locals())
|
|
|
|
if self.in_place:
|
|
|
|
method = mobject.rotate_in_place
|
|
|
|
else:
|
|
|
|
method = mobject.rotate
|
|
|
|
ApplyMethod.__init__(self, method, angle, axis, **kwargs)
|
2015-10-27 21:00:50 -07:00
|
|
|
|
|
|
|
|
2015-10-20 21:55:46 -07:00
|
|
|
class ApplyPointwiseFunction(ApplyMethod):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2015-10-20 21:55:46 -07:00
|
|
|
"run_time" : DEFAULT_POINTWISE_FUNCTION_RUN_TIME
|
|
|
|
}
|
|
|
|
def __init__(self, function, mobject, **kwargs):
|
|
|
|
ApplyMethod.__init__(
|
|
|
|
self, mobject.apply_function, function, **kwargs
|
|
|
|
)
|
|
|
|
|
2015-09-28 16:25:18 -07:00
|
|
|
class FadeToColor(ApplyMethod):
|
|
|
|
def __init__(self, mobject, color, **kwargs):
|
|
|
|
ApplyMethod.__init__(self, mobject.highlight, color, **kwargs)
|
|
|
|
|
|
|
|
class ScaleInPlace(ApplyMethod):
|
|
|
|
def __init__(self, mobject, scale_factor, **kwargs):
|
|
|
|
ApplyMethod.__init__(self, mobject.scale_in_place, scale_factor, **kwargs)
|
|
|
|
|
2015-06-10 22:00:35 -07:00
|
|
|
class ApplyFunction(Transform):
|
2015-10-06 15:35:34 -07:00
|
|
|
def __init__(self, function, mobject, **kwargs):
|
2015-08-07 18:10:00 -07:00
|
|
|
Transform.__init__(
|
|
|
|
self,
|
|
|
|
mobject,
|
2015-11-02 19:09:55 -08:00
|
|
|
function(mobject.copy()),
|
2015-08-07 18:10:00 -07:00
|
|
|
**kwargs
|
|
|
|
)
|
|
|
|
self.name = "ApplyFunctionTo"+str(mobject)
|
|
|
|
|
2016-07-12 10:34:35 -07:00
|
|
|
class ApplyMatrix(ApplyPointwiseFunction):
|
2015-10-06 18:40:18 -07:00
|
|
|
#Truth be told, I'm not sure if this is useful.
|
|
|
|
def __init__(self, matrix, mobject, **kwargs):
|
|
|
|
matrix = np.array(matrix)
|
|
|
|
if matrix.shape == (2, 2):
|
2016-07-12 10:34:35 -07:00
|
|
|
new_matrix = np.identity(3)
|
|
|
|
new_matrix[:2, :2] = matrix
|
|
|
|
matrix = new_matrix
|
|
|
|
elif matrix.shape != (3, 3):
|
2015-10-06 18:40:18 -07:00
|
|
|
raise "Matrix has bad dimensions"
|
2016-07-12 10:34:35 -07:00
|
|
|
transpose = np.transpose(matrix)
|
|
|
|
def func(p):
|
|
|
|
return np.dot(p, transpose)
|
|
|
|
ApplyPointwiseFunction.__init__(self, func, mobject, **kwargs)
|
2015-06-10 22:00:35 -07:00
|
|
|
|
|
|
|
|
2016-01-07 16:24:33 -08:00
|
|
|
class TransformAnimations(Transform):
|
2016-02-27 16:32:53 -08:00
|
|
|
CONFIG = {
|
2016-01-07 16:24:33 -08:00
|
|
|
"rate_func" : squish_rate_func(smooth)
|
|
|
|
}
|
|
|
|
def __init__(self, start_anim, end_anim, **kwargs):
|
|
|
|
digest_config(self, kwargs, locals())
|
|
|
|
if "run_time" in kwargs:
|
|
|
|
self.run_time = kwargs.pop("run_time")
|
|
|
|
else:
|
|
|
|
self.run_time = max(start_anim.run_time, end_anim.run_time)
|
|
|
|
for anim in start_anim, end_anim:
|
|
|
|
anim.set_run_time(self.run_time)
|
|
|
|
|
|
|
|
if start_anim.starting_mobject.get_num_points() != end_anim.starting_mobject.get_num_points():
|
2016-04-10 12:34:28 -07:00
|
|
|
start_anim.starting_mobject.align_data(end_anim.starting_mobject)
|
2016-01-07 16:24:33 -08:00
|
|
|
for anim in start_anim, end_anim:
|
|
|
|
if hasattr(anim, "ending_mobject"):
|
2016-04-10 12:34:28 -07:00
|
|
|
anim.starting_mobject.align_data(anim.ending_mobject)
|
2016-01-07 16:24:33 -08:00
|
|
|
|
|
|
|
Transform.__init__(self, start_anim.mobject, end_anim.mobject, **kwargs)
|
|
|
|
#Rewire starting and ending mobjects
|
|
|
|
start_anim.mobject = self.starting_mobject
|
|
|
|
end_anim.mobject = self.ending_mobject
|
|
|
|
|
|
|
|
def update(self, alpha):
|
|
|
|
self.start_anim.update(alpha)
|
|
|
|
self.end_anim.update(alpha)
|
|
|
|
Transform.update(self, alpha)
|
2015-06-10 22:00:35 -07:00
|
|
|
|
|
|
|
|
|
|
|
|