mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 02:35:22 +08:00
Beginnings of organization
This commit is contained in:
155
animation/transform.py
Normal file
155
animation/transform.py
Normal file
@ -0,0 +1,155 @@
|
||||
import numpy as np
|
||||
import itertools as it
|
||||
import inspect
|
||||
import copy
|
||||
import warnings
|
||||
|
||||
from animation import Animation
|
||||
from mobject import Mobject
|
||||
from constants import *
|
||||
from helpers import *
|
||||
|
||||
class Transform(Animation):
|
||||
def __init__(self, mobject1, mobject2,
|
||||
run_time = DEFAULT_TRANSFORM_RUN_TIME,
|
||||
black_out_extra_points = True,
|
||||
*args, **kwargs):
|
||||
count1, count2 = mobject1.get_num_points(), mobject2.get_num_points()
|
||||
if count2 == 0:
|
||||
mobject2 = Point((SPACE_WIDTH, SPACE_HEIGHT, 0))
|
||||
count2 = mobject2.get_num_points()
|
||||
Mobject.align_data(mobject1, mobject2)
|
||||
Animation.__init__(self, mobject1, run_time = run_time, *args, **kwargs)
|
||||
self.ending_mobject = mobject2
|
||||
self.mobject.SHOULD_BUFF_POINTS = \
|
||||
mobject1.SHOULD_BUFF_POINTS and mobject2.SHOULD_BUFF_POINTS
|
||||
self.reference_mobjects.append(mobject2)
|
||||
self.name += "To" + str(mobject2)
|
||||
|
||||
if black_out_extra_points and count2 < count1:
|
||||
#Ensure redundant pixels fade to black
|
||||
indices = np.arange(
|
||||
0, count1-1, float(count1) / count2
|
||||
).astype('int')
|
||||
temp = np.zeros(mobject2.points.shape)
|
||||
temp[indices] = mobject2.rgbs[indices]
|
||||
mobject2.rgbs = temp
|
||||
self.non_redundant_m2_indices = indices
|
||||
|
||||
def update_mobject(self, alpha):
|
||||
Mobject.interpolate(
|
||||
self.starting_mobject,
|
||||
self.ending_mobject,
|
||||
self.mobject,
|
||||
alpha
|
||||
)
|
||||
|
||||
def clean_up(self):
|
||||
if hasattr(self, "non_redundant_m2_indices"):
|
||||
#Reduce mobject (which has become identical to mobject2), as
|
||||
#well as mobject2 itself
|
||||
for mobject in [self.mobject, self.ending_mobject]:
|
||||
for attr in ['points', 'rgbs']:
|
||||
setattr(
|
||||
mobject, attr,
|
||||
getattr(
|
||||
self.ending_mobject,
|
||||
attr
|
||||
)[self.non_redundant_m2_indices]
|
||||
)
|
||||
|
||||
class SemiCircleTransform(Transform):
|
||||
def update_mobject(self, alpha):
|
||||
sm, em = self.starting_mobject, self.ending_mobject
|
||||
midpoints = (sm.points + em.points) / 2
|
||||
angle = alpha * np.pi
|
||||
rotation_matrix = np.matrix([
|
||||
[np.cos(angle), np.sin(angle), 0],
|
||||
[-np.sin(angle), np.cos(angle), 0],
|
||||
[0, 0, 1],
|
||||
])
|
||||
self.mobject.points = np.dot(
|
||||
sm.points - midpoints,
|
||||
np.transpose(rotation_matrix)
|
||||
) + midpoints
|
||||
self.mobject.rgbs = (1-alpha)*sm.rgbs + alpha*em.rgbs
|
||||
|
||||
class FadeToColor(Transform):
|
||||
def __init__(self, mobject, color, *args, **kwargs):
|
||||
target = copy.deepcopy(mobject).highlight(color)
|
||||
Transform.__init__(self, mobject, target, *args, **kwargs)
|
||||
|
||||
class Highlight(FadeToColor):
|
||||
def __init__(self, mobject, color = "red",
|
||||
run_time = DEFAULT_ANIMATION_RUN_TIME,
|
||||
alpha_func = there_and_back, *args, **kwargs):
|
||||
FadeToColor.__init__(
|
||||
self, mobject, color,
|
||||
run_time = run_time,
|
||||
alpha_func = alpha_func,
|
||||
*args, **kwargs
|
||||
)
|
||||
|
||||
class ScaleInPlace(Transform):
|
||||
def __init__(self, mobject, scale_factor, *args, **kwargs):
|
||||
target = copy.deepcopy(mobject)
|
||||
center = mobject.get_center()
|
||||
target.shift(-center).scale(scale_factor).shift(center)
|
||||
Transform.__init__(self, mobject, target, *args, **kwargs)
|
||||
|
||||
class ApplyMethod(Transform):
|
||||
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
|
||||
"""
|
||||
if not inspect.ismethod(method) or \
|
||||
not isinstance(method.im_self, Mobject):
|
||||
raise "Not a valid Mobject method"
|
||||
Transform.__init__(
|
||||
self,
|
||||
method.im_self,
|
||||
copy.deepcopy(method)(*args),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
class ApplyFunction(Transform):
|
||||
def __init__(self, function, mobject, run_time = DEFAULT_ANIMATION_RUN_TIME,
|
||||
*args, **kwargs):
|
||||
map_image = copy.deepcopy(mobject)
|
||||
map_image.points = np.array(map(function, map_image.points))
|
||||
Transform.__init__(self, mobject, map_image, run_time = run_time,
|
||||
*args, **kwargs)
|
||||
self.name = "".join([
|
||||
"Apply",
|
||||
"".join([s.capitalize() for s in function.__name__.split("_")]),
|
||||
"To" + str(mobject)
|
||||
])
|
||||
|
||||
class ComplexFunction(ApplyFunction):
|
||||
def __init__(self, function, *args, **kwargs):
|
||||
def point_map(point):
|
||||
x, y, z = point
|
||||
c = np.complex(x, y)
|
||||
c = function(c)
|
||||
return c.real, c.imag, z
|
||||
if len(args) > 0:
|
||||
args = list(args)
|
||||
mobject = args.pop(0)
|
||||
elif "mobject" in kwargs:
|
||||
mobject = kwargs.pop("mobject")
|
||||
else:
|
||||
mobject = Grid()
|
||||
ApplyFunction.__init__(self, point_map, mobject, *args, **kwargs)
|
||||
self.name = "ComplexFunction" + to_cammel_case(function.__name__)
|
||||
#Todo, abstract away function naming'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user