diff --git a/triples.py b/triples.py index 981defe2..be876a5f 100644 --- a/triples.py +++ b/triples.py @@ -33,222 +33,177 @@ A_COLOR = BLUE B_COLOR = GREEN C_COLOR = YELLOW SIDE_COLORS = [A_COLOR, B_COLOR, C_COLOR] -U_COLOR = MAROON_B +U_COLOR = GREEN V_COLOR = RED #revert_to_original_skipping_status +def complex_string_with_i(z): + return complex_string(z).replace("j", "i") + class IntroduceTriples(TeacherStudentsScene): def construct(self): title = TexMobject("a", "^2", "+", "b", "^2", "=", "c", "^2") for color, char in zip(SIDE_COLORS, "abc"): title.highlight_by_tex(char, color) - title.to_edge(UP) + title.to_corner(UP + RIGHT) triples = [ (3, 4, 5), (5, 12, 13), (8, 15, 17), ] - triangles = VGroup(*[ - Polygon(ORIGIN, a*RIGHT, a*RIGHT+b*UP) - for a, b, c in triples - ]) - for triple, triangle in zip(triples, triangles): - a, b, c = map(TexMobject, map(str, triple)) - for color, mob in zip(SIDE_COLORS, [a, b, c]): - mob.scale(0.7) - mob.highlight(color) - triangle.scale(0.25) - triangle.highlight(WHITE) - elbow = VGroup( - Line(UP, UP+LEFT), - Line(UP+LEFT, LEFT) - ) - elbow.scale_to_fit_width(0.15) - elbow.move_to(triangle, DOWN+RIGHT) - a.next_to(triangle, DOWN, SMALL_BUFF) - b.next_to(triangle, RIGHT, SMALL_BUFF) - c.next_to(triangle.get_center(), UP+LEFT, SMALL_BUFF) - triangle.add(elbow, a, b, c) - triangles.arrange_submobjects( - RIGHT, buff = MED_LARGE_BUFF, aligned_edge = DOWN - ) - triangles.next_to(self.get_pi_creatures(), UP) - triangles.shift_onto_screen() self.add(title) + for a, b, c in triples: + triangle = Polygon( + ORIGIN, a*RIGHT, a*RIGHT+b*UP, + stroke_width = 0, + fill_color = WHITE, + fill_opacity = 0.5 + ) + hyp_line = Line(ORIGIN, a*RIGHT+b*UP) + elbow = VMobject() + elbow.set_points_as_corners([LEFT, LEFT+UP, UP]) + elbow.scale_to_fit_width(0.2*triangle.get_width()) + elbow.move_to(triangle, DOWN+RIGHT) + triangle.add(elbow) + + square = Square(side_length = 1) + square_groups = VGroup() + for n, color in zip([a, b, c], SIDE_COLORS): + square_group = VGroup(*[ + square.copy().shift(x*RIGHT + y*UP) + for x in range(n) + for y in range(n) + ]) + square_group.set_stroke(color, width = 3) + square_group.set_fill(color, opacity = 0.5) + square_groups.add(square_group) + a_square, b_square, c_square = square_groups + a_square.move_to(triangle.get_bottom(), UP) + b_square.move_to(triangle.get_right(), LEFT) + c_square.move_to(hyp_line.get_center(), DOWN) + c_square.rotate( + hyp_line.get_angle(), + about_point = hyp_line.get_center() + ) + if c in [5, 13]: + if c == 5: + keys = range(0, 5, 2) + elif c == 13: + keys = range(0, 13, 3) + i_list = filter( + lambda i : (i%c) in keys and (i//c) in keys, + range(c**2) + ) + else: + i_list = range(a**2) + not_i_list = filter( + lambda i : i not in i_list, + range(c**2), + ) + c_square_parts = [ + VGroup(*[c_square[i] for i in i_list]), + VGroup(*[c_square[i] for i in not_i_list]), + ] + full_group = VGroup(triangle, square_groups) + full_group.scale_to_fit_height(4) + full_group.center() + full_group.to_edge(UP) + + equation = TexMobject( + str(a), "^2", "+", str(b), "^2", "=", str(c), "^2" + ) + for num, color in zip([a, b, c], SIDE_COLORS): + equation.highlight_by_tex(str(num), color) + equation.next_to(title, DOWN, MED_LARGE_BUFF) + equation.shift_onto_screen() + + self.play( + FadeIn(triangle), + self.teacher.change_mode, "raise_right_hand" + ) + self.play(LaggedStart(FadeIn, a_square)) + self.change_student_modes( + *["pondering"]*3, + look_at_arg = triangle, + added_anims = [LaggedStart(FadeIn, b_square)] + ) + self.play(self.teacher.change_mode, "happy") + for start, target in zip([a_square, b_square], c_square_parts): + mover = start.copy().set_fill(opacity = 0) + target.highlight(start.get_color()) + self.play(ReplacementTransform( + mover, target, + run_time = 2, + path_arc = np.pi/2 + )) + self.play(Write(equation)) + self.play(c_square.highlight, C_COLOR) + self.dither() + self.play(*map(FadeOut, [full_group, equation])) + +class CompareToFermatsLastTheorem(TeacherStudentsScene): + def construct(self): + expressions = [ + TexMobject( + "a", "^%d"%d, "+", "b", "^%d"%d, + "=", "c", "^%d"%d + ) + for d in range(2, 9) + ] + for expression in expressions: + for char, color in zip("abc", SIDE_COLORS): + expression.highlight_by_tex(char, color) + expression.next_to(self.get_pi_creatures(), UP, buff = 1.3) + square_expression = expressions[0] + low_expression = expressions[1] + square_expression.to_edge(UP, buff = 1.3) + top_brace = Brace(square_expression, UP, buff = SMALL_BUFF) + top_text = top_brace.get_text( + "Abundant integer solutions", buff = SMALL_BUFF + ) + low_brace = Brace(low_expression, DOWN, buff = SMALL_BUFF) + low_text = low_brace.get_text( + "No integer solutions", buff = SMALL_BUFF + ) + low_text.highlight(RED) + + self.add(square_expression, top_brace, top_text) self.play( - Write(triangles[0], run_time = 2), - self.teacher.change, "raise_right_hand" + ReplacementTransform( + square_expression.copy(), + low_expression + ), + self.teacher.change_mode, "raise_right_hand", + *[ + ApplyMethod(pi.change, "confused", expressions[1]) + for pi in self.get_students() + ] + ) + self.dither() + self.play(Transform(low_expression, expressions[2])) + self.play( + GrowFromCenter(low_brace), + FadeIn(low_text), ) self.change_student_modes( - *["pondering"]*3, - look_at_arg = triangles[0] + "sassy", "angry", "erm", + look_at_arg = low_expression, + added_anims = [Transform(low_expression, expressions[3])] ) - for triangle in triangles[1:]: - self.play(Write(triangle, run_time = 2)) + for expression in expressions[4:]: + self.play(Transform(low_expression, expression)) self.dither() - self.dither(2) -class LastVideoWrapper(Scene): +class WritePythagoreanTriple(Scene): def construct(self): - title = TextMobject("Pi hiding in prime regularities") - title.to_edge(UP) - screen_rect = ScreenRectangle(height = 6) - screen_rect.next_to(title, DOWN) - - self.play(ShowCreation(screen_rect)) - self.play(Write(title)) - self.dither() - -class PythagoreanProof(Scene): - def construct(self): - self.add_title() - self.show_proof() - - def add_title(self): - title = TexMobject("a^2", "+", "b^2", "=", "c^2") - for color, char in zip(SIDE_COLORS, "abc"): - title.highlight_by_tex(char, color) - title.to_edge(UP) - self.add(title) - self.title = title - - def show_proof(self): - triangle = Polygon( - ORIGIN, 5*RIGHT, 5*RIGHT+12*UP, - stroke_color = WHITE, - stroke_width = 2, - fill_color = WHITE, - fill_opacity = 0.5 - ) - triangle.scale_to_fit_height(3) - triangle.center() - triangle_copy = triangle.copy() - squares = self.get_abc_squares(triangle) - a_square, b_square, c_square = squares - - - self.add(triangle, triangle_copy) - self.play(*map(DrawBorderThenFill, squares)) - self.add_labels_to_squares(squares) - self.dither() - self.play( - VGroup(triangle, c_square).move_to, - 4*LEFT+2*DOWN, DOWN, - VGroup(triangle_copy, a_square, b_square).move_to, - 4*RIGHT+2*DOWN, DOWN, - ) - self.dither() - self.add_new_triangles( - triangle, - self.get_added_triangles_to_c_square(triangle, c_square) - ) - self.dither() - self.add_new_triangles( - triangle_copy, - self.get_added_triangles_to_ab_squares(triangle_copy, a_square) - ) - self.dither() - - big_squares = VGroup(*map( - self.get_big_square, - [triangle, triangle_copy] - )) - negative_space_words = TextMobject( - "Same negative \\\\ space" - ) - negative_space_words.scale(0.75) - negative_space_words.shift(UP) - double_arrow = DoubleArrow(LEFT, RIGHT) - double_arrow.next_to(negative_space_words, DOWN) - - self.play( - FadeIn(big_squares), - Write(negative_space_words), - ShowCreation(double_arrow), - *map(FadeOut, squares) - ) + words = TextMobject("``Pythagorean triple''") + words.scale_to_fit_width(2*SPACE_WIDTH - LARGE_BUFF) + words.to_corner(DOWN+LEFT) + self.play(Write(words)) self.dither(2) - self.play(*it.chain( - map(FadeIn, squares), - map(Animation, big_squares), - )) - self.dither(2) - - def add_labels_to_squares(self, squares): - labels = VGroup(*[ - self.title.get_part_by_tex(tex).copy() - for tex in "a^2", "b^2", "c^2" - ]) - for label, square in zip(labels, squares): - label.generate_target() - label.target.scale(0.7) - label.target.move_to(square) - square.add(label) - - self.play(LaggedStart(MoveToTarget, labels)) - - def add_new_triangles(self, triangle, added_triangles): - self.play(ReplacementTransform( - VGroup(triangle.copy().set_fill(opacity = 0)), - added_triangles, - run_time = 2, - )) - triangle.added_triangles = added_triangles - - def get_big_square(self, triangle): - square = Square(stroke_color = RED) - square.replace( - VGroup(triangle, triangle.added_triangles), - stretch = True - ) - square.scale_in_place(1.01) - return square - - ##### - - def get_abc_squares(self, triangle): - a_square, b_square, c_square = squares = [ - Square( - stroke_color = color, - fill_color = color, - fill_opacity = 0.5, - ) - for color in SIDE_COLORS - ] - a_square.scale_to_fit_width(triangle.get_width()) - a_square.move_to(triangle.get_bottom(), UP) - b_square.scale_to_fit_height(triangle.get_height()) - b_square.move_to(triangle.get_right(), LEFT) - hyp_line = Line( - triangle.get_corner(UP+RIGHT), - triangle.get_corner(DOWN+LEFT), - ) - c_square.scale_to_fit_width(hyp_line.get_length()) - c_square.move_to(hyp_line.get_center(), UP) - c_square.rotate( - hyp_line.get_angle(), - about_point = hyp_line.get_center() - ) - - return a_square, b_square, c_square - - def get_added_triangles_to_c_square(self, triangle, c_square): - return VGroup(*[ - triangle.copy().rotate(i*np.pi/2, about_point = c_square.get_center()) - for i in range(1, 4) - ]) - - def get_added_triangles_to_ab_squares(self, triangle, a_square): - t1 = triangle.copy() - t1.rotate_in_place(np.pi) - group = VGroup(triangle, t1).copy() - group.rotate(-np.pi/2) - group.move_to(a_square.get_right(), LEFT) - t2, t3 = group - return VGroup(t1, t2, t3) class ShowManyTriples(Scene): def construct(self): @@ -332,59 +287,6 @@ class ShowManyTriples(Scene): self.dither(2) -class CompareToFermatsLastTheorem(TeacherStudentsScene): - def construct(self): - expressions = [ - TexMobject( - "a", "^%d"%d, "+", "b", "^%d"%d, - "=", "c", "^%d"%d - ) - for d in range(2, 9) - ] - for expression in expressions: - for char, color in zip("abc", SIDE_COLORS): - expression.highlight_by_tex(char, color) - expression.next_to(self.get_pi_creatures(), UP, buff = 1.3) - square_expression = expressions[0] - low_expression = expressions[1] - square_expression.to_edge(UP, buff = 1.3) - top_brace = Brace(square_expression, UP, buff = SMALL_BUFF) - top_text = top_brace.get_text( - "Abundant integer solutions", buff = SMALL_BUFF - ) - low_brace = Brace(low_expression, DOWN, buff = SMALL_BUFF) - low_text = low_brace.get_text( - "No integer solutions", buff = SMALL_BUFF - ) - low_text.highlight(RED) - - self.add(square_expression, top_brace, top_text) - self.play( - ReplacementTransform( - square_expression.copy(), - low_expression - ), - self.teacher.change_mode, "raise_right_hand", - *[ - ApplyMethod(pi.change, "confused", expressions[1]) - for pi in self.get_students() - ] - ) - self.dither() - self.play(Transform(low_expression, expressions[2])) - self.play( - GrowFromCenter(low_brace), - FadeIn(low_text), - ) - self.change_student_modes( - "sassy", "angry", "erm", - look_at_arg = low_expression, - added_anims = [Transform(low_expression, expressions[3])] - ) - for expression in expressions[4:]: - self.play(Transform(low_expression, expression)) - self.dither() - class BabylonianTablets(Scene): def construct(self): title = TextMobject("Plimpton 322 Tablets \\\\ (1800 BC)") @@ -424,6 +326,185 @@ class BabylonianTablets(Scene): self.play(LaggedStart(FadeIn, triples, run_time = 5)) self.dither() +class PythagoreanProof(Scene): + def construct(self): + self.add_title() + self.show_proof() + + def add_title(self): + title = TexMobject("a^2", "+", "b^2", "=", "c^2") + for color, char in zip(SIDE_COLORS, "abc"): + title.highlight_by_tex(char, color) + title.to_edge(UP) + self.add(title) + self.title = title + + def show_proof(self): + triangle = Polygon( + ORIGIN, 5*RIGHT, 5*RIGHT+12*UP, + stroke_color = WHITE, + stroke_width = 2, + fill_color = WHITE, + fill_opacity = 0.5 + ) + triangle.scale_to_fit_height(3) + triangle.center() + side_labels = self.get_triangle_side_labels(triangle) + triangle_copy = triangle.copy() + squares = self.get_abc_squares(triangle) + a_square, b_square, c_square = squares + + + self.add(triangle, triangle_copy) + self.play(Write(side_labels)) + self.dither() + self.play(*map(DrawBorderThenFill, squares)) + self.add_labels_to_squares(squares, side_labels) + self.dither() + self.play( + VGroup(triangle_copy, a_square, b_square).move_to, + 4*LEFT+2*DOWN, DOWN, + VGroup(triangle, c_square).move_to, + 4*RIGHT+2*DOWN, DOWN, + run_time = 2, + path_arc = np.pi/2, + ) + self.dither() + self.add_new_triangles( + triangle, + self.get_added_triangles_to_c_square(triangle, c_square) + ) + self.dither() + self.add_new_triangles( + triangle_copy, + self.get_added_triangles_to_ab_squares(triangle_copy, a_square) + ) + self.dither() + + big_squares = VGroup(*map( + self.get_big_square, + [triangle, triangle_copy] + )) + negative_space_words = TextMobject( + "Same negative \\\\ space" + ) + negative_space_words.scale(0.75) + negative_space_words.shift(UP) + double_arrow = DoubleArrow(LEFT, RIGHT) + double_arrow.next_to(negative_space_words, DOWN) + + self.play( + FadeIn(big_squares), + Write(negative_space_words), + ShowCreation(double_arrow), + *map(FadeOut, squares) + ) + self.dither(2) + self.play(*it.chain( + map(FadeIn, squares), + map(Animation, big_squares), + )) + self.dither(2) + + def add_labels_to_squares(self, squares, side_labels): + for label, square in zip(side_labels, squares): + label.target = TexMobject(label.get_tex_string() + "^2") + label.target.highlight(label.get_color()) + # label.target.scale(0.7) + label.target.move_to(square) + square.add(label) + + self.play(LaggedStart(MoveToTarget, side_labels)) + + def add_new_triangles(self, triangle, added_triangles): + brace = Brace(added_triangles, DOWN) + label = TexMobject("a", "+", "b") + label.highlight_by_tex("a", A_COLOR) + label.highlight_by_tex("b", B_COLOR) + label.next_to(brace, DOWN) + + self.play(ReplacementTransform( + VGroup(triangle.copy().set_fill(opacity = 0)), + added_triangles, + run_time = 2, + )) + self.play(GrowFromCenter(brace)) + self.play(Write(label)) + triangle.added_triangles = added_triangles + + def get_big_square(self, triangle): + square = Square(stroke_color = RED) + square.replace( + VGroup(triangle, triangle.added_triangles), + stretch = True + ) + square.scale_in_place(1.01) + return square + + ##### + + def get_triangle_side_labels(self, triangle): + a, b, c = map(TexMobject, "abc") + for mob, color in zip([a, b, c], SIDE_COLORS): + mob.highlight(color) + a.next_to(triangle, DOWN) + b.next_to(triangle, RIGHT) + c.next_to(triangle.get_center(), LEFT) + return VGroup(a, b, c) + + def get_abc_squares(self, triangle): + a_square, b_square, c_square = squares = [ + Square( + stroke_color = color, + fill_color = color, + fill_opacity = 0.5, + ) + for color in SIDE_COLORS + ] + a_square.scale_to_fit_width(triangle.get_width()) + a_square.move_to(triangle.get_bottom(), UP) + b_square.scale_to_fit_height(triangle.get_height()) + b_square.move_to(triangle.get_right(), LEFT) + hyp_line = Line( + triangle.get_corner(UP+RIGHT), + triangle.get_corner(DOWN+LEFT), + ) + c_square.scale_to_fit_width(hyp_line.get_length()) + c_square.move_to(hyp_line.get_center(), UP) + c_square.rotate( + hyp_line.get_angle(), + about_point = hyp_line.get_center() + ) + + return a_square, b_square, c_square + + def get_added_triangles_to_c_square(self, triangle, c_square): + return VGroup(*[ + triangle.copy().rotate(i*np.pi/2, about_point = c_square.get_center()) + for i in range(1, 4) + ]) + + def get_added_triangles_to_ab_squares(self, triangle, a_square): + t1 = triangle.copy() + t1.rotate_in_place(np.pi) + group = VGroup(triangle, t1).copy() + group.rotate(-np.pi/2) + group.move_to(a_square.get_right(), LEFT) + t2, t3 = group + return VGroup(t1, t2, t3) + +##TODO, REMOVE +class LastVideoWrapper(Scene): + def construct(self): + title = TextMobject("Pi hiding in prime regularities") + title.to_edge(UP) + screen_rect = ScreenRectangle(height = 6) + screen_rect.next_to(title, DOWN) + + self.play(ShowCreation(screen_rect)) + self.play(Write(title)) + self.dither() + class ReframeOnLattice(PiCreatureScene): CONFIG = { "initial_plane_center" : 3*LEFT + DOWN, @@ -897,10 +978,10 @@ class OneMoreExample(Scene): "unit_size" : 0.5, "plane_center" : 3*LEFT + 3*DOWN, "dot_color" : YELLOW, + "x_label_range" : range(-6, 25, 3), + "y_label_range" : range(3, 13, 3), } def construct(self): - self.force_skipping() - self.add_plane() self.add_point() self.square_algebraically() @@ -915,7 +996,7 @@ class OneMoreExample(Scene): ) plane.axes.set_stroke(width = 4) coordinate_labels = VGroup() - for x in range(-6, 25, 3): + for x in self.x_label_range: if x == 0: continue coord = TexMobject(str(x)) @@ -923,7 +1004,7 @@ class OneMoreExample(Scene): coord.next_to(plane.coords_to_point(x, 0), DOWN, SMALL_BUFF) coord.add_background_rectangle() coordinate_labels.add(coord) - for y in range(3, 13, 3): + for y in self.y_label_range: if y == 0: continue coord = TexMobject("%di"%y) @@ -941,9 +1022,9 @@ class OneMoreExample(Scene): dot = Dot(point, color = self.dot_color) line = Line(self.plane.get_center_point(), point) line.highlight(dot.get_color()) - tuple_label = TexMobject("3+2i") - tuple_label.add_background_rectangle() - tuple_label.next_to(dot, RIGHT, SMALL_BUFF) + number_label = TexMobject("3+2i") + number_label.add_background_rectangle() + number_label.next_to(dot, RIGHT, SMALL_BUFF) distance_labels = VGroup() for tex in "3^2 + 2^2", "13": pre_label = TexMobject("\\sqrt{%s}"%tex) @@ -960,9 +1041,8 @@ class OneMoreExample(Scene): ) distance_labels.add(label) - self.revert_to_original_skipping_status() self.play( - FadeIn(tuple_label), + FadeIn(number_label), ShowCreation(line), DrawBorderThenFill(dot) ) @@ -974,26 +1054,482 @@ class OneMoreExample(Scene): self.distance_label = distance_labels[1] self.line = line self.dot = dot - self.tuple_label = tuple_label + self.number_label = number_label def square_algebraically(self): - pass + #Crazy hacky. To anyone looking at this, for God's + #sake, don't mimic this. + rect = Rectangle( + height = 3.5, width = 7, + stroke_color = WHITE, + stroke_width = 2, + fill_color = BLACK, + fill_opacity = 0.8 + ) + rect.to_corner(UP+RIGHT, buff = 0) + number = self.number_label[1].copy() + + top_line = TexMobject("(3+2i)", "(3+2i)") + for part in top_line: + for i, color in zip([1, 3], [BLUE, YELLOW]): + part[i].highlight(color) + second_line = TexMobject( + "\\big( 3^2 + (2i)^2 \\big) + " + \ + "\\big(3 \\cdot 2 + 2 \\cdot 3 \\big)i" + ) + for i in 1, 12, 18: + second_line[i].highlight(BLUE) + for i in 5, 14, 16: + second_line[i].highlight(YELLOW) + second_line.scale(0.9) + final_line = TexMobject("5 + 12i") + for i in 0, 2, 3: + final_line[i].highlight(GREEN) + lines = VGroup(top_line, second_line, final_line) + lines.arrange_submobjects(DOWN, buff = MED_LARGE_BUFF) + lines.next_to(rect.get_top(), DOWN) + minus = TexMobject("-").scale(0.9) + minus.move_to(second_line[3]) + + self.play( + FadeIn(rect), + Transform(VGroup(number), top_line), + run_time = 2 + ) + self.dither() + + index_alignment_lists = [ + [(0, 0, 0), (0, 1, 1), (1, 1, 2), (1, 5, 9)], + [ + (0, 2, 3), (1, 3, 4), (0, 3, 5), + (0, 4, 6), (1, 4, 7), (1, 3, 8) + ], + [ + (0, 2, 10), (0, 0, 11), (0, 1, 12), + (1, 3, 13), (1, 3, 14), (1, 5, 19), + (0, 4, 20), (1, 4, 20), + ], + [ + (0, 2, 15), (0, 3, 16), + (1, 1, 17), (1, 1, 18), + ], + ] + for index_alignment in index_alignment_lists[:2]: + self.play(*[ + ReplacementTransform( + top_line[i][j].copy(), second_line[k], + run_time = 1.5 + ) + for i, j, k in index_alignment + ]) + self.dither() + self.play( + Transform(second_line[3], minus), + FadeOut(VGroup(*[ + second_line[i] + for i in 4, 6, 7 + ])), + second_line[5].shift, 0.35*RIGHT, + ) + self.play(VGroup(*second_line[:4]).shift, 0.55*RIGHT) + self.dither() + for index_alignment in index_alignment_lists[2:]: + self.play(*[ + ReplacementTransform( + top_line[i][j].copy(), second_line[k], + run_time = 1.5 + ) + for i, j, k in index_alignment + ]) + self.dither() + self.play(FadeIn(final_line)) + self.dither() + + self.final_line = final_line def plot_result(self): - pass + result_label = self.final_line.copy() + result_label.add_background_rectangle() + + point = self.plane.coords_to_point(5, 12) + dot = Dot(point, color = GREEN) + line = Line(self.plane.get_center_point(), point) + line.highlight(dot.get_color()) + distance_label = TexMobject("13") + distance_label.add_background_rectangle() + distance_label.next_to(line.get_center(), UP+LEFT, SMALL_BUFF) + + self.play( + result_label.next_to, dot, UP+LEFT, SMALL_BUFF, + Animation(self.final_line), + DrawBorderThenFill(dot) + ) + self.dither() + self.play(*[ + ReplacementTransform(m1.copy(), m2) + for m1, m2 in [ + (self.line, line), + (self.distance_label, distance_label) + ] + ]) + self.dither() def show_triangle(self): - pass - - - - - - - - - - + triangle = Polygon(*[ + self.plane.coords_to_point(x, y) + for x, y in [(0, 0), (5, 0), (5, 12)] + ]) + triangle.set_stroke(WHITE, 1) + triangle.set_fill(BLUE, opacity = 0.75) + + self.play( + FadeIn(triangle), + Animation(VGroup( + self.line, self.dot, + self.number_label[1], *self.distance_label[1:] + )), + run_time = 2 + ) + self.dither(2) + +class ThisIsMagic(TeacherStudentsScene): + def construct(self): + self.student_says( + "This is magic", target_mode = "hooray" + ) + self.play(self.teacher.change, "happy") + self.dither(2) + +class GeneralExample(OneMoreExample): + CONFIG = { + "number" : complex(4, 1), + "square_color" : MAROON_B, + "result_label_vect" : UP+LEFT, + } + def construct(self): + self.add_plane() + self.square_point() + + def square_point(self): + z = self.number + z_point = self.plane.number_to_point(z) + zero_point = self.plane.number_to_point(0) + dot = Dot(z_point, color = self.dot_color) + line = Line(zero_point, z_point) + line.highlight(dot.get_color()) + label = TexMobject(complex_string_with_i(z)) + label.add_background_rectangle() + label.next_to(dot, RIGHT, SMALL_BUFF) + + square_point = self.plane.number_to_point(z**2) + square_dot = Dot(square_point, color = self.square_color) + square_line = Line(zero_point, square_point) + square_line.highlight(square_dot.get_color()) + square_label = TexMobject(complex_string_with_i(z**2)) + square_label.add_background_rectangle() + square_label.next_to(square_dot, UP+RIGHT, SMALL_BUFF) + result_length_label = TexMobject(str(int(abs(z**2)))) + result_length_label.next_to( + square_line.get_center(), self.result_label_vect + ) + result_length_label.add_background_rectangle() + + arrow = Arrow( + z_point, square_point, + # buff = SMALL_BUFF, + path_arc = np.pi/2 + ) + arrow.highlight(WHITE) + z_to_z_squared = TexMobject("z", "\\to", "z^2") + z_to_z_squared.highlight_by_tex("z", dot.get_color()) + z_to_z_squared.highlight_by_tex("z^2", square_dot.get_color()) + z_to_z_squared.next_to( + arrow.point_from_proportion(0.5), + RIGHT, MED_SMALL_BUFF + ) + z_to_z_squared.add_to_back( + BackgroundRectangle(VGroup( + z_to_z_squared[2][0], + *z_to_z_squared[:-1] + )), + BackgroundRectangle(z_to_z_squared[2][1]) + ) + + + self.play( + Write(label), + ShowCreation(line), + DrawBorderThenFill(dot) + ) + self.dither() + self.play( + ShowCreation(arrow), + FadeIn(z_to_z_squared), + Animation(label), + ) + self.play(*[ + ReplacementTransform( + start.copy(), target, + path_arc = np.pi/2, + run_time = 1.5 + ) + for start, target in [ + (dot, square_dot), + (line, square_line), + (label, square_label), + ] + ]) + self.dither() + self.play(Write(result_length_label)) + self.dither() + + self.example_dot = dot + self.example_label = label + self.example_line = line + self.square_dot = square_dot + self.square_label = square_label + self.square_line = square_line + self.z_to_z_squared = z_to_z_squared + self.z_to_z_squared_arrow = arrow + self.result_length_label = result_length_label + +class BoringExample(GeneralExample): + CONFIG = { + "number" : complex(2, 2), + "result_label_vect" : RIGHT, + } + def construct(self): + self.add_plane() + self.square_point() + self.show_associated_triplet() + + def show_associated_triplet(self): + arrow = Arrow(LEFT, RIGHT, color = GREEN) + arrow.next_to(self.square_label, RIGHT) + triple = TexMobject("0^2 + 8^2 = 8^2") + for part, color in zip(triple[::3], SIDE_COLORS): + part.highlight(color) + triple.add_background_rectangle() + triple.next_to(arrow, RIGHT) + + morty = Mortimer() + morty.next_to(self.plane.coords_to_point(12, 0), UP) + + self.play( + ShowCreation(arrow), + FadeIn(morty) + ) + self.play( + Write(triple), + morty.change, "raise_right_hand", triple + ) + self.play(Blink(morty)) + self.play(morty.change, "tired") + self.dither(2) + self.play(Blink(morty)) + self.dither() + +class FiveTwoExample(GeneralExample): + CONFIG = { + "number" : complex(5, 2), + "unit_size" : 0.25, + "x_label_range" : range(-10, 40, 5), + "y_label_range" : range(0, 30, 5), + } + +class WriteGeneralFormula(GeneralExample): + CONFIG = { + "plane_center" : 2*RIGHT, + "x_label_range" : [], + "y_label_range" : [], + "unit_size" : 0.7, + "number" : complex(2, 1), + } + def construct(self): + self.add_plane() + self.show_squaring() + self.expand_square() + self.draw_triangle() + self.show_uv_to_triples() + + def show_squaring(self): + self.force_skipping() + self.square_point() + dot = self.example_dot + old_label = self.example_label + line = self.example_line + square_dot = self.square_dot + old_square_label = self.square_label + square_line = self.square_line + z_to_z_squared = self.z_to_z_squared + arrow = self.z_to_z_squared_arrow + result_length_label = self.result_length_label + self.clear() + self.add(self.plane, self.plane.coordinate_labels) + self.revert_to_original_skipping_status() + + label = TexMobject("u+vi") + label.move_to(old_label, LEFT) + label.add_background_rectangle() + square_label = TexMobject("(u+vi)^2") + square_label.move_to(old_square_label, LEFT) + square_label.add_background_rectangle() + + self.add(label, dot, line) + self.play( + ShowCreation(arrow), + FadeIn(z_to_z_squared) + ) + self.play(*[ + ReplacementTransform( + start.copy(), target, + run_time = 1.5, + path_arc = np.pi/2 + ) + for start, target in [ + (dot, square_dot), + (line, square_line), + (label, square_label), + ] + ]) + + self.example_label = label + self.square_label = square_label + + def expand_square(self): + rect = Rectangle( + height = 2.5, width = 7, + stroke_width = 0, + fill_color = BLACK, + fill_opacity = 0.8, + ) + rect.to_corner(UP+LEFT, buff = 0) + top_line = TexMobject("(u+vi)(u+vi)") + for i in 1, 7: + top_line[i].highlight(U_COLOR) + top_line[i+2].highlight(V_COLOR) + top_line.next_to(rect.get_top(), DOWN) + second_line = TexMobject( + "\\big(", "u^2 - v^2", "\\big)", "+", + "\\big(", "2uv", "\\big)", "i" + ) + for i, j in (1, 0), (5, 1): + second_line[i][j].highlight(U_COLOR) + for i, j in (1, 3), (5, 2): + second_line[i][j].highlight(V_COLOR) + second_line.next_to(top_line, DOWN, MED_LARGE_BUFF) + real_part = second_line[1] + imag_part = second_line[5] + for part in real_part, imag_part: + part.add_to_back(BackgroundRectangle(part)) + + z = self.number**2 + square_point = self.plane.number_to_point(z) + zero_point = self.plane.number_to_point(0) + real_part_point = self.plane.number_to_point(z.real) + real_part_line = Line(zero_point, real_part_point) + imag_part_line = Line(real_part_point, square_point) + for line in real_part_line, imag_part_line: + line.highlight(self.square_color) + + + self.play(*map(FadeIn, [rect, top_line, second_line])) + self.dither() + self.play( + real_part.copy().next_to, real_part_line.copy(), + DOWN, SMALL_BUFF, + ShowCreation(real_part_line) + ) + self.dither() + self.play( + FadeOut(VGroup( + self.example_label, self.example_dot, self.example_line, + self.z_to_z_squared, self.z_to_z_squared_arrow + )), + imag_part.copy().next_to, imag_part_line.copy(), + RIGHT, SMALL_BUFF, + ShowCreation(imag_part_line) + ) + self.dither() + + self.corner_rect = rect + + def draw_triangle(self): + hyp_length = TexMobject("u", "^2", "+", "v", "^2") + hyp_length.highlight_by_tex("u", U_COLOR) + hyp_length.highlight_by_tex("v", V_COLOR) + hyp_length.add_background_rectangle() + line = self.square_line + hyp_length.next_to(line.get_center(), UP, SMALL_BUFF) + hyp_length.rotate( + line.get_angle(), + about_point = line.get_center() + ) + triangle = Polygon( + ORIGIN, RIGHT, RIGHT+UP, + stroke_width = 0, + fill_color = MAROON_B, + fill_opacity = 0.5, + ) + triangle.replace(line, stretch = True) + + self.play(Write(hyp_length)) + self.dither() + self.play(FadeIn(triangle)) + self.dither() + + def show_uv_to_triples(self): + rect = self.corner_rect.copy() + rect.stretch_to_fit_height(2*SPACE_HEIGHT) + rect.move_to(self.corner_rect.get_bottom(), UP) + + h_line = Line(rect.get_left(), rect.get_right()) + h_line.next_to(rect.get_top(), DOWN, LARGE_BUFF) + v_line = Line(rect.get_top(), rect.get_bottom()) + v_line.shift(1.3*LEFT) + uv_title = TexMobject("(u, v)") + triple_title = TexMobject("(u^2 - v^2, 2uv, u^2 + v^2)") + uv_title.scale(0.75) + triple_title.scale(0.75) + uv_title.next_to( + h_line.point_from_proportion(1./6), + UP, SMALL_BUFF + ) + triple_title.next_to( + h_line.point_from_proportion(2./3), + UP, SMALL_BUFF + ) + + pairs = [(2, 1), (3, 2), (4, 1), (4, 3), (5, 2), (5, 4)] + pair_mobs = VGroup() + triple_mobs = VGroup() + for u, v in pairs: + a, b, c = u**2 - v**2, 2*u*v, u**2 + v**2 + pair_mob = TexMobject("(", str(u), ",", str(v), ")") + pair_mob.highlight_by_tex(str(u), U_COLOR) + pair_mob.highlight_by_tex(str(v), V_COLOR) + triple_mob = TexMobject("(%d, %d, %d)"%(a, b, c)) + pair_mobs.add(pair_mob) + triple_mobs.add(triple_mob) + pair_mob.scale(0.75) + triple_mob.scale(0.75) + pair_mobs.arrange_submobjects(DOWN) + pair_mobs.next_to(uv_title, DOWN, MED_LARGE_BUFF) + triple_mobs.arrange_submobjects(DOWN) + triple_mobs.next_to(triple_title, DOWN, MED_LARGE_BUFF) + + self.play(*map(FadeIn, [ + rect, h_line, v_line, + uv_title, triple_title + ])) + self.play(*[ + LaggedStart( + FadeIn, mob, + run_time = 5, + lag_ratio = 0.2 + ) + for mob in pair_mobs, triple_mobs + ])