Moved complex transformation out of zeta

This commit is contained in:
Grant Sanderson
2017-02-23 18:13:36 -08:00
parent d696f98725
commit c2eb360684
3 changed files with 178 additions and 251 deletions

View File

@ -1,11 +1,174 @@
from helpers import *
from mobject import VGroup
from mobject.tex_mobject import TexMobject, TextMobject
from number_line import NumberPlane
from animation import Animation
from animation.transform import ApplyPointwiseFunction
from animation.simple_animations import Homotopy
from scene import Scene
class ComplexTransformationScene(Scene):
CONFIG = {
"plane_config" : {
"x_line_frequency" : 1,
"y_line_frequency" : 1,
"secondary_line_ratio" : 1,
},
"background_fade_factor" : 0.5,
"x_min" : -int(SPACE_WIDTH),
"x_max" : int(SPACE_WIDTH),
"y_min" : -SPACE_HEIGHT,
"y_max" : SPACE_HEIGHT,
"use_multicolored_plane" : False,
"vert_start_color" : MAROON_B,
"vert_end_color" : RED,
"horiz_start_color" : GREEN_B,
"horiz_end_color" : YELLOW,
"num_anchors_to_add_per_line" : 50,
"post_transformation_stroke_width" : None,
"default_apply_complex_function_kwargs" : {
"run_time" : 5,
},
"background_label_scale_val" : 0.5,
}
def setup(self):
self.foreground_mobjects = []
self.transformable_mobjects = []
self.add_background_plane()
def add_foreground_mobject(self, mobject):
self.add_foreground_mobjects(mobject)
def add_transformable_mobjects(self, *mobjects):
self.transformable_mobjects += list(mobjects)
self.add(*mobjects)
def add_foreground_mobjects(self, *mobjects):
self.foreground_mobjects += list(mobjects)
Scene.add(self, *mobjects)
def add(self, *mobjects):
Scene.add(self, *list(mobjects)+self.foreground_mobjects)
def play(self, *animations, **kwargs):
Scene.play(
self,
*list(animations)+map(Animation, self.foreground_mobjects),
**kwargs
)
def add_background_plane(self):
background = NumberPlane(**self.plane_config).fade(
self.background_fade_factor
)
real_labels = VGroup(*[
TexMobject(str(x)).shift(
background.num_pair_to_point((x, 0))
)
for x in range(-int(self.x_max), int(self.x_max))
])
imag_labels = VGroup(*[
TexMobject("%di"%y).shift(
background.num_pair_to_point((0, y))
)
for y in range(-int(self.y_max), int(self.y_max))
if y != 0
])
for labels in real_labels, imag_labels:
for label in labels:
label.scale_in_place(self.background_label_scale_val)
label.next_to(label.get_center(), DOWN+LEFT, buff = SMALL_BUFF)
label.add_background_rectangle()
background.add(labels)
self.real_labels = real_labels
self.imag_labels = imag_labels
self.add(background)
self.background = background
def add_transformable_plane(self, animate = False):
self.plane_config.update({
"x_radius" : (self.x_max - self.x_min)/2.,
"y_radius" : (self.y_max - self.y_min)/2.,
})
plane = NumberPlane(**self.plane_config)
plane.shift(
(self.x_max+self.x_min)*RIGHT/2.,
(self.y_max+self.y_min)*UP/2.,
)
self.paint_plane(plane)
if animate:
self.play(ShowCreation(plane, run_time = 2))
else:
self.add(plane)
self.plane = plane
def prepare_for_transformation(self, mob):
if hasattr(mob, "prepare_for_nonlinear_transform"):
mob.prepare_for_nonlinear_transform(
self.num_anchors_to_add_per_line
)
#TODO...
def paint_plane(self, plane):
if self.use_multicolored_plane:
for lines in plane.main_lines, plane.secondary_lines:
lines.gradient_highlight(
self.vert_start_color,
self.vert_end_color,
self.horiz_start_color,
self.horiz_end_color,
)
plane.axes.gradient_highlight(
self.horiz_start_color,
self.vert_start_color
)
def z_to_point(self, z):
return self.background.num_pair_to_point((z.real, z.imag))
def get_transformer(self, **kwargs):
transform_kwargs = dict(self.default_apply_complex_function_kwargs)
transform_kwargs.update(kwargs)
plane = self.plane
self.prepare_for_transformation(plane)
transformer = VGroup(
plane, *self.transformable_mobjects
)
return transformer, transform_kwargs
def apply_complex_function(self, func, added_anims = [], **kwargs):
transformer, transform_kwargs = self.get_transformer(**kwargs)
transformer.generate_target()
transformer.target.apply_complex_function(func)
for mob in transformer.target[0].family_members_with_points():
mob.make_smooth()
if self.post_transformation_stroke_width is not None:
transformer.target.set_stroke(width = self.post_transformation_stroke_width)
self.play(
MoveToTarget(transformer, **transform_kwargs),
*added_anims
)
def apply_complex_homotopy(self, complex_homotopy, added_anims = [], **kwargs):
transformer, transform_kwargs = self.get_transformer(**kwargs)
def homotopy(x, y, z, t):
output = complex_homotopy(complex(x, y), t)
return (output.real, output.imag, z)
self.play(
SmoothedVectorizedHomotopy(
homotopy, transformer,
**transform_kwargs
),
*added_anims
)
##### Unsure about what comes under here...
def complex_string(complex_num):
return filter(lambda c : c not in "()", str(complex_num))
@ -99,107 +262,22 @@ class ComplexHomotopy(Homotopy):
Homotopy.__init__(self, homotopy, mobject, *args, **kwargs)
class ComplexMultiplication(Scene):
@staticmethod
def args_to_string(multiplier, mark_one = False):
num_str = complex_string(multiplier)
arrow_str = "MarkOne" if mark_one else ""
return num_str + arrow_str
@staticmethod
def string_to_args(arg_string):
parts = arg_string.split()
multiplier = complex(parts[0])
mark_one = len(parts) > 1 and parts[1] == "MarkOne"
return (multiplier, mark_one)
def construct(self, multiplier, mark_one = False, **plane_config):
norm = np.linalg.norm(multiplier)
arg = np.log(multiplier).imag
plane_config["faded_line_frequency"] = 0
plane_config.update(DEFAULT_PLANE_CONFIG)
if norm > 1 and "density" not in plane_config:
plane_config["density"] = norm*DEFAULT_POINT_DENSITY_1D
if "radius" not in plane_config:
radius = SPACE_WIDTH
if norm > 0 and norm < 1:
radius /= norm
else:
radius = plane_config["radius"]
plane_config["x_radius"] = plane_config["y_radius"] = radius
plane = ComplexPlane(**plane_config)
self.plane = plane
self.add(plane)
# plane.add_spider_web()
self.anim_config = {
"run_time" : 2.0,
"path_func" : path_along_arc(arg)
}
plane_config["faded_line_frequency"] = 0.5
background = ComplexPlane(color = "grey", **plane_config)
# background.add_spider_web()
labels = background.get_coordinate_labels()
self.paint_into_background(background, *labels)
self.mobjects_to_move_without_molding = []
if mark_one:
self.draw_dot("1", 1, True)
self.draw_dot("z", multiplier)
self.mobjects_to_multiply = [plane]
self.additional_animations = []
self.multiplier = multiplier
if self.__class__ == ComplexMultiplication:
self.apply_multiplication()
def draw_dot(self, tex_string, value, move_dot = False):
dot = Dot(
self.plane.number_to_point(value),
radius = 0.1*self.plane.unit_to_spatial_width,
color = BLUE if value == 1 else YELLOW
)
label = TexMobject(tex_string)
label.shift(dot.get_center()+1.5*UP+RIGHT)
arrow = Arrow(label, dot)
self.add(label)
self.play(ShowCreation(arrow))
self.play(ShowCreation(dot))
self.dither()
self.remove(label, arrow)
if move_dot:
self.mobjects_to_move_without_molding.append(dot)
return dot
def apply_multiplication(self):
def func((x, y, z)):
complex_num = self.multiplier*complex(x, y)
return (complex_num.real, complex_num.imag, z)
mobjects = self.mobjects_to_multiply
mobjects += self.mobjects_to_move_without_molding
mobjects += [anim.mobject for anim in self.additional_animations]
self.add(*mobjects)
full_multiplications = [
ApplyMethod(mobject.apply_function, func, **self.anim_config)
for mobject in self.mobjects_to_multiply
]
movements_with_plane = [
ApplyMethod(
mobject.shift,
func(mobject.get_center())-mobject.get_center(),
**self.anim_config
)
for mobject in self.mobjects_to_move_without_molding
]
self.dither()
self.play(*reduce(op.add, [
full_multiplications,
movements_with_plane,
self.additional_animations
]))
self.dither()