mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
Up to description of angle-preservation
This commit is contained in:
parent
b9f0e6aa48
commit
ab75d251b9
4 changed files with 573 additions and 128 deletions
|
@ -141,7 +141,7 @@ class Camera(object):
|
|||
result = ""
|
||||
for mob in [vmobject]+vmobject.get_subpath_mobjects():
|
||||
points = mob.points
|
||||
points = self.adjust_out_of_range_points(points)
|
||||
# points = self.adjust_out_of_range_points(points)
|
||||
if len(points) == 0:
|
||||
continue
|
||||
points = self.align_points_to_camera(points)
|
||||
|
|
|
@ -117,24 +117,35 @@ class Mobject(object):
|
|||
return self
|
||||
|
||||
|
||||
def scale(self, scale_factor):
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points *= scale_factor
|
||||
return self
|
||||
|
||||
def rotate(self, angle, axis = OUT, axes = [], about_point = None):
|
||||
if len(axes) == 0:
|
||||
axes = [axis]
|
||||
def scale(self, scale_factor, about_point = None):
|
||||
if about_point is not None:
|
||||
self.shift(-about_point)
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points *= scale_factor
|
||||
if about_point is not None:
|
||||
self.shift(about_point)
|
||||
return self
|
||||
|
||||
def scale_about_point(self, scale_factor, point):
|
||||
self.do_about_point(point, self.scale, scale_factor)
|
||||
return self
|
||||
|
||||
def rotate_about_origin(self, angle, axis = OUT, axes = []):
|
||||
if len(axes) == 0:
|
||||
axes = [axis]
|
||||
rot_matrix = np.identity(self.dim)
|
||||
for axis in axes:
|
||||
rot_matrix = np.dot(rot_matrix, rotation_matrix(angle, axis))
|
||||
t_rot_matrix = np.transpose(rot_matrix)
|
||||
for mob in self.family_members_with_points():
|
||||
mob.points = np.dot(mob.points, t_rot_matrix)
|
||||
if about_point is not None:
|
||||
self.shift(about_point)
|
||||
return self
|
||||
|
||||
def rotate(self, angle, axis = OUT, axes = [], about_point = None):
|
||||
if about_point is None:
|
||||
self.rotate_about_origin(angle, axis, axes)
|
||||
else:
|
||||
self.do_about_point(about_point, self.rotate, angle, axis, axes)
|
||||
return self
|
||||
|
||||
def stretch(self, factor, dim):
|
||||
|
@ -181,11 +192,14 @@ class Mobject(object):
|
|||
|
||||
#### In place operations ######
|
||||
|
||||
def do_in_place(self, method, *args, **kwargs):
|
||||
center = self.get_center()
|
||||
self.shift(-center)
|
||||
def do_about_point(self, point, method, *args, **kwargs):
|
||||
self.shift(-point)
|
||||
method(*args, **kwargs)
|
||||
self.shift(center)
|
||||
self.shift(point)
|
||||
return self
|
||||
|
||||
def do_in_place(self, method, *args, **kwargs):
|
||||
self.do_about_point(self.get_center(), method, *args, **kwargs)
|
||||
return self
|
||||
|
||||
def rotate_in_place(self, angle, axis = OUT, axes = []):
|
||||
|
|
|
@ -358,32 +358,34 @@ class TeacherStudentsScene(Scene):
|
|||
content = content[0]
|
||||
else:
|
||||
raise Exception("Invalid content type")
|
||||
content_intro_anims = self.get_bubble_intro_animation(
|
||||
|
||||
anims = []
|
||||
#Remove other bubbles
|
||||
for p in self.get_everyone():
|
||||
if (p.bubble is not None) and (p is not pi_creature):
|
||||
anims += [
|
||||
FadeOut(p.bubble),
|
||||
FadeOut(p.bubble.content)
|
||||
]
|
||||
p.bubble = None
|
||||
anims.append(ApplyMethod(p.change_mode, "plain"))
|
||||
#Bring in new bubble
|
||||
anims += self.get_bubble_intro_animation(
|
||||
content, bubble_type, pi_creature, **bubble_kwargs
|
||||
)
|
||||
|
||||
#Add changing mode
|
||||
if not target_mode:
|
||||
if bubble_type is "speech":
|
||||
target_mode = "speaking"
|
||||
else:
|
||||
target_mode = "pondering"
|
||||
|
||||
for p in self.get_everyone():
|
||||
if (p.bubble is not None) and (p is not pi_creature):
|
||||
added_anims += [
|
||||
FadeOut(p.bubble),
|
||||
FadeOut(p.bubble.content)
|
||||
]
|
||||
p.bubble = None
|
||||
added_anims.append(ApplyMethod(p.change_mode, "plain"))
|
||||
|
||||
anims = added_anims + content_intro_anims + [
|
||||
anims.append(
|
||||
ApplyMethod(
|
||||
pi_creature.change_mode,
|
||||
target_mode,
|
||||
),
|
||||
]
|
||||
self.play(*anims)
|
||||
)
|
||||
)
|
||||
self.play(*anims + added_anims)
|
||||
return pi_creature.bubble
|
||||
|
||||
def teacher_says(self, *content, **kwargs):
|
||||
|
|
623
zeta.py
623
zeta.py
|
@ -27,12 +27,16 @@ mpmath.mp.dps = 7
|
|||
|
||||
|
||||
def zeta(z):
|
||||
max_norm = 5*SPACE_WIDTH
|
||||
max_norm = SPACE_WIDTH
|
||||
try:
|
||||
return np.complex(mpmath.zeta(z))
|
||||
except:
|
||||
return np.complex(max_norm, 0)
|
||||
|
||||
def d_zeta(z):
|
||||
epsilon = 0.01
|
||||
return (zeta(z + epsilon) - zeta(z))/epsilon
|
||||
|
||||
class ComplexTransformationScene(Scene):
|
||||
CONFIG = {
|
||||
"plane_config" : {
|
||||
|
@ -87,13 +91,13 @@ class ComplexTransformationScene(Scene):
|
|||
TexMobject(str(x)).shift(
|
||||
background.num_pair_to_point((x, 0))
|
||||
)
|
||||
for x in range(int(self.x_min), int(self.x_max)+1)
|
||||
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_min), int(self.y_max)+1)
|
||||
for y in range(-int(self.y_max), int(self.y_max))
|
||||
if y != 0
|
||||
])
|
||||
for labels in real_labels, imag_labels:
|
||||
|
@ -124,11 +128,12 @@ class ComplexTransformationScene(Scene):
|
|||
self.add(plane)
|
||||
self.plane = plane
|
||||
|
||||
def add_points_to_plane(self, plane):
|
||||
#TODO
|
||||
plane.prepare_for_nonlinear_transform(
|
||||
self.num_anchors_to_add_per_line
|
||||
)
|
||||
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):
|
||||
for lines in plane.main_lines, plane.secondary_lines:
|
||||
|
@ -150,7 +155,7 @@ class ComplexTransformationScene(Scene):
|
|||
transform_kwargs = dict(self.default_apply_complex_function_kwargs)
|
||||
transform_kwargs.update(kwargs)
|
||||
plane = self.plane
|
||||
self.add_points_to_plane(plane)
|
||||
self.prepare_for_transformation(plane)
|
||||
transformer = VGroup(
|
||||
plane, *self.transformable_mobjects
|
||||
)
|
||||
|
@ -186,22 +191,68 @@ class ComplexTransformationScene(Scene):
|
|||
|
||||
class ZetaTransformationScene(ComplexTransformationScene):
|
||||
CONFIG = {
|
||||
"num_anchors_in_extra_lines" : 300,
|
||||
"anchor_density" : 35,
|
||||
"min_added_anchors" : 10,
|
||||
"max_added_anchors" : 300,
|
||||
"num_anchors_to_add_per_line" : 75,
|
||||
"post_transformation_storke_width" : 2,
|
||||
"default_apply_complex_function_kwargs" : {
|
||||
"run_time" : 5,
|
||||
}
|
||||
},
|
||||
"x_min" : 1,
|
||||
"x_max" : int(SPACE_WIDTH+2),
|
||||
"extra_lines_x_min" : -2,
|
||||
"extra_lines_x_max" : 4,
|
||||
"extra_lines_y_min" : -2,
|
||||
"extra_lines_y_max" : 2,
|
||||
}
|
||||
def add_extra_plane_lines_for_zeta(self, step_size = 1./16, animate = False):
|
||||
def prepare_for_transformation(self, mob):
|
||||
for line in mob.family_members_with_points():
|
||||
#Find point of line cloest to 1 on C
|
||||
p1 = line.get_start()+LEFT
|
||||
p2 = line.get_end()+LEFT
|
||||
t = (-np.dot(p1, p2-p1))/(np.linalg.norm(p2-p1)**2)
|
||||
closest_to_one = interpolate(
|
||||
line.get_start(), line.get_end(), t
|
||||
)
|
||||
#See how big this line will become
|
||||
diameter = abs(zeta(complex(*closest_to_one[:2])))
|
||||
target_num_anchors = np.clip(
|
||||
int(self.anchor_density*np.pi*diameter),
|
||||
self.min_added_anchors,
|
||||
self.max_added_anchors,
|
||||
)
|
||||
num_anchors = line.get_num_anchor_points()
|
||||
if num_anchors < target_num_anchors:
|
||||
line.insert_n_anchor_points(target_num_anchors-num_anchors)
|
||||
line.make_smooth()
|
||||
|
||||
def add_extra_plane_lines_for_zeta(self, animate = False, **kwargs):
|
||||
dense_grid = self.get_dense_grid(**kwargs)
|
||||
if animate:
|
||||
self.play(ShowCreation(dense_grid))
|
||||
self.plane.add(dense_grid)
|
||||
self.add(self.plane)
|
||||
|
||||
def get_dense_grid(self, step_size = 1./16):
|
||||
epsilon = 0.1
|
||||
x_range = np.arange(
|
||||
max(self.x_min, self.extra_lines_x_min),
|
||||
min(self.x_max, self.extra_lines_x_max),
|
||||
step_size
|
||||
)
|
||||
y_range = np.arange(
|
||||
max(self.y_min, self.extra_lines_y_min),
|
||||
min(self.y_max, self.extra_lines_y_max),
|
||||
step_size
|
||||
)
|
||||
vert_lines = VGroup(*[
|
||||
Line(
|
||||
self.y_min*UP,
|
||||
self.y_max*UP,
|
||||
).shift(x*RIGHT)
|
||||
for x in np.arange(max(0, self.x_min), 2, step_size)
|
||||
if abs(x) > epsilon
|
||||
for x in x_range
|
||||
if abs(x-1) > epsilon
|
||||
])
|
||||
vert_lines.gradient_highlight(
|
||||
self.vert_start_color, self.vert_end_color
|
||||
|
@ -211,23 +262,21 @@ class ZetaTransformationScene(ComplexTransformationScene):
|
|||
self.x_min*RIGHT,
|
||||
self.x_max*RIGHT,
|
||||
).shift(y*UP)
|
||||
for y in np.arange(-1, 1, step_size)
|
||||
for y in y_range
|
||||
if abs(y) > epsilon
|
||||
])
|
||||
horiz_lines.gradient_highlight(
|
||||
self.horiz_start_color, self.horiz_end_color
|
||||
)
|
||||
for lines in horiz_lines, vert_lines:
|
||||
lines.set_stroke(width = 1)
|
||||
for line in lines:
|
||||
line.insert_n_anchor_points(self.num_anchors_in_extra_lines)
|
||||
lines.make_smooth()
|
||||
dense_grid = VGroup(horiz_lines, vert_lines)
|
||||
dense_grid.set_stroke(width = 1)
|
||||
return dense_grid
|
||||
|
||||
def add_reflected_plane(self, animate = False):
|
||||
reflected_plane = self.get_reflected_plane()
|
||||
if animate:
|
||||
self.play(*[
|
||||
ShowCreation(lines)
|
||||
for lines in vert_lines, horiz_lines
|
||||
])
|
||||
self.plane.add(vert_lines, horiz_lines)
|
||||
self.play(ShowCreation(reflected_plane, run_time = 5))
|
||||
self.plane.add(reflected_plane)
|
||||
self.add(self.plane)
|
||||
|
||||
def get_reflected_plane(self):
|
||||
|
@ -237,9 +286,7 @@ class ZetaTransformationScene(ComplexTransformationScene):
|
|||
mob.highlight(
|
||||
Color(rgb = 1-0.5*color_to_rgb(mob.get_color()))
|
||||
)
|
||||
reflected_plane.prepare_for_nonlinear_transform(
|
||||
self.num_anchors_in_extra_lines
|
||||
)
|
||||
self.prepare_for_transformation(reflected_plane)
|
||||
reflected_plane.submobjects = list(reversed(
|
||||
reflected_plane.family_members_with_points()
|
||||
))
|
||||
|
@ -252,24 +299,31 @@ class ZetaTransformationScene(ComplexTransformationScene):
|
|||
|
||||
class TestZetaOnFullPlane(ZetaTransformationScene):
|
||||
CONFIG = {
|
||||
"num_anchors_to_add_per_line" : 300,
|
||||
"anchor_density" : 15,
|
||||
}
|
||||
def construct(self):
|
||||
self.add_transformable_plane(animate = True)
|
||||
self.add_extra_plane_lines_for_zeta(animate = True)
|
||||
self.dither()
|
||||
self.add_transformable_plane()
|
||||
self.add_extra_plane_lines_for_zeta()
|
||||
self.prepare_for_transformation(self.plane)
|
||||
print sum([
|
||||
mob.get_num_points()
|
||||
for mob in self.plane.family_members_with_points()
|
||||
])
|
||||
print len(self.plane.family_members_with_points())
|
||||
self.show_frame()
|
||||
self.apply_zeta_function()
|
||||
self.dither(3)
|
||||
self.dither()
|
||||
|
||||
class TestZetaOnHalfPlane(ZetaTransformationScene):
|
||||
CONFIG = {
|
||||
"x_min" : 1,
|
||||
"x_max" : int(SPACE_WIDTH+2)
|
||||
}
|
||||
def construct(self):
|
||||
self.add_transformable_plane(animate = True)
|
||||
self.add_extra_plane_lines_for_zeta(animate = True)
|
||||
self.add_reflected_plane(animate = True)
|
||||
self.apply_zeta_function()
|
||||
self.dither(3)
|
||||
|
||||
class TestZetaOnLine(ZetaTransformationScene):
|
||||
def construct(self):
|
||||
|
@ -306,8 +360,12 @@ class IntroduceZeta(ZetaTransformationScene):
|
|||
randy.to_corner(DOWN+RIGHT)
|
||||
|
||||
self.add_foreground_mobjects(title, func_mob)
|
||||
self.add_transformable_plane(animate = True)
|
||||
self.add_extra_plane_lines_for_zeta(animate = True)
|
||||
self.add_transformable_plane()
|
||||
self.add_extra_plane_lines_for_zeta()
|
||||
self.play(ShowCreation(self.plane, run_time = 2))
|
||||
reflected_plane = self.get_reflected_plane()
|
||||
self.play(ShowCreation(reflected_plane, run_time = 2))
|
||||
self.plane.add(reflected_plane)
|
||||
self.dither()
|
||||
self.apply_zeta_function()
|
||||
self.dither(2)
|
||||
|
@ -393,8 +451,6 @@ class WhyPeopleMayKnowIt(TeacherStudentsScene):
|
|||
|
||||
class PreviewZetaAndContinuation(ZetaTransformationScene):
|
||||
CONFIG = {
|
||||
"x_min" : 1,
|
||||
"num_anchors_to_add_per_line" : 300,
|
||||
"default_apply_complex_function_kwargs" : {
|
||||
"run_time" : 4,
|
||||
}
|
||||
|
@ -402,14 +458,7 @@ class PreviewZetaAndContinuation(ZetaTransformationScene):
|
|||
def construct(self):
|
||||
self.add_transformable_plane()
|
||||
self.add_extra_plane_lines_for_zeta()
|
||||
reflected_plane = self.plane.copy()
|
||||
reflected_plane.rotate(np.pi, UP, about_point = RIGHT)
|
||||
reflected_plane.prepare_for_nonlinear_transform(self.num_anchors_to_add_per_line)
|
||||
for mob in reflected_plane.family_members_with_points():
|
||||
mob.highlight(
|
||||
Color(rgb = 1-0.5*color_to_rgb(mob.get_color()))
|
||||
)
|
||||
mob.set_stroke(width = 2)
|
||||
reflected_plane = self.get_reflected_plane()
|
||||
|
||||
titles = [
|
||||
TextMobject(
|
||||
|
@ -434,6 +483,7 @@ class PreviewZetaAndContinuation(ZetaTransformationScene):
|
|||
self.apply_zeta_function()
|
||||
reflected_plane.apply_complex_function(zeta)
|
||||
reflected_plane.make_smooth()
|
||||
reflected_plane.set_stroke(width = 2)
|
||||
self.dither()
|
||||
self.play(Transform(*titles))
|
||||
self.dither()
|
||||
|
@ -1562,14 +1612,18 @@ class VisualizingSSquared(ComplexTransformationScene):
|
|||
self.input_dots = input_dots
|
||||
self.output_dots = output_dots
|
||||
|
||||
def show_transformation(self):
|
||||
self.add_transformable_plane(animate = False)
|
||||
def add_transformable_plane(self, **kwargs):
|
||||
ComplexTransformationScene.add_transformable_plane(self, **kwargs)
|
||||
self.plane.next_to(ORIGIN, UP, buff = 0.01)
|
||||
self.plane.add(self.plane.copy().rotate(np.pi, RIGHT))
|
||||
self.plane.add(
|
||||
Line(ORIGIN, SPACE_WIDTH*RIGHT, color = self.horiz_end_color),
|
||||
Line(ORIGIN, SPACE_WIDTH*LEFT, color = self.horiz_end_color),
|
||||
)
|
||||
self.add(self.plane)
|
||||
|
||||
def show_transformation(self):
|
||||
self.add_transformable_plane()
|
||||
self.play(ShowCreation(self.plane, run_time = 3))
|
||||
|
||||
self.dither()
|
||||
|
@ -1609,7 +1663,6 @@ class ShowZetaOnHalfPlane(ZetaTransformationScene):
|
|||
CONFIG = {
|
||||
"x_min" : 1,
|
||||
"x_max" : int(SPACE_WIDTH+2),
|
||||
"num_anchors_in_extra_lines" : 300,
|
||||
}
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
|
@ -1666,7 +1719,6 @@ class ShowZetaOnHalfPlane(ZetaTransformationScene):
|
|||
self.play(morty.look_at, self.plane.get_top())
|
||||
self.dither()
|
||||
self.play(
|
||||
morty.change_mode, "happy",
|
||||
morty.look_at, self.plane.get_bottom(),
|
||||
*map(FadeOut, [bubble, bubble.content])
|
||||
)
|
||||
|
@ -1714,8 +1766,7 @@ class ShowZetaOnHalfPlane(ZetaTransformationScene):
|
|||
right_i_lines.highlight(YELLOW)
|
||||
left_i_lines.highlight(BLUE)
|
||||
for lines in right_i_lines, left_i_lines:
|
||||
for line in lines:
|
||||
line.insert_n_anchor_points(self.num_anchors_to_add_per_line)
|
||||
self.prepare_for_transformation(lines)
|
||||
|
||||
self.restore_mobjects(self.plane)
|
||||
self.plane.add(*right_i_lines)
|
||||
|
@ -1733,8 +1784,8 @@ class ShowZetaOnHalfPlane(ZetaTransformationScene):
|
|||
|
||||
left_i_lines.save_state()
|
||||
left_i_lines.apply_complex_function(zeta)
|
||||
self.play(ShowCreation(left_i_lines, run_time = 2))
|
||||
self.dither(2)
|
||||
self.play(ShowCreation(left_i_lines, run_time = 5))
|
||||
self.dither()
|
||||
self.restore_mobjects(self.plane, left_i_lines)
|
||||
self.play(Transform(self.plane, colored_plane))
|
||||
self.dither()
|
||||
|
@ -1742,12 +1793,9 @@ class ShowZetaOnHalfPlane(ZetaTransformationScene):
|
|||
|
||||
def show_continuation(self):
|
||||
reflected_plane = self.get_reflected_plane()
|
||||
self.play(ShowCreation(reflected_plane, run_time = 5))
|
||||
self.play(ShowCreation(reflected_plane, run_time = 2))
|
||||
self.plane.add(reflected_plane)
|
||||
self.remove(self.left_i_lines)
|
||||
reflected_plane.prepare_for_nonlinear_transform(
|
||||
self.num_anchors_to_add_per_line
|
||||
)
|
||||
self.add_transformable_mobjects(reflected_plane)
|
||||
self.dither()
|
||||
self.apply_zeta_function()
|
||||
self.dither(2)
|
||||
|
@ -1835,9 +1883,8 @@ class ShowConditionalDefinition(Scene):
|
|||
|
||||
class SquiggleOnExtensions(ZetaTransformationScene):
|
||||
CONFIG = {
|
||||
"num_anchors_in_extra_lines" : 300,
|
||||
"x_min" : 1,
|
||||
"x_max" : int(SPACE_WIDTH+1),
|
||||
"x_max" : int(SPACE_WIDTH+2),
|
||||
}
|
||||
def construct(self):
|
||||
self.show_negative_one()
|
||||
|
@ -1846,20 +1893,30 @@ class SquiggleOnExtensions(ZetaTransformationScene):
|
|||
|
||||
def show_negative_one(self):
|
||||
self.add_transformable_plane()
|
||||
self.add_reflected_plane()
|
||||
thin_plane = self.plane.copy()
|
||||
self.remove(self.plane)
|
||||
self.add_extra_plane_lines_for_zeta()
|
||||
reflected_plane = self.get_reflected_plane()
|
||||
self.add(reflected_plane)
|
||||
|
||||
self.plane.add(reflected_plane)
|
||||
self.remove(self.plane)
|
||||
self.add(thin_plane)
|
||||
|
||||
dot = self.note_point(-1, "-1")
|
||||
self.add_transformable_mobjects(reflected_plane)
|
||||
self.play(
|
||||
ShowCreation(self.plane, run_time = 2),
|
||||
Animation(dot),
|
||||
run_time = 2
|
||||
)
|
||||
self.remove(thin_plane)
|
||||
self.apply_zeta_function(added_anims = [
|
||||
ApplyMethod(
|
||||
dot.move_to, self.z_to_point(-1./12),
|
||||
run_time = 5
|
||||
)
|
||||
])
|
||||
self.note_point(-1./12, "-\\frac{1}{12}")
|
||||
dot_to_remove = self.note_point(-1./12, "-\\frac{1}{12}")
|
||||
self.remove(dot_to_remove)
|
||||
self.left_plane = reflected_plane
|
||||
self.dot = dot
|
||||
|
||||
|
@ -1868,9 +1925,9 @@ class SquiggleOnExtensions(ZetaTransformationScene):
|
|||
dot.highlight(YELLOW)
|
||||
label = TexMobject(label_tex)
|
||||
label.add_background_rectangle()
|
||||
label.next_to(dot, UP, buff = 1)
|
||||
label.shift(0.5*LEFT)
|
||||
arrow = Arrow(label, dot, buff = SMALL_BUFF)
|
||||
label.next_to(dot, UP+LEFT, buff = SMALL_BUFF)
|
||||
label.shift(LEFT)
|
||||
arrow = Arrow(label.get_right(), dot, buff = SMALL_BUFF)
|
||||
|
||||
self.play(Write(label, run_time = 1))
|
||||
self.play(*map(ShowCreation, [arrow, dot]))
|
||||
|
@ -1880,11 +1937,11 @@ class SquiggleOnExtensions(ZetaTransformationScene):
|
|||
|
||||
def cycle_through_options(self):
|
||||
gamma = np.euler_gamma
|
||||
def sinusoidal_func(point):
|
||||
def shear(point):
|
||||
x, y, z = point
|
||||
return np.array([
|
||||
x - abs(0.2*np.sin(np.pi*x/gamma)*np.cos(y)),
|
||||
y + 0.2*np.sin(np.pi*x/gamma),
|
||||
x,
|
||||
y+0.25*(1-x)**2,
|
||||
0
|
||||
])
|
||||
def mixed_scalar_func(point):
|
||||
|
@ -1895,16 +1952,29 @@ class SquiggleOnExtensions(ZetaTransformationScene):
|
|||
(scalar**3)*y,
|
||||
0
|
||||
])
|
||||
def alt_sinusoidal_func(point):
|
||||
def alt_mixed_scalar_func(point):
|
||||
x, y, z = point
|
||||
scalar = 1 + (gamma-x)/(gamma+SPACE_WIDTH)
|
||||
return np.array([
|
||||
(scalar**5)*x,
|
||||
(scalar**2)*y,
|
||||
0
|
||||
])
|
||||
def sinusoidal_func(point):
|
||||
x, y, z = point
|
||||
freq = np.pi/gamma
|
||||
return np.array([
|
||||
x-0.2*np.sin(x*freq)*np.sin(x),
|
||||
y+0.2*np.sin(x*freq)*np.cos(y),
|
||||
x-0.2*np.sin(x*freq)*np.sin(y),
|
||||
y-0.2*np.sin(x*freq)*np.sin(y),
|
||||
0
|
||||
])
|
||||
|
||||
funcs = [sinusoidal_func, mixed_scalar_func, alt_sinusoidal_func]
|
||||
funcs = [
|
||||
shear,
|
||||
mixed_scalar_func,
|
||||
alt_mixed_scalar_func,
|
||||
sinusoidal_func,
|
||||
]
|
||||
new_left_planes = [
|
||||
self.left_plane.copy().apply_function(func)
|
||||
for func in funcs
|
||||
|
@ -1917,11 +1987,11 @@ class SquiggleOnExtensions(ZetaTransformationScene):
|
|||
for plane, dot in zip(new_left_planes, new_dots):
|
||||
self.play(
|
||||
Transform(self.left_plane, plane),
|
||||
Transform(self.dot, new_dot),
|
||||
Transform(self.dot, dot),
|
||||
run_time = 3
|
||||
)
|
||||
self.dither()
|
||||
self.play(FadeOut(dot))
|
||||
self.play(FadeOut(self.dot))
|
||||
|
||||
#Squiggle on example
|
||||
self.dither()
|
||||
|
@ -1934,34 +2004,393 @@ class SquiggleOnExtensions(ZetaTransformationScene):
|
|||
self.dither()
|
||||
|
||||
def lock_into_place(self):
|
||||
words = TextMobject("""
|
||||
If $\\zeta(s)$ is to have a
|
||||
\\emph{derivative} everywhere,
|
||||
there is only one possible extension
|
||||
""", alignment = "")
|
||||
words = TextMobject(
|
||||
"""Only one extension
|
||||
has a """,
|
||||
"\\emph{derivative}",
|
||||
"everywhere",
|
||||
alignment = ""
|
||||
)
|
||||
words.to_corner(UP+LEFT)
|
||||
words.highlight_by_tex("\\emph{derivative}", YELLOW)
|
||||
words.add_background_rectangle()
|
||||
words.show()
|
||||
|
||||
self.play(Write(words))
|
||||
self.add_foreground_mobjects(words)
|
||||
self.play(self.left_plane.restore)
|
||||
self.dither()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class DontKnowDerivatives(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"""
|
||||
You said we don't
|
||||
need derivatives!
|
||||
""",
|
||||
target_mode = "pleading"
|
||||
)
|
||||
self.random_blink(2)
|
||||
self.student_says(
|
||||
"""
|
||||
I get $\\frac{df}{dx}$, just not
|
||||
for complex functions
|
||||
""",
|
||||
target_mode = "confused",
|
||||
student_index = 2
|
||||
)
|
||||
self.random_blink(2)
|
||||
self.teacher_says(
|
||||
"""
|
||||
Luckily, there's a purely
|
||||
geometric intuition here.
|
||||
""",
|
||||
target_mode = "hooray"
|
||||
)
|
||||
self.change_student_modes(*["happy"]*3)
|
||||
self.random_blink(3)
|
||||
|
||||
class IntroduceAnglePreservation(VisualizingSSquared):
|
||||
CONFIG = {
|
||||
"num_anchors_to_add_per_line" : 50,
|
||||
"use_homotopy" : True,
|
||||
}
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.show_initial_transformation()
|
||||
self.cycle_through_line_pairs()
|
||||
self.note_grid_lines()
|
||||
self.name_analytic()
|
||||
|
||||
def add_title(self):
|
||||
title = TexMobject("f(", "s", ")=", "s", "^2")
|
||||
title.highlight_by_tex("s", YELLOW)
|
||||
title.scale(1.5)
|
||||
title.to_corner(UP+LEFT)
|
||||
title.add_background_rectangle()
|
||||
self.title = title
|
||||
|
||||
self.add_transformable_plane()
|
||||
self.play(Write(title))
|
||||
self.add_foreground_mobjects(title)
|
||||
self.dither()
|
||||
|
||||
def show_initial_transformation(self):
|
||||
self.apply_function()
|
||||
self.dither(2)
|
||||
self.reset()
|
||||
|
||||
def cycle_through_line_pairs(self):
|
||||
line_pairs = [
|
||||
(
|
||||
Line(3*DOWN+2*RIGHT, LEFT+2*UP),
|
||||
Line(DOWN, 3*UP+3*RIGHT)
|
||||
),
|
||||
(
|
||||
Line(RIGHT+3*DOWN, RIGHT+3*UP),
|
||||
Line(3*LEFT+UP, 3*RIGHT+UP)
|
||||
),
|
||||
(
|
||||
Line(4*RIGHT+4*DOWN, RIGHT+2*UP),
|
||||
Line(4*DOWN+RIGHT, 2*UP+2*RIGHT)
|
||||
),
|
||||
]
|
||||
for lines in line_pairs:
|
||||
self.show_angle_preservation_between_lines(*lines)
|
||||
self.reset()
|
||||
|
||||
def note_grid_lines(self):
|
||||
intersection_inputs = [
|
||||
complex(x, y)
|
||||
for x in np.arange(-5, 5, 0.5)
|
||||
for y in np.arange(0, 3, 0.5)
|
||||
if not (x <= 0 and y == 0)
|
||||
]
|
||||
brackets = VGroup(*map(
|
||||
self.get_right_angle_bracket,
|
||||
intersection_inputs
|
||||
))
|
||||
self.apply_function()
|
||||
self.dither()
|
||||
self.play(
|
||||
ShowCreation(brackets, run_time = 5),
|
||||
Animation(self.plane)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
def name_analytic(self):
|
||||
equiv = TextMobject("``Analytic'' $\\Leftrightarrow$ Angle-preserving")
|
||||
kind_of = TextMobject("...kind of")
|
||||
for text in equiv, kind_of:
|
||||
text.scale(1.2)
|
||||
text.add_background_rectangle()
|
||||
equiv.highlight(YELLOW)
|
||||
kind_of.highlight(RED)
|
||||
kind_of.next_to(equiv, RIGHT)
|
||||
VGroup(equiv, kind_of).next_to(ORIGIN, UP, buff = 1)
|
||||
|
||||
self.play(Write(equiv))
|
||||
self.dither(2)
|
||||
self.play(Write(kind_of, run_time = 1))
|
||||
self.dither(2)
|
||||
|
||||
def reset(self, faded = True):
|
||||
self.play(FadeOut(self.plane))
|
||||
self.add_transformable_plane()
|
||||
if faded:
|
||||
self.plane.fade()
|
||||
self.play(FadeIn(self.plane))
|
||||
|
||||
def apply_function(self, **kwargs):
|
||||
if self.use_homotopy:
|
||||
self.apply_complex_homotopy(
|
||||
lambda z, t : z**(1+t),
|
||||
run_time = 5,
|
||||
**kwargs
|
||||
)
|
||||
else:
|
||||
self.apply_complex_function(
|
||||
lambda z : z**2,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def show_angle_preservation_between_lines(self, *lines):
|
||||
R2_endpoints = [
|
||||
[l.get_start()[:2], l.get_end()[:2]]
|
||||
for l in lines
|
||||
]
|
||||
R2_intersection_point = intersection(*R2_endpoints)
|
||||
intersection_point = np.array(list(R2_intersection_point) + [0])
|
||||
|
||||
angle1, angle2 = [l.get_angle() for l in lines]
|
||||
arc = Arc(
|
||||
start_angle = angle1,
|
||||
angle = angle2-angle1,
|
||||
radius = 0.4,
|
||||
color = YELLOW
|
||||
)
|
||||
arc.shift(intersection_point)
|
||||
arc.insert_n_anchor_points(10)
|
||||
arc.generate_target()
|
||||
input_z = complex(*arc.get_center()[:2])
|
||||
scale_factor = abs(2*input_z)
|
||||
arc.target.scale_about_point(1./scale_factor, intersection_point)
|
||||
arc.target.apply_complex_function(lambda z : z**2)
|
||||
|
||||
angle_tex = TexMobject(
|
||||
"%d^\\circ"%abs(int((angle2-angle1)*180/np.pi))
|
||||
)
|
||||
angle_tex.highlight(arc.get_color())
|
||||
angle_tex.add_background_rectangle()
|
||||
self.put_angle_tex_next_to_arc(angle_tex, arc)
|
||||
angle_arrow = Arrow(
|
||||
angle_tex, arc,
|
||||
color = arc.get_color(),
|
||||
buff = 0.1,
|
||||
)
|
||||
angle_group = VGroup(angle_tex, angle_arrow)
|
||||
|
||||
|
||||
self.play(*map(ShowCreation, lines))
|
||||
self.play(
|
||||
Write(angle_tex),
|
||||
ShowCreation(angle_arrow),
|
||||
ShowCreation(arc)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
self.play(FadeOut(angle_group))
|
||||
self.plane.add(*lines)
|
||||
self.apply_function(added_anims = [
|
||||
MoveToTarget(arc, run_time = 5)
|
||||
])
|
||||
self.put_angle_tex_next_to_arc(angle_tex, arc)
|
||||
arrow = Arrow(angle_tex, arc, buff = 0.1)
|
||||
arrow.highlight(arc.get_color())
|
||||
self.play(
|
||||
Write(angle_tex),
|
||||
ShowCreation(arrow)
|
||||
)
|
||||
self.dither(2)
|
||||
self.play(*map(FadeOut, [arc, angle_tex, arrow]))
|
||||
|
||||
def put_angle_tex_next_to_arc(self, angle_tex, arc):
|
||||
vect = arc.point_from_proportion(0.5)-interpolate(
|
||||
arc.points[0], arc.points[-1], 0.5
|
||||
)
|
||||
unit_vect = vect/np.linalg.norm(vect)
|
||||
angle_tex.move_to(arc.get_center() + 1.7*unit_vect)
|
||||
|
||||
def get_right_angle_bracket(self, input_z):
|
||||
output_z = input_z**2
|
||||
derivative = 2*input_z
|
||||
rotation = np.log(derivative).imag
|
||||
|
||||
brackets = VGroup(
|
||||
Line(RIGHT, RIGHT+UP),
|
||||
Line(RIGHT+UP, UP)
|
||||
)
|
||||
brackets.scale(0.15)
|
||||
brackets.set_stroke(width = 2)
|
||||
brackets.highlight(YELLOW)
|
||||
brackets.shift(0.02*UP) ##Why???
|
||||
brackets.rotate(rotation, about_point = ORIGIN)
|
||||
brackets.shift(self.z_to_point(output_z))
|
||||
return brackets
|
||||
|
||||
class AngleAtZeroDerivativePoints(IntroduceAnglePreservation):
|
||||
CONFIG = {
|
||||
"use_homotopy" : True
|
||||
}
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.is_before_transformation = True
|
||||
self.add_transformable_plane()
|
||||
self.plane.fade()
|
||||
line = Line(3*LEFT+0.5*UP, 3*RIGHT+0.5*DOWN)
|
||||
self.show_angle_preservation_between_lines(
|
||||
line, line.copy().rotate(np.pi/5)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
def add_title(self):
|
||||
title = TexMobject("f(", "s", ")=", "s", "^2")
|
||||
title.highlight_by_tex("s", YELLOW)
|
||||
title.scale(1.5)
|
||||
title.to_corner(UP+LEFT)
|
||||
title.add_background_rectangle()
|
||||
derivative = TexMobject("f'(0) = 0")
|
||||
derivative.highlight(RED)
|
||||
derivative.scale(1.2)
|
||||
derivative.add_background_rectangle()
|
||||
derivative.next_to(title, DOWN)
|
||||
|
||||
self.add_foreground_mobjects(title, derivative)
|
||||
|
||||
|
||||
def put_angle_tex_next_to_arc(self, angle_tex, arc):
|
||||
IntroduceAnglePreservation.put_angle_tex_next_to_arc(
|
||||
self, angle_tex, arc
|
||||
)
|
||||
if not self.is_before_transformation:
|
||||
two_dot = TexMobject("2 \\times ")
|
||||
two_dot.highlight(angle_tex.get_color())
|
||||
two_dot.next_to(angle_tex, LEFT, buff = SMALL_BUFF)
|
||||
two_dot.add_background_rectangle()
|
||||
center = angle_tex.get_center()
|
||||
angle_tex.add_to_back(two_dot)
|
||||
angle_tex.move_to(center)
|
||||
else:
|
||||
self.is_before_transformation = False
|
||||
|
||||
class AnglePreservationAtAnyPairOfPoints(IntroduceAnglePreservation):
|
||||
def construct(self):
|
||||
self.add_transformable_plane()
|
||||
self.plane.fade()
|
||||
line_pairs = self.get_line_pairs()
|
||||
line_pair = line_pairs[0]
|
||||
for target_pair in line_pairs[1:]:
|
||||
self.play(Transform(
|
||||
line_pair, target_pair,
|
||||
run_time = 2,
|
||||
path_arc = np.pi
|
||||
))
|
||||
self.dither()
|
||||
self.show_angle_preservation_between_lines(*line_pair)
|
||||
self.show_example_analytic_functions()
|
||||
|
||||
def get_line_pairs(self):
|
||||
return list(it.starmap(VGroup, [
|
||||
(
|
||||
Line(3*DOWN, 3*LEFT+2*UP),
|
||||
Line(2*LEFT+DOWN, 3*UP+RIGHT)
|
||||
),
|
||||
(
|
||||
Line(2*RIGHT+DOWN, 3*LEFT+2*UP),
|
||||
Line(LEFT+3*DOWN, 4*RIGHT+3*UP),
|
||||
),
|
||||
(
|
||||
Line(LEFT+3*DOWN, LEFT+3*UP),
|
||||
Line(5*LEFT+UP, 3*RIGHT+UP)
|
||||
),
|
||||
(
|
||||
Line(4*RIGHT+3*DOWN, RIGHT+2*UP),
|
||||
Line(3*DOWN+RIGHT, 2*UP+2*RIGHT)
|
||||
),
|
||||
]))
|
||||
|
||||
def show_example_analytic_functions(self):
|
||||
words = TextMobject("Examples of analytic functions:")
|
||||
words.shift(2*UP)
|
||||
words.highlight(YELLOW)
|
||||
words.add_background_rectangle()
|
||||
words.next_to(UP, UP).to_edge(LEFT)
|
||||
functions = TextMobject(
|
||||
"$e^x$, ",
|
||||
"$\\sin(x)$, ",
|
||||
"any polynomial, "
|
||||
"$\\log(x)$, ",
|
||||
"\\dots",
|
||||
)
|
||||
functions.next_to(ORIGIN, UP).to_edge(LEFT)
|
||||
for function in functions:
|
||||
function.add_to_back(BackgroundRectangle(function))
|
||||
|
||||
self.play(Write(words))
|
||||
for function in functions:
|
||||
self.play(FadeIn(function))
|
||||
self.dither()
|
||||
|
||||
class NoteZetaFunctionAnalyticOnRightHalf(ZetaTransformationScene):
|
||||
CONFIG = {
|
||||
"anchor_density" : 35,
|
||||
}
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.add_transformable_plane(animate = False)
|
||||
self.add_extra_plane_lines_for_zeta(animate = True)
|
||||
self.apply_zeta_function()
|
||||
self.note_right_angles()
|
||||
|
||||
def add_title(self):
|
||||
title = TexMobject(
|
||||
"\\zeta(s) = \\sum_{n=1}^\\infty \\frac{1}{n^s}"
|
||||
)
|
||||
title[2].highlight(YELLOW)
|
||||
title[-1].highlight(YELLOW)
|
||||
title.add_background_rectangle()
|
||||
title.to_corner(UP+LEFT)
|
||||
self.add_foreground_mobjects(title)
|
||||
|
||||
def note_right_angles(self):
|
||||
intersection_inputs = [
|
||||
complex(x, y)
|
||||
for x in np.arange(1+2./16, 1.4, 1./16)
|
||||
for y in np.arange(-0.5, 0.5, 1./16)
|
||||
if abs(y) > 1./16
|
||||
]
|
||||
brackets = VGroup(*map(
|
||||
self.get_right_angle_bracket,
|
||||
intersection_inputs
|
||||
))
|
||||
self.play(ShowCreation(brackets, run_time = 3))
|
||||
self.dither()
|
||||
|
||||
def get_right_angle_bracket(self, input_z):
|
||||
output_z = zeta(input_z)
|
||||
derivative = d_zeta(input_z)
|
||||
rotation = np.log(derivative).imag
|
||||
|
||||
brackets = VGroup(
|
||||
Line(RIGHT, RIGHT+UP),
|
||||
Line(RIGHT+UP, UP)
|
||||
)
|
||||
brackets.scale(0.1)
|
||||
brackets.set_stroke(width = 2)
|
||||
brackets.highlight(YELLOW)
|
||||
brackets.rotate(rotation, about_point = ORIGIN)
|
||||
brackets.shift(self.z_to_point(output_z))
|
||||
return brackets
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue