mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 02:35:22 +08:00
Up to definition of problem in wcat
This commit is contained in:
@ -33,7 +33,7 @@ MED_BUFF = 0.25
|
||||
LARGE_BUFF = 1
|
||||
|
||||
DEFAULT_MOBJECT_TO_EDGE_BUFFER = MED_BUFF
|
||||
DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = SMALL_BUFF
|
||||
DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_BUFF
|
||||
|
||||
|
||||
#All in seconds
|
||||
|
@ -42,6 +42,7 @@ def play_finish_sound():
|
||||
play_chord(12, 9, 5, 2)
|
||||
|
||||
def get_smooth_handle_points(points):
|
||||
points = np.array(points)
|
||||
num_handles = len(points) - 1
|
||||
dim = points.shape[1]
|
||||
if num_handles < 1:
|
||||
|
@ -76,12 +76,12 @@ class Scene(object):
|
||||
###
|
||||
|
||||
def extract_mobject_family_members(self, *mobjects):
|
||||
return remove_list_redundancies(list(
|
||||
return list(
|
||||
it.chain(*[
|
||||
m.submobject_family()
|
||||
for m in mobjects
|
||||
])
|
||||
))
|
||||
)
|
||||
|
||||
def add(self, *mobjects_to_add):
|
||||
"""
|
||||
@ -237,7 +237,6 @@ class Scene(object):
|
||||
animations = self.align_run_times(*animations, **kwargs)
|
||||
moving_mobjects, static_mobjects = \
|
||||
self.separate_moving_and_static_mobjects(*animations)
|
||||
|
||||
self.update_frame(static_mobjects)
|
||||
static_image = self.get_frame()
|
||||
for t in self.get_time_progression(animations):
|
||||
|
@ -51,11 +51,11 @@ class PiCreature(SVGMobject):
|
||||
def name_parts(self):
|
||||
self.mouth = self.submobjects[MOUTH_INDEX]
|
||||
self.body = self.submobjects[BODY_INDEX]
|
||||
self.pupils = VMobject(*[
|
||||
self.pupils = VGroup(*[
|
||||
self.submobjects[LEFT_PUPIL_INDEX],
|
||||
self.submobjects[RIGHT_PUPIL_INDEX]
|
||||
])
|
||||
self.eyes = VMobject(*[
|
||||
self.eyes = VGroup(*[
|
||||
self.submobjects[LEFT_EYE_INDEX],
|
||||
self.submobjects[RIGHT_EYE_INDEX]
|
||||
])
|
||||
@ -176,6 +176,28 @@ class Mathematician(PiCreature):
|
||||
"color" : GREY,
|
||||
}
|
||||
|
||||
class BabyPiCreature(PiCreature):
|
||||
CONFIG = {
|
||||
"scale_factor" : 0.5,
|
||||
"eye_scale_factor" : 1.2,
|
||||
"pupil_scale_factor" : 1.3
|
||||
}
|
||||
def __init__(self, *args, **kwargs):
|
||||
PiCreature.__init__(self, *args, **kwargs)
|
||||
self.scale(self.scale_factor)
|
||||
self.shift(LEFT)
|
||||
self.to_edge(DOWN, buff = LARGE_BUFF)
|
||||
eyes = VGroup(self.eyes, self.pupils)
|
||||
eyes_bottom = eyes.get_bottom()
|
||||
eyes.scale(self.eye_scale_factor)
|
||||
eyes.move_to(eyes_bottom, aligned_edge = DOWN)
|
||||
looking_direction = self.get_looking_direction()
|
||||
for pupil in self.pupils:
|
||||
pupil.scale_in_place(self.pupil_scale_factor)
|
||||
self.look(looking_direction)
|
||||
|
||||
|
||||
|
||||
class Blink(ApplyMethod):
|
||||
CONFIG = {
|
||||
"rate_func" : squish_rate_func(there_and_back)
|
||||
|
@ -50,7 +50,7 @@ class Circle(Arc):
|
||||
|
||||
class Dot(Circle): #Use 1D density, even though 2D
|
||||
CONFIG = {
|
||||
"radius" : 0.05,
|
||||
"radius" : 0.08,
|
||||
"stroke_width" : 0,
|
||||
"fill_opacity" : 1.0,
|
||||
"color" : WHITE
|
||||
|
537
wcat.py
Normal file
537
wcat.py
Normal file
@ -0,0 +1,537 @@
|
||||
from helpers import *
|
||||
|
||||
from mobject.tex_mobject import TexMobject
|
||||
from mobject import Mobject
|
||||
from mobject.image_mobject import ImageMobject
|
||||
from mobject.vectorized_mobject import *
|
||||
|
||||
from animation.animation import Animation
|
||||
from animation.transform import *
|
||||
from animation.simple_animations import *
|
||||
from animation.playground import *
|
||||
from topics.geometry import *
|
||||
from topics.characters import *
|
||||
from topics.functions import *
|
||||
from topics.fractals import *
|
||||
from topics.number_line import *
|
||||
from topics.combinatorics import *
|
||||
from topics.numerals import *
|
||||
from topics.three_dimensions import *
|
||||
from scene import Scene
|
||||
from camera import Camera
|
||||
from mobject.svg_mobject import *
|
||||
from mobject.tex_mobject import *
|
||||
|
||||
|
||||
class ClosedLoopScene(Scene):
|
||||
CONFIG = {
|
||||
"loop_anchor_points" : [
|
||||
3*RIGHT,
|
||||
2*RIGHT+UP,
|
||||
3*RIGHT + 3*UP,
|
||||
UP,
|
||||
2*UP+LEFT,
|
||||
2*LEFT + 2*UP,
|
||||
3*LEFT,
|
||||
2*LEFT+DOWN,
|
||||
3*LEFT+2*DOWN,
|
||||
2*DOWN+RIGHT,
|
||||
LEFT+DOWN,
|
||||
],
|
||||
"square_vertices" : [
|
||||
2*RIGHT+UP,
|
||||
2*UP+LEFT,
|
||||
2*LEFT+DOWN,
|
||||
2*DOWN+RIGHT
|
||||
],
|
||||
"rect_vertices" : [
|
||||
0*RIGHT + 1*UP,
|
||||
-1*RIGHT + 2*UP,
|
||||
-3*RIGHT + 0*UP,
|
||||
-2*RIGHT + -1*UP,
|
||||
],
|
||||
"dot_color" : YELLOW,
|
||||
"connecting_lines_color" : BLUE,
|
||||
}
|
||||
def setup(self):
|
||||
self.dots = VGroup()
|
||||
self.connecting_lines = VGroup()
|
||||
self.add_loop()
|
||||
|
||||
def add_loop(self):
|
||||
self.loop = self.get_default_loop()
|
||||
self.add(self.loop)
|
||||
|
||||
def get_default_loop(self):
|
||||
loop = VMobject()
|
||||
loop.set_points_smoothly(
|
||||
self.loop_anchor_points + [self.loop_anchor_points[0]]
|
||||
)
|
||||
return loop
|
||||
|
||||
def get_square(self):
|
||||
return Polygon(*self.square_vertices)
|
||||
|
||||
def get_rect_vertex_dots(self, square = False):
|
||||
if square:
|
||||
vertices = self.square_vertices
|
||||
else:
|
||||
vertices = self.rect_vertices
|
||||
dots = VGroup(*[Dot(v) for v in vertices])
|
||||
dots.highlight(self.dot_color)
|
||||
return dots
|
||||
|
||||
def add_dot(self, dot):
|
||||
self.add_dots(dot)
|
||||
|
||||
def add_dots(self, *dots):
|
||||
self.dots.add(*dots)
|
||||
self.add(self.dots)
|
||||
|
||||
def add_rect_dots(self, square = False):
|
||||
self.add_dots(*self.get_rect_vertex_dots())
|
||||
|
||||
def add_dots_at_alphas(self, *alphas):
|
||||
self.add_dots(*[
|
||||
Dot(
|
||||
self.loop.point_from_proportion(alpha),
|
||||
color = self.dot_color
|
||||
)
|
||||
for alpha in alphas
|
||||
])
|
||||
|
||||
def add_connecting_lines(self, cyclic = False):
|
||||
if cyclic:
|
||||
pairs = adjascent_pairs(self.dots)
|
||||
else:
|
||||
n_pairs = len(list(self.dots))/2
|
||||
pairs = zip(self.dots[:n_pairs], self.dots[n_pairs:])
|
||||
for d1, d2 in pairs:
|
||||
line = Line(
|
||||
d1.get_center(), d2.get_center(),
|
||||
stroke_width = 6
|
||||
)
|
||||
line.start_dot = d1
|
||||
line.end_dot = d2
|
||||
line.update_anim = UpdateFromFunc(
|
||||
line,
|
||||
lambda l : l.put_start_and_end_on(
|
||||
l.start_dot.get_center(),
|
||||
l.end_dot.get_center()
|
||||
)
|
||||
)
|
||||
self.connecting_lines.add(line)
|
||||
self.connecting_lines.highlight(self.connecting_lines_color)
|
||||
self.add(self.connecting_lines, self.dots)
|
||||
|
||||
def get_line_anims(self):
|
||||
return [
|
||||
line.update_anim
|
||||
for line in self.connecting_lines
|
||||
] + [Animation(self.dots)]
|
||||
|
||||
def get_dot_alphas(self, dots = None, precision = 0.005):
|
||||
if dots == None:
|
||||
dots = self.dots
|
||||
alphas = []
|
||||
alpha_range = np.arange(0, 1, precision)
|
||||
loop_points = np.array(map(self.loop.point_from_proportion, alpha_range))
|
||||
for dot in dots:
|
||||
vects = loop_points - dot.get_center()
|
||||
norms = np.apply_along_axis(np.linalg.norm, 1, vects)
|
||||
index = np.argmin(norms)
|
||||
alphas.append(alpha_range[index])
|
||||
return alphas
|
||||
|
||||
def let_dots_wonder(self, run_time = 5, random_seed = None, added_anims = []):
|
||||
if random_seed is not None:
|
||||
np.random.seed(random_seed)
|
||||
start_alphas = self.get_dot_alphas()
|
||||
alpha_rates = 0.1 + 0.1*np.random.random(len(list(self.dots)))
|
||||
def generate_rate_func(start, rate):
|
||||
return lambda t : (start + t*rate*run_time)%1
|
||||
anims = [
|
||||
MoveAlongPath(
|
||||
dot,
|
||||
self.loop,
|
||||
rate_func = generate_rate_func(start, rate)
|
||||
)
|
||||
for dot, start, rate in zip(self.dots, start_alphas, alpha_rates)
|
||||
]
|
||||
anims += self.get_line_anims()
|
||||
anims += added_anims
|
||||
self.play(*anims, run_time = run_time)
|
||||
|
||||
def move_dots_to_alphas(self, alphas, run_time = 3):
|
||||
assert(len(alphas) == len(list(self.dots)))
|
||||
start_alphas = self.get_dot_alphas()
|
||||
def generate_rate_func(start_alpha, alpha):
|
||||
return lambda t : interpolate(start_alpha, alpha, smooth(t))
|
||||
anims = [
|
||||
MoveAlongPath(
|
||||
dot, self.loop,
|
||||
rate_func = generate_rate_func(sa, a),
|
||||
run_time = run_time,
|
||||
)
|
||||
for dot, sa, a in zip(self.dots, start_alphas, alphas)
|
||||
]
|
||||
anims += self.get_line_anims()
|
||||
self.play(*anims)
|
||||
|
||||
def transform_loop(self, target_loop, **kwargs):
|
||||
alphas = self.get_dot_alphas()
|
||||
dot_anims = []
|
||||
for dot, alpha in zip(self.dots, alphas):
|
||||
dot.generate_target()
|
||||
dot.target.move_to(target_loop.point_from_proportion(alpha))
|
||||
dot_anims.append(MoveToTarget(dot))
|
||||
self.play(
|
||||
Transform(self.loop, target_loop),
|
||||
*dot_anims + self.get_line_anims(),
|
||||
**kwargs
|
||||
)
|
||||
self.remove(self.loop)
|
||||
self.loop = target_loop
|
||||
self.add(self.loop)
|
||||
|
||||
def find_square(self):
|
||||
alpha_quads = list(it.combinations(
|
||||
np.arange(0, 1, 0.02) , 4
|
||||
))
|
||||
quads = np.array([
|
||||
[
|
||||
self.loop.point_from_proportion(alpha)
|
||||
for alpha in quad
|
||||
]
|
||||
for quad in alpha_quads
|
||||
])
|
||||
scores = self.square_scores(quads)
|
||||
index = np.argmin(scores)
|
||||
return quads[index]
|
||||
|
||||
def square_scores(self, all_quads):
|
||||
midpoint_diffs = np.apply_along_axis(
|
||||
np.linalg.norm, 1,
|
||||
0.5*(all_quads[:,0] + all_quads[:,2]) - 0.5*(all_quads[:,1] + all_quads[:,3])
|
||||
)
|
||||
vects1 = all_quads[:,0] - all_quads[:,2]
|
||||
vects2 = all_quads[:,1] - all_quads[:,3]
|
||||
distances1 = np.apply_along_axis(np.linalg.norm, 1, vects1)
|
||||
distances2 = np.apply_along_axis(np.linalg.norm, 1, vects2)
|
||||
distance_diffs = np.abs(distances1 - distances2)
|
||||
midpoint_diffs /= distances1
|
||||
distance_diffs /= distances2
|
||||
|
||||
buffed_d1s = np.repeat(distances1, 3).reshape(vects1.shape)
|
||||
buffed_d2s = np.repeat(distances2, 3).reshape(vects2.shape)
|
||||
unit_v1s = vects1/buffed_d1s
|
||||
unit_v2s = vects2/buffed_d2s
|
||||
dots = np.abs(unit_v1s[:,0]*unit_v2s[:,0] + unit_v1s[:,1]*unit_v2s[:,1] + unit_v1s[:,2]*unit_v2s[:,2])
|
||||
|
||||
return midpoint_diffs + distance_diffs + dots
|
||||
|
||||
|
||||
|
||||
#############################
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.play(self.get_teacher().change_mode, "hooray")
|
||||
self.random_blink()
|
||||
self.teacher_says("")
|
||||
for pi in self.get_students():
|
||||
pi.generate_target()
|
||||
pi.target.change_mode("happy")
|
||||
pi.target.look_at(self.get_teacher().bubble)
|
||||
self.play(*map(MoveToTarget, self.get_students()))
|
||||
self.random_blink(3)
|
||||
self.teacher_says(
|
||||
"Here's why \\\\ I'm excited...",
|
||||
pi_creature_target_mode = "hooray"
|
||||
)
|
||||
for pi in self.get_students():
|
||||
pi.target.look_at(self.get_teacher().eyes)
|
||||
self.play(*map(MoveToTarget, self.get_students()))
|
||||
self.dither()
|
||||
|
||||
class WhenIWasAKid(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
children = self.get_children()
|
||||
speaker = self.get_speaker()
|
||||
|
||||
self.prepare_everyone(children, speaker)
|
||||
self.transition_from_previous_scene(children, speaker)
|
||||
self.students = children
|
||||
self.teacher = speaker
|
||||
self.run_class()
|
||||
self.grow_up()
|
||||
|
||||
def transition_from_previous_scene(self, children, speaker):
|
||||
self.play(self.get_teacher().change_mode, "hooray", run_time = 0)
|
||||
self.change_student_modes(*["happy"]*3)
|
||||
|
||||
speaker.look_at(children)
|
||||
me = children[-1]
|
||||
self.play(
|
||||
FadeOut(self.get_students()),
|
||||
Transform(self.get_teacher(), me)
|
||||
)
|
||||
self.remove(self.get_teacher())
|
||||
self.add(me)
|
||||
self.play(*map(FadeIn, children[:-1] + [speaker]))
|
||||
self.random_blink()
|
||||
|
||||
def run_class(self):
|
||||
children = self.students
|
||||
speaker = self.teacher
|
||||
title = TextMobject("Topology")
|
||||
title.to_edge(UP)
|
||||
|
||||
self.random_blink()
|
||||
self.play(self.teacher.change_mode, "speaking")
|
||||
self.play(Write(title))
|
||||
self.random_blink()
|
||||
pi1, pi2, pi3, me = children
|
||||
self.play(pi1.change_mode, "raise_right_hand")
|
||||
self.random_blink()
|
||||
self.play(
|
||||
pi2.change_mode, "confused",
|
||||
pi3.change_mode, "happy",
|
||||
pi2.look_at, pi3.eyes,
|
||||
pi3.look_at, pi2.eyes,
|
||||
)
|
||||
self.random_blink()
|
||||
self.play(me.change_mode, "pondering")
|
||||
self.dither()
|
||||
self.random_blink(2)
|
||||
self.play(pi1.change_mode, "raise_left_hand")
|
||||
self.dither()
|
||||
self.play(pi2.change_mode, "erm")
|
||||
self.random_blink()
|
||||
self.student_says(
|
||||
"How is this math?",
|
||||
student_index = -1,
|
||||
pi_creature_target_mode = "pleading",
|
||||
width = 5,
|
||||
height = 3,
|
||||
direction = RIGHT
|
||||
)
|
||||
self.play(
|
||||
pi1.change_mode, "pondering",
|
||||
pi2.change_mode, "pondering",
|
||||
pi3.change_mode, "pondering",
|
||||
)
|
||||
self.play(speaker.change_mode, "pondering")
|
||||
self.random_blink()
|
||||
|
||||
def grow_up(self):
|
||||
me = self.students[-1]
|
||||
self.students.remove(me)
|
||||
morty = Mortimer(mode = "pondering")
|
||||
morty.flip()
|
||||
morty.move_to(me, aligned_edge = DOWN)
|
||||
morty.to_edge(LEFT)
|
||||
morty.look(RIGHT)
|
||||
|
||||
self.play(
|
||||
Transform(me, morty),
|
||||
*map(FadeOut, [
|
||||
self.students, self.teacher,
|
||||
me.bubble, me.bubble.content
|
||||
])
|
||||
)
|
||||
self.remove(me)
|
||||
self.add(morty)
|
||||
self.play(Blink(morty))
|
||||
self.dither()
|
||||
self.play(morty.change_mode, "hooray")
|
||||
self.dither()
|
||||
|
||||
|
||||
def prepare_everyone(self, children, speaker):
|
||||
self.everyone = list(children) + [speaker]
|
||||
for pi in self.everyone:
|
||||
pi.bubble = None
|
||||
|
||||
def get_children(self):
|
||||
colors = [MAROON_E, YELLOW_D, PINK, GREY_BROWN]
|
||||
children = VGroup(*[
|
||||
BabyPiCreature(color = color)
|
||||
for color in colors
|
||||
])
|
||||
children.arrange_submobjects(RIGHT)
|
||||
children.to_edge(DOWN, buff = LARGE_BUFF)
|
||||
children.to_edge(LEFT)
|
||||
return children
|
||||
|
||||
def get_speaker(self):
|
||||
speaker = Mathematician(mode = "happy")
|
||||
speaker.flip()
|
||||
speaker.to_edge(DOWN, buff = LARGE_BUFF)
|
||||
speaker.to_edge(RIGHT)
|
||||
return speaker
|
||||
|
||||
def get_everyone(self):
|
||||
if hasattr(self, "everyone"):
|
||||
return self.everyone
|
||||
else:
|
||||
return TeacherStudentsScene.get_everyone(self)
|
||||
|
||||
class FormingTheMobiusStrip(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class DrawLineOnMobiusStrip(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class MugIntoTorus(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class DefineInscribedSquareProblem(ClosedLoopScene):
|
||||
def construct(self):
|
||||
self.draw_loop()
|
||||
self.cycle_through_shapes()
|
||||
self.ask_about_rectangles()
|
||||
|
||||
def draw_loop(self):
|
||||
self.title = TextMobject("Inscribed", "square", "problem")
|
||||
self.title.to_edge(UP)
|
||||
|
||||
#Draw loop
|
||||
self.remove(self.loop)
|
||||
self.play(Write(self.title))
|
||||
self.dither()
|
||||
self.play(ShowCreation(
|
||||
self.loop,
|
||||
run_time = 3,
|
||||
rate_func = None
|
||||
))
|
||||
self.dither()
|
||||
self.add_rect_dots(square = True)
|
||||
self.play(ShowCreation(self.dots, run_time = 2))
|
||||
self.dither()
|
||||
self.add_connecting_lines(cyclic = True)
|
||||
self.play(
|
||||
ShowCreation(
|
||||
self.connecting_lines,
|
||||
submobject_mode = "all_at_once",
|
||||
run_time = 2
|
||||
),
|
||||
Animation(self.dots)
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
def cycle_through_shapes(self):
|
||||
circle = Circle(radius = 2.5, color = WHITE)
|
||||
ellipse = circle.copy()
|
||||
ellipse.stretch(1.5, 0)
|
||||
ellipse.stretch(0.7, 1)
|
||||
ellipse.rotate(-np.pi/2)
|
||||
ellipse.scale_to_fit_height(4)
|
||||
pi_loop = TexMobject("\\pi")[0]
|
||||
pi_loop.set_fill(opacity = 0)
|
||||
pi_loop.set_stroke(
|
||||
color = WHITE,
|
||||
width = DEFAULT_POINT_THICKNESS
|
||||
)
|
||||
pi_loop.scale_to_fit_height(4)
|
||||
randy = Randolph()
|
||||
randy.look(DOWN)
|
||||
randy.scale_to_fit_width(pi_loop.get_width())
|
||||
randy.move_to(pi_loop, aligned_edge = DOWN)
|
||||
randy.body.set_fill(opacity = 0)
|
||||
randy.mouth.set_stroke(width = 0)
|
||||
|
||||
self.transform_loop(circle)
|
||||
self.dither()
|
||||
odd_eigths = np.linspace(1./8, 7./8, 4)
|
||||
self.move_dots_to_alphas(odd_eigths)
|
||||
self.dither()
|
||||
for nudge in 0.1, -0.1, 0:
|
||||
self.move_dots_to_alphas(odd_eigths+nudge)
|
||||
self.dither()
|
||||
self.transform_loop(ellipse)
|
||||
self.dither()
|
||||
nudge = 0.055
|
||||
self.move_dots_to_alphas(
|
||||
odd_eigths + [nudge, -nudge, nudge, -nudge]
|
||||
)
|
||||
self.dither(2)
|
||||
self.transform_loop(pi_loop)
|
||||
self.let_dots_wonder()
|
||||
randy_anims = [
|
||||
FadeIn(randy),
|
||||
Animation(randy),
|
||||
Blink(randy),
|
||||
Animation(randy),
|
||||
Blink(randy, rate_func = smooth)
|
||||
]
|
||||
for anim in randy_anims:
|
||||
self.let_dots_wonder(
|
||||
run_time = 1,
|
||||
random_seed = 0,
|
||||
added_anims = [anim]
|
||||
)
|
||||
self.remove(randy)
|
||||
self.transform_loop(self.get_default_loop())
|
||||
|
||||
def ask_about_rectangles(self):
|
||||
morty = Mortimer()
|
||||
morty.next_to(ORIGIN, DOWN)
|
||||
morty.to_edge(RIGHT)
|
||||
|
||||
new_title = TextMobject("Inscribed", "rectangle", "problem")
|
||||
new_title.highlight_by_tex("rectangle", YELLOW)
|
||||
new_title.to_edge(UP)
|
||||
rect_dots = self.get_rect_vertex_dots()
|
||||
rect_alphas = self.get_dot_alphas(rect_dots)
|
||||
|
||||
self.play(FadeIn(morty))
|
||||
self.play(morty.change_mode, "speaking")
|
||||
self.play(Transform(self.title, new_title))
|
||||
self.move_dots_to_alphas(rect_alphas)
|
||||
self.dither()
|
||||
self.play(morty.change_mode, "hooray")
|
||||
self.play(Blink(morty))
|
||||
self.dither()
|
||||
self.play(FadeOut(self.connecting_lines))
|
||||
self.connecting_lines = VGroup()
|
||||
self.play(morty.change_mode, "plain")
|
||||
|
||||
dot_pairs = [
|
||||
VGroup(self.dots[i], self.dots[j])
|
||||
for i, j in (0, 2), (1, 3)
|
||||
]
|
||||
pair_colors = MAROON_B, PURPLE_C
|
||||
diag_lines = [
|
||||
Line(d1.get_center(), d2.get_center(), color = c)
|
||||
for (d1, d2), c in zip(dot_pairs, pair_colors)
|
||||
]
|
||||
|
||||
for pair, line in zip(dot_pairs, diag_lines):
|
||||
self.play(
|
||||
FadeIn(line),
|
||||
pair.highlight, line.get_color(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user