mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 08:54:38 +08:00
Finished main visualizations of triples
This commit is contained in:
@ -84,6 +84,9 @@ class TexMobject(SVGMobject):
|
||||
if tex == "\\over":
|
||||
#fraction line needs something to be over
|
||||
tex = "\\over\\,"
|
||||
for t1, t2 in ("\\left", "\\right"), ("\\right", "\\left"):
|
||||
if t1 in tex and t2 not in tex:
|
||||
tex = tex.replace(t1, "\\big")
|
||||
return tex
|
||||
|
||||
def remove_stray_braces(self, tex):
|
||||
|
@ -188,6 +188,10 @@ class ComplexPlane(NumberPlane):
|
||||
number = complex(number)
|
||||
return self.coords_to_point(number.real, number.imag)
|
||||
|
||||
def point_to_number(self, point):
|
||||
x, y = self.point_to_coords(point)
|
||||
return complex(x, y)
|
||||
|
||||
def get_coordinate_labels(self, *numbers):
|
||||
result = VGroup()
|
||||
nudge = 0.1*(DOWN+RIGHT)
|
||||
@ -245,7 +249,8 @@ class ComplexHomotopy(Homotopy):
|
||||
"""
|
||||
Complex Hootopy a function Cx[0, 1] to C
|
||||
"""
|
||||
def homotopy((x, y, z, t)):
|
||||
def homotopy(event):
|
||||
x, y, z, t = event
|
||||
c = complex_homotopy((complex(x, y), t))
|
||||
return (c.real, c.imag, z)
|
||||
Homotopy.__init__(self, homotopy, mobject, *args, **kwargs)
|
||||
|
@ -123,10 +123,10 @@ class Line(VMobject):
|
||||
return self.get_start(), self.get_end()
|
||||
|
||||
def get_start(self):
|
||||
return self.points[0]
|
||||
return np.array(self.points[0])
|
||||
|
||||
def get_end(self):
|
||||
return self.points[-1]
|
||||
return np.array(self.points[-1])
|
||||
|
||||
def get_slope(self):
|
||||
start, end = self.get_start_and_end()
|
||||
|
972
triples.py
972
triples.py
@ -39,6 +39,10 @@ V_COLOR = RED
|
||||
#revert_to_original_skipping_status
|
||||
|
||||
def complex_string_with_i(z):
|
||||
if z.real == 0:
|
||||
return str(int(z.imag)) + "i"
|
||||
elif z.imag == 0:
|
||||
return str(int(z.real))
|
||||
return complex_string(z).replace("j", "i")
|
||||
|
||||
class IntroduceTriples(TeacherStudentsScene):
|
||||
@ -1531,6 +1535,974 @@ class WriteGeneralFormula(GeneralExample):
|
||||
for mob in pair_mobs, triple_mobs
|
||||
])
|
||||
|
||||
class VisualizeZSquared(Scene):
|
||||
CONFIG = {
|
||||
"initial_unit_size" : 0.4,
|
||||
"final_unit_size" : 0.1,
|
||||
"plane_center" : 3*LEFT + 2*DOWN,
|
||||
"x_label_range" : range(-12, 24, 4),
|
||||
"y_label_range" : range(-4, 24, 4),
|
||||
"dot_color" : YELLOW,
|
||||
"square_color" : MAROON_B,
|
||||
"big_dot_radius" : 0.075,
|
||||
"dot_radius" : 0.05,
|
||||
}
|
||||
def construct(self):
|
||||
self.force_skipping()
|
||||
|
||||
self.add_plane()
|
||||
self.write_z_to_z_squared()
|
||||
self.draw_arrows()
|
||||
self.draw_dots()
|
||||
self.add_colored_grid()
|
||||
self.apply_transformation()
|
||||
self.show_triangles()
|
||||
self.zoom_out()
|
||||
self.show_more_triangles()
|
||||
|
||||
def add_plane(self):
|
||||
width = (SPACE_WIDTH+abs(self.plane_center[0]))/self.final_unit_size
|
||||
height = (SPACE_HEIGHT+abs(self.plane_center[1]))/self.final_unit_size
|
||||
background_plane = ComplexPlane(
|
||||
x_radius = width,
|
||||
y_radius = height,
|
||||
stroke_width = 2,
|
||||
stroke_color = BLUE_E,
|
||||
secondary_line_ratio = 0,
|
||||
)
|
||||
background_plane.axes.set_stroke(width = 4)
|
||||
|
||||
background_plane.scale(self.initial_unit_size)
|
||||
background_plane.shift(self.plane_center)
|
||||
|
||||
coordinate_labels = VGroup()
|
||||
z_list = np.append(
|
||||
self.x_label_range,
|
||||
complex(0, 1)*np.array(self.y_label_range)
|
||||
)
|
||||
for z in z_list:
|
||||
if z == 0:
|
||||
continue
|
||||
if z.imag == 0:
|
||||
tex = str(int(z.real))
|
||||
else:
|
||||
tex = str(int(z.imag)) + "i"
|
||||
label = TexMobject(tex)
|
||||
label.scale(0.75)
|
||||
label.add_background_rectangle()
|
||||
point = background_plane.number_to_point(z)
|
||||
if z.imag == 0:
|
||||
label.next_to(point, DOWN, SMALL_BUFF)
|
||||
else:
|
||||
label.next_to(point, LEFT, SMALL_BUFF)
|
||||
coordinate_labels.add(label)
|
||||
|
||||
self.add(background_plane, coordinate_labels)
|
||||
self.background_plane = background_plane
|
||||
self.coordinate_labels = coordinate_labels
|
||||
|
||||
def write_z_to_z_squared(self):
|
||||
z_to_z_squared = TexMobject("z", "\\to", "z^2")
|
||||
z_to_z_squared.highlight_by_tex("z", YELLOW)
|
||||
z_to_z_squared.highlight_by_tex("z^2", MAROON_B)
|
||||
z_to_z_squared.add_background_rectangle()
|
||||
z_to_z_squared.to_edge(UP)
|
||||
z_to_z_squared.shift(2*RIGHT)
|
||||
|
||||
self.play(Write(z_to_z_squared))
|
||||
self.dither()
|
||||
self.z_to_z_squared = z_to_z_squared
|
||||
|
||||
def draw_arrows(self):
|
||||
z_list = [
|
||||
complex(2, 1),
|
||||
complex(3, 2),
|
||||
complex(0, 1),
|
||||
complex(-1, 0),
|
||||
]
|
||||
|
||||
arrows = VGroup()
|
||||
dots = VGroup()
|
||||
for z in z_list:
|
||||
z_point, square_point, mid_point = [
|
||||
self.background_plane.number_to_point(z**p)
|
||||
for p in 1, 2, 1.5
|
||||
]
|
||||
angle = Line(mid_point, square_point).get_angle()
|
||||
angle -= Line(z_point, mid_point).get_angle()
|
||||
angle *= 2
|
||||
arrow = Arrow(
|
||||
z_point, square_point,
|
||||
path_arc = angle,
|
||||
color = WHITE,
|
||||
tip_length = 0.15,
|
||||
buff = SMALL_BUFF,
|
||||
)
|
||||
|
||||
z_dot, square_dot = [
|
||||
Dot(
|
||||
point, color = color,
|
||||
radius = self.big_dot_radius,
|
||||
)
|
||||
for point, color in [
|
||||
(z_point, self.dot_color),
|
||||
(square_point, self.square_color),
|
||||
]
|
||||
]
|
||||
z_label = TexMobject(complex_string_with_i(z))
|
||||
square_label = TexMobject(complex_string_with_i(z**2))
|
||||
for label, point in (z_label, z_point), (square_label, square_point):
|
||||
if abs(z) > 2:
|
||||
vect = RIGHT
|
||||
else:
|
||||
vect = point - self.plane_center
|
||||
vect /= np.linalg.norm(vect)
|
||||
if abs(vect[1]) < 0.1:
|
||||
vect[1] = -1
|
||||
label.next_to(point, vect)
|
||||
label.add_background_rectangle()
|
||||
|
||||
self.play(*map(FadeIn, [z_label, z_dot]))
|
||||
self.dither()
|
||||
self.play(ShowCreation(arrow))
|
||||
self.play(ReplacementTransform(
|
||||
z_dot.copy(), square_dot,
|
||||
path_arc = angle
|
||||
))
|
||||
self.play(FadeIn(square_label))
|
||||
self.dither()
|
||||
self.play(
|
||||
FadeOut(z_label),
|
||||
FadeOut(square_label),
|
||||
Animation(arrow)
|
||||
)
|
||||
|
||||
arrows.add(arrow)
|
||||
dots.add(z_dot, square_dot)
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [
|
||||
dots, arrows, self.z_to_z_squared
|
||||
]))
|
||||
|
||||
def draw_dots(self):
|
||||
min_corner, max_corner = [
|
||||
self.background_plane.point_to_coords(
|
||||
u*SPACE_WIDTH*RIGHT + u*SPACE_HEIGHT*UP
|
||||
)
|
||||
for u in -1, 1
|
||||
]
|
||||
x_min, y_min = map(int, min_corner[:2])
|
||||
x_max, y_max = map(int, max_corner[:2])
|
||||
|
||||
dots = VGroup(*[
|
||||
Dot(
|
||||
self.background_plane.coords_to_point(x, y),
|
||||
color = self.dot_color,
|
||||
radius = self.dot_radius,
|
||||
)
|
||||
for x in range(x_min, x_max+1)
|
||||
for y in range(y_min, y_max+1)
|
||||
])
|
||||
dots.sort_submobjects(lambda p : np.dot(p, UP+RIGHT))
|
||||
|
||||
self.add_foreground_mobject(self.coordinate_labels)
|
||||
self.play(LaggedStart(
|
||||
DrawBorderThenFill, dots,
|
||||
stroke_width = 3,
|
||||
stroke_color = PINK,
|
||||
run_time = 3,
|
||||
lag_ratio = 0.2
|
||||
))
|
||||
self.dither()
|
||||
|
||||
self.dots = dots
|
||||
|
||||
def add_colored_grid(self):
|
||||
color_grid = self.get_color_grid()
|
||||
|
||||
self.play(
|
||||
self.background_plane.main_lines.set_stroke, None, 1,
|
||||
LaggedStart(
|
||||
FadeIn, color_grid,
|
||||
run_time = 2
|
||||
),
|
||||
Animation(self.dots),
|
||||
)
|
||||
self.dither()
|
||||
|
||||
self.color_grid = color_grid
|
||||
|
||||
def apply_transformation(self):
|
||||
for dot in self.dots:
|
||||
dot.start_point = dot.get_center()
|
||||
def update_dot(dot, alpha):
|
||||
event = list(dot.start_point) + [alpha]
|
||||
dot.move_to(self.homotopy(*event))
|
||||
return dot
|
||||
self.play(
|
||||
Homotopy(self.homotopy, self.color_grid),
|
||||
*[
|
||||
UpdateFromAlphaFunc(dot, update_dot)
|
||||
for dot in self.dots
|
||||
],
|
||||
run_time = 3
|
||||
)
|
||||
self.dither(2)
|
||||
self.play(self.color_grid.set_stroke, None, 3)
|
||||
self.dither()
|
||||
scale_factor = self.big_dot_radius/self.dot_radius
|
||||
self.play(LaggedStart(
|
||||
ApplyMethod, self.dots,
|
||||
lambda d : (d.scale_in_place, scale_factor),
|
||||
rate_func = there_and_back,
|
||||
run_time = 3
|
||||
))
|
||||
self.dither()
|
||||
|
||||
def show_triangles(self):
|
||||
z_list = [
|
||||
complex(u, v)**2
|
||||
for u, v in (2, 1), (3, 2), (4, 1)
|
||||
]
|
||||
triangles = self.get_triangles(z_list)
|
||||
triangle = triangles[0]
|
||||
triangle.save_state()
|
||||
triangle.scale(0.01, about_point = triangle.tip)
|
||||
|
||||
self.play(triangle.restore, run_time = 2)
|
||||
self.dither(2)
|
||||
for new_triangle in triangles[1:]:
|
||||
self.play(Transform(triangle, new_triangle))
|
||||
self.dither(2)
|
||||
self.play(FadeOut(triangle))
|
||||
|
||||
def zoom_out(self):
|
||||
self.remove_foreground_mobject(self.coordinate_labels)
|
||||
movers = [
|
||||
self.background_plane,
|
||||
self.color_grid,
|
||||
self.dots,
|
||||
self.coordinate_labels,
|
||||
]
|
||||
scale_factor = self.final_unit_size/self.initial_unit_size
|
||||
for mover in movers:
|
||||
mover.generate_target()
|
||||
mover.target.scale(
|
||||
scale_factor,
|
||||
about_point = self.plane_center
|
||||
)
|
||||
for dot in self.dots.target:
|
||||
dot.scale_in_place(1./scale_factor)
|
||||
self.background_plane.target.fade()
|
||||
|
||||
self.revert_to_original_skipping_status()
|
||||
self.play(
|
||||
*map(MoveToTarget, movers),
|
||||
run_time = 3
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
def show_more_triangles(self):
|
||||
z_list = [
|
||||
complex(u, v)**2
|
||||
for u in range(4, 7)
|
||||
for v in range(1, u)
|
||||
]
|
||||
triangles = self.get_triangles(z_list)
|
||||
triangle = triangles[0]
|
||||
|
||||
self.play(FadeOut(triangle))
|
||||
self.dither(2)
|
||||
for new_triangle in triangles[1:]:
|
||||
self.play(Transform(triangle, new_triangle))
|
||||
self.dither(2)
|
||||
|
||||
###
|
||||
|
||||
def get_color_grid(self):
|
||||
width = (SPACE_WIDTH+abs(self.plane_center[0]))/self.initial_unit_size
|
||||
height = (SPACE_HEIGHT+abs(self.plane_center[1]))/self.initial_unit_size
|
||||
color_grid = ComplexPlane(
|
||||
x_radius = width,
|
||||
y_radius = int(height),
|
||||
secondary_line_ratio = 0,
|
||||
stroke_width = 2,
|
||||
)
|
||||
color_grid.main_lines.gradient_highlight(
|
||||
*[GREEN, RED, MAROON_B, TEAL]*2
|
||||
)
|
||||
color_grid.remove(color_grid.axes[0])
|
||||
for line in color_grid.family_members_with_points():
|
||||
center = line.get_center()
|
||||
if center[0] <= 0 and abs(center[1]) < 0.01:
|
||||
line_copy = line.copy()
|
||||
line.scale(0.499, about_point = line.get_start())
|
||||
line_copy.scale(0.499, about_point = line_copy.get_end())
|
||||
color_grid.add(line_copy)
|
||||
color_grid.scale(self.initial_unit_size)
|
||||
color_grid.shift(self.plane_center)
|
||||
color_grid.prepare_for_nonlinear_transform()
|
||||
return color_grid
|
||||
|
||||
def get_triangles(self, z_list):
|
||||
triangles = VGroup()
|
||||
for z in z_list:
|
||||
point = self.background_plane.number_to_point(z)
|
||||
line = Line(self.plane_center, point)
|
||||
triangle = Polygon(
|
||||
ORIGIN, RIGHT, RIGHT+UP,
|
||||
stroke_color = BLUE,
|
||||
stroke_width = 2,
|
||||
fill_color = BLUE,
|
||||
fill_opacity = 0.5,
|
||||
)
|
||||
triangle.replace(line, stretch = True)
|
||||
a = int(z.real)
|
||||
b = int(z.imag)
|
||||
c = int(abs(z))
|
||||
a_label, b_label, c_label = labels = [
|
||||
TexMobject(str(num))
|
||||
for num in a, b, c
|
||||
]
|
||||
for label in b_label, c_label:
|
||||
label.add_background_rectangle()
|
||||
a_label.next_to(triangle.get_bottom(), UP, SMALL_BUFF)
|
||||
b_label.next_to(triangle, RIGHT, SMALL_BUFF)
|
||||
c_label.next_to(line.get_center(), UP+LEFT, SMALL_BUFF)
|
||||
triangle.add(*labels)
|
||||
triangle.tip = point
|
||||
triangles.add(triangle)
|
||||
return triangles
|
||||
|
||||
def homotopy(self, x, y, z, t):
|
||||
z_complex = self.background_plane.point_to_number(np.array([x, y, z]))
|
||||
result = z_complex**(1+t)
|
||||
return self.background_plane.number_to_point(result)
|
||||
|
||||
class AskAboutHittingAllPoints(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Does this hit \\\\ all pythagorean triples?",
|
||||
target_mode = "raise_left_hand"
|
||||
)
|
||||
self.dither()
|
||||
self.teacher_says("No", target_mode = "sad")
|
||||
self.change_student_modes(*["hesitant"]*3)
|
||||
self.dither()
|
||||
|
||||
class PointsWeMiss(VisualizeZSquared):
|
||||
CONFIG = {
|
||||
"final_unit_size" : 0.4,
|
||||
"plane_center" : 2*LEFT + 2*DOWN,
|
||||
"dot_x_range" : range(-5, 6),
|
||||
"dot_y_range" : range(-4, 4),
|
||||
}
|
||||
def construct(self):
|
||||
self.add_plane()
|
||||
self.add_transformed_color_grid()
|
||||
self.add_dots()
|
||||
self.show_missing_point()
|
||||
self.show_second_missing_point()
|
||||
self.mention_one_half_rule()
|
||||
|
||||
def add_transformed_color_grid(self):
|
||||
color_grid = self.get_color_grid()
|
||||
func = lambda p : self.homotopy(p[0], p[1], p[1], 1)
|
||||
color_grid.apply_function(func)
|
||||
color_grid.set_stroke(width = 4)
|
||||
self.add(color_grid, self.coordinate_labels)
|
||||
self.color_grid = color_grid
|
||||
|
||||
def add_dots(self):
|
||||
z_list = [
|
||||
complex(x, y)**2
|
||||
for x in self.dot_x_range
|
||||
for y in self.dot_y_range
|
||||
]
|
||||
dots = VGroup(*[
|
||||
Dot(
|
||||
self.background_plane.number_to_point(z),
|
||||
color = self.dot_color,
|
||||
radius = self.big_dot_radius,
|
||||
)
|
||||
for z in z_list
|
||||
])
|
||||
dots.sort_submobjects(np.linalg.norm)
|
||||
self.add(dots)
|
||||
self.dots = dots
|
||||
|
||||
def show_missing_point(self):
|
||||
z_list = [complex(6, 8), complex(9, 12), complex(3, 4)]
|
||||
points = map(
|
||||
self.background_plane.number_to_point,
|
||||
z_list
|
||||
)
|
||||
dots = VGroup(*map(Dot, points))
|
||||
for dot in dots[:2]:
|
||||
dot.set_stroke(RED, 4)
|
||||
dot.set_fill(opacity = 0)
|
||||
labels = VGroup(*[
|
||||
TexMobject(complex_string_with_i(z))
|
||||
for z in z_list
|
||||
])
|
||||
labels.highlight(RED)
|
||||
labels[2].highlight(GREEN)
|
||||
rhss = VGroup()
|
||||
for label, dot in zip(labels, dots):
|
||||
label.add_background_rectangle()
|
||||
label.next_to(dot, UP+RIGHT, SMALL_BUFF)
|
||||
if label is labels[-1]:
|
||||
rhs = TexMobject("= (2+i)^2")
|
||||
else:
|
||||
rhs = TexMobject("\\ne (u+vi)^2")
|
||||
rhs.add_background_rectangle()
|
||||
rhs.next_to(label, RIGHT)
|
||||
rhss.add(rhs)
|
||||
triangles = self.get_triangles(z_list)
|
||||
|
||||
self.play(FocusOn(dots[0]))
|
||||
self.play(ShowCreation(dots[0]))
|
||||
self.play(Write(labels[0]))
|
||||
self.dither()
|
||||
self.play(FadeIn(triangles[0]))
|
||||
self.dither(2)
|
||||
self.play(Write(rhss[0]))
|
||||
self.dither(2)
|
||||
groups = triangles, dots, labels, rhss
|
||||
for i in 1, 2:
|
||||
self.play(*[
|
||||
Transform(group[0], group[i])
|
||||
for group in groups
|
||||
])
|
||||
self.dither(3)
|
||||
self.play(*[
|
||||
FadeOut(group[0])
|
||||
for group in groups
|
||||
])
|
||||
|
||||
def show_second_missing_point(self):
|
||||
z_list = [complex(4, 3), complex(8, 6)]
|
||||
points = map(
|
||||
self.background_plane.number_to_point,
|
||||
z_list
|
||||
)
|
||||
dots = VGroup(*map(Dot, points))
|
||||
dots[0].set_stroke(RED, 4)
|
||||
dots[0].set_fill(opacity = 0)
|
||||
labels = VGroup(*[
|
||||
TexMobject(complex_string_with_i(z))
|
||||
for z in z_list
|
||||
])
|
||||
labels[0].highlight(RED)
|
||||
labels[1].highlight(GREEN)
|
||||
rhss = VGroup()
|
||||
for label, dot in zip(labels, dots):
|
||||
label.add_background_rectangle()
|
||||
label.next_to(dot, UP+RIGHT, SMALL_BUFF)
|
||||
if label is labels[-1]:
|
||||
rhs = TexMobject("= (3+i)^2")
|
||||
else:
|
||||
rhs = TexMobject("\\ne (u+vi)^2")
|
||||
rhs.add_background_rectangle()
|
||||
rhs.next_to(label, RIGHT)
|
||||
rhss.add(rhs)
|
||||
triangles = self.get_triangles(z_list)
|
||||
groups = [dots, labels, rhss, triangles]
|
||||
for group in groups:
|
||||
group[0].save_state()
|
||||
|
||||
self.play(ShowCreation(dots[0]))
|
||||
self.play(Write(VGroup(labels[0], rhss[0])))
|
||||
self.play(FadeIn(triangles[0]))
|
||||
self.dither(3)
|
||||
self.play(*[Transform(*group) for group in groups])
|
||||
self.dither(3)
|
||||
self.play(*[group[0].restore for group in groups])
|
||||
self.dither(2)
|
||||
|
||||
def mention_one_half_rule(self):
|
||||
morty = Mortimer()
|
||||
morty.flip()
|
||||
morty.to_corner(DOWN+LEFT)
|
||||
|
||||
self.play(FadeIn(morty))
|
||||
self.play(PiCreatureSays(
|
||||
morty,
|
||||
"Never need to scale \\\\ by less than $\\frac{1}{2}$"
|
||||
))
|
||||
self.play(Blink(morty))
|
||||
self.dither(2)
|
||||
|
||||
class DrawRadialLines(PointsWeMiss):
|
||||
CONFIG = {
|
||||
"final_unit_size" : 0.2,
|
||||
"dot_x_range" : range(-4, 10),
|
||||
"dot_y_range" : range(-4, 10),
|
||||
"x_label_range" : range(-12, 40, 4),
|
||||
"y_label_range" : range(-4, 32, 4),
|
||||
"big_dot_radius" : 0.05,
|
||||
}
|
||||
def construct(self):
|
||||
self.add_plane()
|
||||
self.add_transformed_color_grid()
|
||||
self.resize_plane()
|
||||
self.add_dots()
|
||||
self.create_lines()
|
||||
self.show_single_line()
|
||||
self.show_all_lines()
|
||||
self.show_triangles()
|
||||
|
||||
def resize_plane(self):
|
||||
everything = VGroup(*self.get_top_level_mobjects())
|
||||
everything.scale(
|
||||
self.final_unit_size/self.initial_unit_size,
|
||||
about_point = self.plane_center
|
||||
)
|
||||
self.background_plane.set_stroke(width = 1)
|
||||
|
||||
def create_lines(self):
|
||||
coord_strings = set([])
|
||||
reduced_coords_yet_to_be_reached = set([])
|
||||
for dot in self.dots:
|
||||
point = dot.get_center()
|
||||
float_coords = self.background_plane.point_to_coords(point)
|
||||
coords = np.round(float_coords).astype('int')
|
||||
gcd = fractions.gcd(*coords)
|
||||
reduced_coords = coords/abs(gcd)
|
||||
|
||||
if np.all(coords == [3, 4]):
|
||||
first_dot = dot
|
||||
|
||||
dot.coords = coords
|
||||
dot.reduced_coords = reduced_coords
|
||||
coord_strings.add(str(coords))
|
||||
reduced_coords_yet_to_be_reached.add(str(reduced_coords))
|
||||
lines = VGroup()
|
||||
for dot in [first_dot] + list(self.dots):
|
||||
rc_str = str(dot.reduced_coords)
|
||||
if rc_str not in reduced_coords_yet_to_be_reached:
|
||||
continue
|
||||
reduced_coords_yet_to_be_reached.remove(rc_str)
|
||||
new_dots = VGroup()
|
||||
for k in range(50):
|
||||
new_coords = k*dot.reduced_coords
|
||||
if str(new_coords) in coord_strings:
|
||||
continue
|
||||
coord_strings.add(str(new_coords))
|
||||
point = self.background_plane.coords_to_point(*new_coords)
|
||||
if abs(point[0]) > SPACE_WIDTH or abs(point[1]) > SPACE_HEIGHT:
|
||||
continue
|
||||
new_dot = Dot(
|
||||
point, color = GREEN,
|
||||
radius = self.big_dot_radius
|
||||
)
|
||||
new_dots.add(new_dot)
|
||||
line = Line(self.plane_center, dot.get_center())
|
||||
line.scale(
|
||||
2*SPACE_WIDTH/line.get_length(),
|
||||
about_point = self.plane_center
|
||||
)
|
||||
line.set_stroke(width = 1)
|
||||
line.seed_dot = dot.copy()
|
||||
line.new_dots = new_dots
|
||||
lines.add(line)
|
||||
self.lines = lines
|
||||
|
||||
def show_single_line(self):
|
||||
line = self.lines[0]
|
||||
dot = line.seed_dot
|
||||
|
||||
self.play(
|
||||
dot.scale_in_place, 2,
|
||||
dot.highlight, RED
|
||||
)
|
||||
self.play(ReplacementTransform(dot, line))
|
||||
self.dither()
|
||||
self.play(LaggedStart(
|
||||
DrawBorderThenFill, line.new_dots,
|
||||
stroke_width = 4,
|
||||
stroke_color = PINK,
|
||||
run_time = 3,
|
||||
))
|
||||
self.dither()
|
||||
|
||||
def show_all_lines(self):
|
||||
seed_dots = VGroup(*[line.seed_dot for line in self.lines])
|
||||
new_dots = VGroup(*[line.new_dots for line in self.lines])
|
||||
for dot in seed_dots:
|
||||
dot.generate_target()
|
||||
dot.target.scale_in_place(1.5)
|
||||
dot.target.highlight(RED)
|
||||
|
||||
self.play(LaggedStart(
|
||||
MoveToTarget, seed_dots,
|
||||
run_time = 2
|
||||
))
|
||||
self.play(ReplacementTransform(
|
||||
seed_dots, self.lines,
|
||||
run_time = 3,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.play(LaggedStart(
|
||||
DrawBorderThenFill, new_dots,
|
||||
stroke_width = 4,
|
||||
stroke_color = PINK,
|
||||
run_time = 3,
|
||||
))
|
||||
self.dither()
|
||||
|
||||
self.new_dots = new_dots
|
||||
|
||||
def show_triangles(self):
|
||||
z_list = [
|
||||
complex(9, 12),
|
||||
complex(7, 24),
|
||||
complex(8, 15),
|
||||
complex(21, 20),
|
||||
complex(36, 15),
|
||||
]
|
||||
triangles = self.get_triangles(z_list)
|
||||
triangle = triangles[0]
|
||||
|
||||
self.play(FadeIn(triangle))
|
||||
self.dither(2)
|
||||
for new_triangle in triangles[1:]:
|
||||
self.play(Transform(triangle, new_triangle))
|
||||
self.dither(2)
|
||||
|
||||
class RationalPointsOnUnitCircle(DrawRadialLines):
|
||||
CONFIG = {
|
||||
"initial_unit_size" : 1.2,
|
||||
"final_unit_size" : 0.4,
|
||||
"plane_center" : 1.5*DOWN
|
||||
}
|
||||
def construct(self):
|
||||
self.add_plane()
|
||||
self.show_rational_points_on_unit_circle()
|
||||
self.divide_by_c_squared()
|
||||
self.from_rational_point_to_triple()
|
||||
|
||||
def add_plane(self):
|
||||
added_x_coords = range(-4, 6, 2)
|
||||
added_y_coords = range(-2, 4, 2)
|
||||
self.x_label_range += added_x_coords
|
||||
self.y_label_range += added_y_coords
|
||||
DrawRadialLines.add_plane(self)
|
||||
|
||||
def show_rational_points_on_unit_circle(self):
|
||||
circle = self.get_unit_circle()
|
||||
|
||||
coord_list = [
|
||||
(12, 5),
|
||||
(8, 15),
|
||||
(7, 24),
|
||||
(3, 4),
|
||||
]
|
||||
groups = VGroup()
|
||||
for x, y in coord_list:
|
||||
norm = np.sqrt(x**2 + y**2)
|
||||
point = self.background_plane.coords_to_point(
|
||||
x/norm, y/norm
|
||||
)
|
||||
dot = Dot(point, color = YELLOW)
|
||||
line = Line(self.plane_center, point)
|
||||
line.highlight(dot.get_color())
|
||||
label = TexMobject(
|
||||
"{"+str(x), "\\over", str(int(norm))+"}",
|
||||
"+",
|
||||
"{"+str(y), "\\over", str(int(norm))+"}",
|
||||
"i"
|
||||
)
|
||||
label.next_to(dot, UP+RIGHT, buff = 0)
|
||||
label.add_background_rectangle()
|
||||
|
||||
group = VGroup(line, dot, label)
|
||||
group.coords = (x, y)
|
||||
groups.add(group)
|
||||
group = groups[0].copy()
|
||||
|
||||
self.add(circle, self.coordinate_labels)
|
||||
self.play(FadeIn(group))
|
||||
self.dither()
|
||||
for new_group in groups[1:]:
|
||||
self.play(Transform(group, new_group))
|
||||
self.dither()
|
||||
|
||||
self.curr_example_point_group = group
|
||||
self.next_rational_point_example = groups[0]
|
||||
self.unit_circle = circle
|
||||
|
||||
def divide_by_c_squared(self):
|
||||
top_line = TexMobject(
|
||||
"a", "^2", "+", "b", "^2", "=", "c", "^2 \\phantom{1}"
|
||||
)
|
||||
top_line.shift(SPACE_WIDTH*RIGHT/2)
|
||||
top_line.to_corner(UP + LEFT)
|
||||
top_line.shift(RIGHT)
|
||||
top_rect = BackgroundRectangle(top_line)
|
||||
|
||||
second_line = TexMobject(
|
||||
"\\left(", "{a", "\\over", "c}", "\\right)", "^2",
|
||||
"+",
|
||||
"\\left(", "{b", "\\over", "c}", "\\right)", "^2",
|
||||
"=", "1"
|
||||
)
|
||||
second_line.move_to(top_line, UP)
|
||||
second_line.shift_onto_screen()
|
||||
second_rect = BackgroundRectangle(second_line)
|
||||
|
||||
circle_label = TextMobject(
|
||||
"All $x+yi$ where \\\\",
|
||||
"$x^2 + y^2 = 1$"
|
||||
)
|
||||
circle_label.next_to(second_line, DOWN, MED_LARGE_BUFF)
|
||||
circle_label.shift_onto_screen()
|
||||
circle_label.highlight_by_tex("x^2", GREEN)
|
||||
circle_label.add_background_rectangle()
|
||||
circle_arrow = Arrow(
|
||||
circle_label.get_bottom(),
|
||||
self.unit_circle.point_from_proportion(0.45),
|
||||
color = GREEN
|
||||
)
|
||||
|
||||
self.play(FadeIn(top_rect), FadeIn(top_line))
|
||||
self.dither()
|
||||
self.play(*[
|
||||
ReplacementTransform(top_rect, second_rect)
|
||||
] + [
|
||||
ReplacementTransform(
|
||||
top_line.get_parts_by_tex(tex, substring = False),
|
||||
second_line.get_parts_by_tex(tex),
|
||||
run_time = 2,
|
||||
path_arc = -np.pi/3
|
||||
)
|
||||
for tex in "a", "b", "c", "^2", "+", "="
|
||||
] + [
|
||||
ReplacementTransform(
|
||||
top_line.get_parts_by_tex("1"),
|
||||
second_line.get_parts_by_tex("1"),
|
||||
run_time = 2
|
||||
)
|
||||
] + [
|
||||
Write(
|
||||
second_line.get_parts_by_tex(tex),
|
||||
run_time = 2,
|
||||
rate_func = squish_rate_func(smooth, 0, 0.5)
|
||||
)
|
||||
for tex in "(", ")", "over",
|
||||
])
|
||||
self.dither(2)
|
||||
self.play(Write(circle_label))
|
||||
self.play(ShowCreation(circle_arrow))
|
||||
self.dither(2)
|
||||
self.play(FadeOut(circle_arrow))
|
||||
|
||||
self.algebra = VGroup(
|
||||
second_rect, second_line, circle_label,
|
||||
)
|
||||
|
||||
def from_rational_point_to_triple(self):
|
||||
rational_point_group = self.next_rational_point_example
|
||||
scale_factor = self.final_unit_size/self.initial_unit_size
|
||||
|
||||
self.play(ReplacementTransform(
|
||||
self.curr_example_point_group,
|
||||
rational_point_group
|
||||
))
|
||||
self.dither(2)
|
||||
self.play(*[
|
||||
ApplyMethod(
|
||||
mob.scale_about_point,
|
||||
scale_factor,
|
||||
self.plane_center
|
||||
)
|
||||
for mob in [
|
||||
self.background_plane,
|
||||
self.coordinate_labels,
|
||||
self.unit_circle,
|
||||
rational_point_group,
|
||||
]
|
||||
] + [
|
||||
Animation(self.algebra),
|
||||
])
|
||||
|
||||
#mimic_group
|
||||
point = self.background_plane.coords_to_point(
|
||||
*rational_point_group.coords
|
||||
)
|
||||
dot = Dot(point, color = YELLOW)
|
||||
line = Line(self.plane_center, point)
|
||||
line.highlight(dot.get_color())
|
||||
x, y = rational_point_group.coords
|
||||
label = TexMobject(str(x), "+", str(y), "i")
|
||||
label.next_to(dot, UP+RIGHT, buff = 0)
|
||||
label.add_background_rectangle()
|
||||
integer_point_group = VGroup(line, dot, label)
|
||||
distance_label = TexMobject(
|
||||
str(int(np.sqrt(x**2 + y**2)))
|
||||
)
|
||||
distance_label.add_background_rectangle()
|
||||
distance_label.next_to(line.get_center(), UP+LEFT, SMALL_BUFF)
|
||||
|
||||
self.play(ReplacementTransform(
|
||||
rational_point_group,
|
||||
integer_point_group
|
||||
))
|
||||
self.play(Write(distance_label))
|
||||
self.dither(2)
|
||||
|
||||
###
|
||||
|
||||
def get_unit_circle(self):
|
||||
template_line = Line(*[
|
||||
self.background_plane.number_to_point(z)
|
||||
for z in -1, 1
|
||||
])
|
||||
circle = Circle(color = GREEN)
|
||||
circle.replace(template_line, dim_to_match = 0)
|
||||
return circle
|
||||
|
||||
class ProjectPointsOntoUnitCircle(DrawRadialLines):
|
||||
def construct(self):
|
||||
###
|
||||
self.force_skipping()
|
||||
self.add_plane()
|
||||
self.add_transformed_color_grid()
|
||||
self.resize_plane()
|
||||
self.add_dots()
|
||||
self.create_lines()
|
||||
self.show_all_lines()
|
||||
self.revert_to_original_skipping_status()
|
||||
###
|
||||
|
||||
self.add_unit_circle()
|
||||
self.project_all_dots()
|
||||
self.zoom_in()
|
||||
self.draw_infinitely_many_lines()
|
||||
|
||||
|
||||
def add_unit_circle(self):
|
||||
template_line = Line(*[
|
||||
self.background_plane.number_to_point(n)
|
||||
for n in -1, 1
|
||||
])
|
||||
circle = Circle(color = BLUE)
|
||||
circle.replace(template_line, dim_to_match = 0)
|
||||
|
||||
self.play(ShowCreation(circle))
|
||||
self.unit_circle = circle
|
||||
|
||||
def project_all_dots(self):
|
||||
dots = self.dots
|
||||
dots.add(*self.new_dots)
|
||||
dots.sort_submobjects(
|
||||
lambda p : np.linalg.norm(p - self.plane_center)
|
||||
)
|
||||
unit_length = self.unit_circle.get_width()/2.0
|
||||
for dot in dots:
|
||||
dot.generate_target()
|
||||
point = dot.get_center()
|
||||
vect = point-self.plane_center
|
||||
if np.round(vect[0], 3) == 0 and abs(vect[1]) > 2*unit_length:
|
||||
dot.target.set_fill(opacity = 0)
|
||||
continue
|
||||
distance = np.linalg.norm(vect)
|
||||
dot.target.scale(
|
||||
unit_length/distance,
|
||||
about_point = self.plane_center
|
||||
)
|
||||
dot.target.scale_to_fit_width(0.01)
|
||||
|
||||
self.play(LaggedStart(
|
||||
MoveToTarget, dots,
|
||||
run_time = 3,
|
||||
lag_ratio = 0.2
|
||||
))
|
||||
|
||||
def zoom_in(self):
|
||||
target_height = 5.0
|
||||
scale_factor = target_height / self.unit_circle.get_height()
|
||||
group = VGroup(
|
||||
self.background_plane, self.coordinate_labels,
|
||||
self.color_grid,
|
||||
self.lines, self.unit_circle,
|
||||
self.dots,
|
||||
)
|
||||
|
||||
self.play(
|
||||
group.shift, -self.plane_center,
|
||||
group.scale, scale_factor,
|
||||
run_time = 2
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
def draw_infinitely_many_lines(self):
|
||||
lines = VGroup(*[
|
||||
Line(ORIGIN, 2*SPACE_WIDTH*vect)
|
||||
for vect in compass_directions(1000)
|
||||
])
|
||||
|
||||
self.play(LaggedStart(
|
||||
ShowCreation, lines,
|
||||
run_time = 3
|
||||
))
|
||||
self.play(FadeOut(lines))
|
||||
self.dither()
|
||||
|
||||
class ProofTime(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says("Proof time!", target_mode = "hooray")
|
||||
self.change_student_modes(*["hooray"]*3)
|
||||
self.dither(2)
|
||||
|
||||
class FinalProof(RationalPointsOnUnitCircle):
|
||||
def construct(self):
|
||||
self.force_skipping()
|
||||
|
||||
self.add_plane()
|
||||
self.draw_line_from_example_point()
|
||||
self.show_slope_is_rational()
|
||||
self.show_all_rational_slopes()
|
||||
self.square_example_point()
|
||||
self.show_circle_geometry()
|
||||
self.show_same_slope()
|
||||
self.write_v_over_u_slope()
|
||||
|
||||
def draw_line_from_example_point(self):
|
||||
coords = (5./13, 12/13.)
|
||||
point = self.background_plane.coords_to_point(*coords)
|
||||
dot = Dot(point, color = YELLOW)
|
||||
label = TexMobject(
|
||||
"\\frac{a}{c} + \\frac{b}{c}i"
|
||||
)
|
||||
label.add_background_rectangle()
|
||||
label.next_to(dot, UP+RIGHT, buff = 0)
|
||||
|
||||
|
||||
|
||||
def show_slope_is_rational(self):
|
||||
pass
|
||||
|
||||
def show_all_rational_slopes(self):
|
||||
pass
|
||||
|
||||
def square_example_point(self):
|
||||
pass
|
||||
|
||||
def show_circle_geometry(self):
|
||||
pass
|
||||
|
||||
def show_same_slope(self):
|
||||
pass
|
||||
|
||||
def write_v_over_u_slope(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user