mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
More clack animations
This commit is contained in:
parent
67ae6bf3a8
commit
10d64ec74e
1 changed files with 743 additions and 32 deletions
|
@ -14,6 +14,7 @@ class SlidingBlocks(VGroup):
|
|||
"distance": 7,
|
||||
"width": None,
|
||||
"color": None,
|
||||
"label_text": None,
|
||||
},
|
||||
"block2_config": {
|
||||
"mass": 1,
|
||||
|
@ -21,6 +22,7 @@ class SlidingBlocks(VGroup):
|
|||
"distance": 3,
|
||||
"width": None,
|
||||
"color": None,
|
||||
"label_text": None,
|
||||
},
|
||||
"block_style": {
|
||||
"fill_opacity": 1,
|
||||
|
@ -29,7 +31,8 @@ class SlidingBlocks(VGroup):
|
|||
"sheen_direction": UL,
|
||||
"sheen_factor": 0.5,
|
||||
"sheen_direction": UL,
|
||||
}
|
||||
},
|
||||
"collect_clack_data": True,
|
||||
}
|
||||
|
||||
def __init__(self, surrounding_scene, **kwargs):
|
||||
|
@ -48,13 +51,16 @@ class SlidingBlocks(VGroup):
|
|||
)
|
||||
self.add_updater(self.__class__.update_positions)
|
||||
|
||||
if self.collect_clack_data:
|
||||
self.clack_data = self.get_clack_data()
|
||||
|
||||
def get_block(self, mass, distance, velocity, width, color):
|
||||
def get_block(self, mass, distance, velocity, width, color, label_text):
|
||||
if width is None:
|
||||
width = self.mass_to_width(mass)
|
||||
if color is None:
|
||||
color = self.mass_to_color(mass)
|
||||
if label_text is None:
|
||||
label_text = "{:,}\\,kg".format(int(mass))
|
||||
block = Square(side_length=width)
|
||||
block.mass = mass
|
||||
block.velocity = velocity
|
||||
|
@ -68,9 +74,7 @@ class SlidingBlocks(VGroup):
|
|||
(self.wall.get_right()[0] + distance) * RIGHT,
|
||||
DL,
|
||||
)
|
||||
label = block.label = TextMobject(
|
||||
"{:,}\\,kg".format(int(mass))
|
||||
)
|
||||
label = block.label = TextMobject(label_text)
|
||||
label.scale(0.8)
|
||||
label.next_to(block, UP, SMALL_BUFF)
|
||||
block.add(label)
|
||||
|
@ -254,26 +258,42 @@ class ClackFlashes(ContinualAnimation):
|
|||
|
||||
class BlocksAndWallScene(Scene):
|
||||
CONFIG = {
|
||||
"include_sound_file": True,
|
||||
"include_sound": True,
|
||||
"count_clacks": True,
|
||||
"counter_group_shift_vect": LEFT,
|
||||
"sliding_blocks_config": {},
|
||||
"floor_y": -2,
|
||||
"wall_x": -6,
|
||||
"n_wall_ticks": 15,
|
||||
"counter_label": "\\# Collisions: ",
|
||||
"collision_sound": "clack.wav",
|
||||
"show_flash_animations": True,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
self.floor = self.get_floor()
|
||||
self.wall = self.get_wall()
|
||||
self.blocks = SlidingBlocks(self, **self.sliding_blocks_config)
|
||||
self.clack_data = self.blocks.clack_data
|
||||
self.clack_flashes = ClackFlashes(self.clack_data)
|
||||
self.add(self.floor, self.wall, self.blocks, self.clack_flashes)
|
||||
self.track_time()
|
||||
self.add_floor_and_wall()
|
||||
self.add_blocks()
|
||||
if self.show_flash_animations:
|
||||
self.add_flash_animations()
|
||||
|
||||
if self.count_clacks:
|
||||
self.add_counter()
|
||||
self.track_time()
|
||||
|
||||
def add_floor_and_wall(self):
|
||||
self.floor = self.get_floor()
|
||||
self.wall = self.get_wall()
|
||||
self.add(self.floor, self.wall)
|
||||
|
||||
def add_blocks(self):
|
||||
self.blocks = SlidingBlocks(self, **self.sliding_blocks_config)
|
||||
if hasattr(self.blocks, "clack_data"):
|
||||
self.clack_data = self.blocks.clack_data
|
||||
self.add(self.blocks)
|
||||
|
||||
def add_flash_animations(self):
|
||||
self.clack_flashes = ClackFlashes(self.clack_data)
|
||||
self.add(self.clack_flashes)
|
||||
|
||||
def track_time(self):
|
||||
time_tracker = ValueTracker()
|
||||
|
@ -289,13 +309,13 @@ class BlocksAndWallScene(Scene):
|
|||
counter_label[-1], RIGHT,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
clack_group = VGroup(
|
||||
counter_group = VGroup(
|
||||
counter_label,
|
||||
counter_mob,
|
||||
)
|
||||
clack_group.to_corner(UR)
|
||||
clack_group.shift(LEFT)
|
||||
self.add(clack_group)
|
||||
counter_group.to_corner(UR)
|
||||
counter_group.shift(self.counter_group_shift_vect)
|
||||
self.add(counter_group)
|
||||
|
||||
self.counter_mob = counter_mob
|
||||
|
||||
|
@ -304,7 +324,7 @@ class BlocksAndWallScene(Scene):
|
|||
wall.shift(self.wall_x * RIGHT)
|
||||
lines = VGroup(*[
|
||||
Line(ORIGIN, 0.25 * UR)
|
||||
for x in range(15)
|
||||
for x in range(self.n_wall_ticks)
|
||||
])
|
||||
lines.set_stroke(width=1)
|
||||
lines.arrange_submobjects(UP, buff=MED_SMALL_BUFF)
|
||||
|
@ -358,7 +378,7 @@ class BlocksAndWallScene(Scene):
|
|||
|
||||
def close_movie_pipe(self):
|
||||
Scene.close_movie_pipe(self)
|
||||
if self.include_sound_file:
|
||||
if self.include_sound:
|
||||
sound_file_path = self.create_sound_file(self.clack_data)
|
||||
movie_path = self.get_movie_file_path()
|
||||
temp_path = self.get_movie_file_path(str(self) + "TempSound")
|
||||
|
@ -452,16 +472,78 @@ class MathAndPhysicsConspiring(Scene):
|
|||
return result
|
||||
|
||||
|
||||
class LightBouncing(Scene):
|
||||
class LightBouncing(MovingCameraScene):
|
||||
CONFIG = {
|
||||
"theta": np.arctan(0.1)
|
||||
"theta": np.arctan(0.15),
|
||||
"show_fanning": False,
|
||||
"mirror_shift_vect": 5 * LEFT,
|
||||
"mirror_length": 10,
|
||||
"beam_start_x": 12,
|
||||
"beam_height": 1,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
pass
|
||||
theta = self.theta
|
||||
h_line = Line(ORIGIN, self.mirror_length * RIGHT)
|
||||
d_line = h_line.copy().rotate(theta, about_point=ORIGIN)
|
||||
mirrors = VGroup(h_line, d_line)
|
||||
self.add(mirrors)
|
||||
|
||||
beam_height = self.beam_height
|
||||
start_point = self.beam_start_x * RIGHT + beam_height * UP
|
||||
points = [start_point] + [
|
||||
np.array([
|
||||
(beam_height / np.tan(k * theta)),
|
||||
beam_height,
|
||||
0,
|
||||
])
|
||||
for k in range(1, int(PI / theta))
|
||||
] + [rotate(start_point, PI, UP)]
|
||||
reflected_points = []
|
||||
for k, point in enumerate(points):
|
||||
reflected_point = rotate_vector(point, -2 * (k // 2) * theta)
|
||||
reflected_point[1] = abs(reflected_point[1])
|
||||
reflected_points.append(reflected_point)
|
||||
beam = VMobject()
|
||||
beam.set_points_as_corners(reflected_points)
|
||||
beam.set_stroke(YELLOW, 2)
|
||||
|
||||
anims = [self.get_beam_anim(beam)]
|
||||
|
||||
if self.show_fanning:
|
||||
for k in range(2, int(PI / theta) + 1):
|
||||
line = h_line.copy()
|
||||
line.set_stroke(WHITE, 1)
|
||||
line.rotate(k * theta, about_point=ORIGIN)
|
||||
self.add(line)
|
||||
straight_beam = VMobject()
|
||||
straight_beam.set_points_as_corners(points)
|
||||
straight_beam.set_stroke(YELLOW, 2)
|
||||
anims.append(self.get_beam_anim(straight_beam))
|
||||
|
||||
self.camera_frame.shift(-self.mirror_shift_vect)
|
||||
self.play(*anims)
|
||||
self.wait()
|
||||
|
||||
def get_beam_anim(self, beam):
|
||||
dot = Dot()
|
||||
dot.scale(0.5)
|
||||
dot.match_color(beam)
|
||||
return AnimationGroup(
|
||||
ShowPassingFlash(
|
||||
beam,
|
||||
run_time=5,
|
||||
rate_func=lambda t: smooth(t, 5),
|
||||
time_width=0.05,
|
||||
),
|
||||
UpdateFromFunc(
|
||||
dot,
|
||||
lambda m: m.move_to(beam.points[-1])
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class BlocksAndWallExampleSameMass(BlocksAndWallScene):
|
||||
class BlocksAndWallExample(BlocksAndWallScene):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -476,7 +558,7 @@ class BlocksAndWallExampleSameMass(BlocksAndWallScene):
|
|||
self.wait(self.wait_time)
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e1(BlocksAndWallExampleSameMass):
|
||||
class BlocksAndWallExampleMass1e1(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -488,7 +570,113 @@ class BlocksAndWallExampleMass1e1(BlocksAndWallExampleSameMass):
|
|||
}
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e2(BlocksAndWallExampleSameMass):
|
||||
class CowToSphere(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
|
||||
class NoFrictionLabel(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Frictionless")
|
||||
words.shift(2 * RIGHT)
|
||||
words.add_updater(
|
||||
lambda m, dt: m.shift(dt * LEFT)
|
||||
)
|
||||
|
||||
self.play(VFadeIn(words))
|
||||
self.wait(2)
|
||||
self.play(VFadeOut(words))
|
||||
|
||||
|
||||
class Mass1e1WithElasticLabel(BlocksAndWallExampleMass1e1):
|
||||
def add_flash_animations(self):
|
||||
super().add_flash_animations()
|
||||
flashes = self.clack_flashes
|
||||
label = TextMobject(
|
||||
"Purely elastic collisions\\\\"
|
||||
"(no energy lost)"
|
||||
)
|
||||
label.set_color(YELLOW)
|
||||
label.move_to(2 * LEFT + 2 * UP)
|
||||
self.add(label)
|
||||
self.add(*[
|
||||
self.get_arrow(label, flashes, flash)
|
||||
for flash in flashes.flashes
|
||||
])
|
||||
|
||||
def get_arrow(self, label, clack_flashes, flash):
|
||||
arrow = Arrow(
|
||||
label.get_bottom(),
|
||||
flash.mobject.get_center() + 0.5 * UP,
|
||||
)
|
||||
arrow.set_fill(YELLOW)
|
||||
|
||||
def set_opacity(arrow):
|
||||
time = self.get_time()
|
||||
from_start = time - flash.start_time
|
||||
if from_start < 0:
|
||||
opacity = 0
|
||||
else:
|
||||
opacity = smooth(1 - from_start)
|
||||
arrow.set_fill(opacity=opacity)
|
||||
|
||||
arrow.add_updater(set_opacity)
|
||||
return arrow
|
||||
|
||||
|
||||
class AskAboutSoundlessness(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Wait, elastic collisions should\\\\"
|
||||
"make no sound, right?",
|
||||
)
|
||||
self.play(self.teacher.change, "guilty")
|
||||
self.wait(2)
|
||||
self.play(
|
||||
RemovePiCreatureBubble(self.students[1], target_mode="confused"),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
added_anims=[
|
||||
self.get_student_changes("pondering", "confused", "thinking")
|
||||
]
|
||||
)
|
||||
self.look_at(self.screen)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class ShowCreationRect(Scene):
|
||||
def construct(self):
|
||||
rect = SurroundingRectangle(TextMobject("\\# Collisions: 3"))
|
||||
self.play(ShowCreation(rect))
|
||||
self.play(FadeOut(rect))
|
||||
self.wait()
|
||||
|
||||
|
||||
class BlocksAndWallExampleSameMass(BlocksAndWallExample):
|
||||
pass
|
||||
|
||||
|
||||
class ShowLeftArrow(Scene):
|
||||
def construct(self):
|
||||
arrow = Vector(2 * LEFT, color=RED)
|
||||
self.play(GrowArrow(arrow))
|
||||
self.wait()
|
||||
self.play(FadeOut(arrow))
|
||||
|
||||
|
||||
class AskWhatWillHappen(PiCreatureScene):
|
||||
def construct(self):
|
||||
morty = self.pi_creature
|
||||
morty.set_color(GREY_BROWN)
|
||||
|
||||
self.pi_creature_says(
|
||||
"What will\\\\"
|
||||
"happen?",
|
||||
target_mode="maybe",
|
||||
look_at_arg=4 * DR,
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e2(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -500,7 +688,7 @@ class BlocksAndWallExampleMass1e2(BlocksAndWallExampleSameMass):
|
|||
}
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e4(BlocksAndWallExampleSameMass):
|
||||
class BlocksAndWallExampleMass1e4(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -512,7 +700,7 @@ class BlocksAndWallExampleMass1e4(BlocksAndWallExampleSameMass):
|
|||
}
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e4SlowMo(BlocksAndWallExampleSameMass):
|
||||
class BlocksAndWallExampleMass1e4SlowMo(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -526,7 +714,15 @@ class BlocksAndWallExampleMass1e4SlowMo(BlocksAndWallExampleSameMass):
|
|||
}
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e6(BlocksAndWallExampleSameMass):
|
||||
class SlowMotionLabel(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Slow motion replay")
|
||||
words.scale(2).to_edge(UP)
|
||||
self.play(Write(words))
|
||||
self.wait()
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e6(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -538,7 +734,7 @@ class BlocksAndWallExampleMass1e6(BlocksAndWallExampleSameMass):
|
|||
}
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e6SlowMo(BlocksAndWallExampleSameMass):
|
||||
class BlocksAndWallExampleMass1e6SlowMo(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -552,7 +748,7 @@ class BlocksAndWallExampleMass1e6SlowMo(BlocksAndWallExampleSameMass):
|
|||
}
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e8(BlocksAndWallExampleSameMass):
|
||||
class BlocksAndWallExampleMass1e8(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -564,7 +760,7 @@ class BlocksAndWallExampleMass1e8(BlocksAndWallExampleSameMass):
|
|||
}
|
||||
|
||||
|
||||
class BlocksAndWallExampleMass1e10(BlocksAndWallExampleSameMass):
|
||||
class BlocksAndWallExampleMass1e10(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
|
@ -574,3 +770,518 @@ class BlocksAndWallExampleMass1e10(BlocksAndWallExampleSameMass):
|
|||
},
|
||||
"wait_time": 25,
|
||||
}
|
||||
|
||||
|
||||
class GalperinPaperScroll(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
|
||||
class PiComputingAlgorithmsAxes(Scene):
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.add_methods()
|
||||
|
||||
def setup_axes(self):
|
||||
axes = Axes(
|
||||
x_min=0,
|
||||
y_min=0,
|
||||
x_max=9,
|
||||
y_max=5,
|
||||
number_line_config={
|
||||
"tick_frequency": 100,
|
||||
"numbers_with_elongated_ticks": [],
|
||||
}
|
||||
)
|
||||
|
||||
y_label = TextMobject("Efficiency")
|
||||
y_label.rotate(90 * DEGREES)
|
||||
y_label.next_to(axes.y_axis, LEFT, SMALL_BUFF)
|
||||
x_label = TextMobject("Elegance")
|
||||
x_label.next_to(axes.x_axis, DOWN, SMALL_BUFF)
|
||||
axes.add(y_label, x_label)
|
||||
axes.center().to_edge(DOWN)
|
||||
self.axes = axes
|
||||
|
||||
title = TextMobject("Algorithms for computing $\\pi$")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
|
||||
self.add(title, axes)
|
||||
|
||||
def add_methods(self):
|
||||
method_location_list = [
|
||||
(self.get_machin_like_formula(), (1, 4.5)),
|
||||
(self.get_viete(), (3, 3.5)),
|
||||
(self.get_measuring_tape(), (0.5, 1)),
|
||||
(self.get_monte_carlo(), (2, 0.2)),
|
||||
(self.get_basel(), (6, 1)),
|
||||
(self.get_blocks_image(), (8, 0.1)),
|
||||
]
|
||||
|
||||
algorithms = VGroup()
|
||||
for method, location in method_location_list:
|
||||
cross = TexMobject("\\times")
|
||||
cross.set_color(RED)
|
||||
cross.move_to(self.axes.coords_to_point(*location))
|
||||
method.next_to(cross, UP, SMALL_BUFF)
|
||||
method.align_to(cross, LEFT)
|
||||
method.shift_onto_screen()
|
||||
algorithms.add(VGroup(method, cross))
|
||||
|
||||
self.play(LaggedStart(
|
||||
FadeInFromDown, algorithms,
|
||||
run_time=4,
|
||||
lag_ratio=0.4,
|
||||
))
|
||||
self.wait()
|
||||
self.play(CircleThenFadeAround(algorithms[-1][0]))
|
||||
|
||||
def get_machin_like_formula(self):
|
||||
formula = TexMobject(
|
||||
"\\frac{\\pi}{4} = "
|
||||
"12\\arctan\\left(\\frac{1}{49}\\right) + "
|
||||
"32\\arctan\\left(\\frac{1}{57}\\right) - "
|
||||
"5\\arctan\\left(\\frac{1}{239}\\right) + "
|
||||
"12\\arctan\\left(\\frac{1}{110{,}443}\\right)"
|
||||
)
|
||||
formula.scale(0.5)
|
||||
return formula
|
||||
|
||||
def get_viete(self):
|
||||
formula = TexMobject(
|
||||
"\\frac{2}{\\pi} = "
|
||||
"\\frac{\\sqrt{2}}{2} \\cdot"
|
||||
"\\frac{\\sqrt{2 + \\sqrt{2}}}{2} \\cdot"
|
||||
"\\frac{\\sqrt{2 + \\sqrt{2 + \\sqrt{2}}}}{2} \\cdots"
|
||||
)
|
||||
formula.scale(0.5)
|
||||
return formula
|
||||
|
||||
def get_measuring_tape(self):
|
||||
return TextMobject("Measuring tape").scale(0.75)
|
||||
|
||||
def get_monte_carlo(self):
|
||||
return TextMobject("Monte Carlo").scale(0.75)
|
||||
|
||||
def get_basel(self):
|
||||
formula = TexMobject(
|
||||
"\\frac{\\pi^2}{6} = "
|
||||
"\\sum_{n=1}^\\infty \\frac{1}{n^2}"
|
||||
)
|
||||
formula.scale(0.5)
|
||||
return formula
|
||||
|
||||
def get_blocks_image(self):
|
||||
scene = BlocksAndWallScene(
|
||||
write_to_movie=False,
|
||||
skip_animations=True,
|
||||
count_clacks=False,
|
||||
floor_y=1,
|
||||
wall_x=0,
|
||||
n_wall_ticks=6,
|
||||
sliding_blocks_config={
|
||||
"block1_config": {
|
||||
"mass": 1e2,
|
||||
"velocity": -0.01,
|
||||
"distance": 3.5
|
||||
},
|
||||
"block2_config": {
|
||||
"distance": 1,
|
||||
"velocity": 0,
|
||||
},
|
||||
}
|
||||
)
|
||||
group = VGroup(
|
||||
scene.wall, scene.floor,
|
||||
scene.blocks.block1,
|
||||
scene.blocks.block2,
|
||||
)
|
||||
group.set_width(3)
|
||||
return group
|
||||
|
||||
|
||||
class StepsOfTheAlgorithm(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
steps = VGroup(
|
||||
TextMobject("Step 1:", "Implement a physics engine"),
|
||||
TextMobject(
|
||||
"Step 2:",
|
||||
"Choose the number of digits, $d$,\\\\"
|
||||
"of $\\pi$ that you want to compute"
|
||||
),
|
||||
TextMobject(
|
||||
"Step 3:",
|
||||
"Set one mass to $100^{d - 1}$, the other to $1$"
|
||||
),
|
||||
TextMobject("Step 4:", "Count collisions"),
|
||||
)
|
||||
steps.arrange_submobjects(
|
||||
DOWN,
|
||||
buff=MED_LARGE_BUFF,
|
||||
aligned_edge=LEFT,
|
||||
)
|
||||
steps.to_corner(UL)
|
||||
steps.scale(0.8)
|
||||
|
||||
for step in steps:
|
||||
self.play(
|
||||
FadeInFromDown(step[0]),
|
||||
self.teacher.change, "raise_right_hand"
|
||||
)
|
||||
self.play(
|
||||
Write(step[1], run_time=2),
|
||||
self.get_student_changes(
|
||||
*["pondering"] * 3,
|
||||
look_at_arg=step,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
self.change_student_modes(
|
||||
"sassy", "erm", "confused",
|
||||
look_at_arg=steps,
|
||||
added_anims=[self.teacher.change, "happy"]
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class CompareToGalacticMass(Scene):
|
||||
def construct(self):
|
||||
self.add_digits_of_pi()
|
||||
self.show_mass()
|
||||
self.show_galactic_black_holes()
|
||||
self.show_total_count()
|
||||
|
||||
def add_digits_of_pi(self):
|
||||
# 20 digits of pi
|
||||
digits = TexMobject("3.1415926535897932384...")
|
||||
digits.set_width(FRAME_WIDTH - 3)
|
||||
digits.to_edge(UP)
|
||||
|
||||
highlighted_digits = VGroup(*[
|
||||
d.copy().set_background_stroke(color=BLUE, width=5)
|
||||
for d in [digits[0], *digits[2:-3]]
|
||||
])
|
||||
counter = Integer(0)
|
||||
counter.scale(1.5)
|
||||
counter.set_color(BLUE)
|
||||
brace = VMobject()
|
||||
self.add(counter, brace)
|
||||
|
||||
for k in range(len(highlighted_digits)):
|
||||
if k == 0:
|
||||
self.add(digits[0])
|
||||
else:
|
||||
self.remove(highlighted_digits[k - 1])
|
||||
self.add(digits[k + 1])
|
||||
self.add(highlighted_digits[k])
|
||||
counter.increment_value()
|
||||
brace.become(Brace(highlighted_digits[:k + 1], DOWN))
|
||||
counter.next_to(brace, DOWN)
|
||||
self.wait(0.1)
|
||||
self.add(digits)
|
||||
self.remove(*highlighted_digits)
|
||||
|
||||
digits_word = TextMobject("digits")
|
||||
digits_word.scale(1.5)
|
||||
digits_word.match_color(counter)
|
||||
counter.generate_target()
|
||||
group = VGroup(counter.target, digits_word)
|
||||
group.arrange_submobjects(
|
||||
RIGHT,
|
||||
index_of_submobject_to_align=0,
|
||||
aligned_edge=DOWN,
|
||||
buff=0.7,
|
||||
)
|
||||
group.next_to(brace, DOWN)
|
||||
self.play(
|
||||
MoveToTarget(counter),
|
||||
FadeInFrom(digits_word, LEFT),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.pi_digits_group = VGroup(
|
||||
digits, brace, counter, digits_word
|
||||
)
|
||||
|
||||
def show_mass(self):
|
||||
bw_scene = BlocksAndWallExample(
|
||||
write_to_movie=False,
|
||||
skip_animations=True,
|
||||
count_clacks=False,
|
||||
show_flash_animations=False,
|
||||
floor_y=0,
|
||||
wall_x=-2,
|
||||
n_wall_ticks=8,
|
||||
sliding_blocks_config={
|
||||
"block1_config": {
|
||||
"mass": 1e6,
|
||||
"velocity": -0.01,
|
||||
"distance": 4.5,
|
||||
"label_text": "$100^{(20 - 1)}$ kg",
|
||||
"color": BLACK,
|
||||
},
|
||||
"block2_config": {
|
||||
"distance": 1,
|
||||
"velocity": 0,
|
||||
},
|
||||
}
|
||||
)
|
||||
block1 = bw_scene.blocks.block1
|
||||
block2 = bw_scene.blocks.block2
|
||||
group = VGroup(
|
||||
bw_scene.wall, bw_scene.floor,
|
||||
block1, block2
|
||||
)
|
||||
group.center()
|
||||
group.to_edge(DOWN)
|
||||
|
||||
arrow = Vector(2 * LEFT, color=RED)
|
||||
arrow.shift(block1.get_center())
|
||||
group.add(arrow)
|
||||
|
||||
brace = Brace(block1.label[:-2], UP, buff=SMALL_BUFF)
|
||||
number_words = TextMobject(
|
||||
"100", *["billion"] * 4,
|
||||
)
|
||||
number_words.next_to(brace, UP, buff=SMALL_BUFF)
|
||||
VGroup(brace, number_words).set_color(YELLOW)
|
||||
|
||||
self.play(Write(group))
|
||||
self.wait()
|
||||
last_word = number_words[0].copy()
|
||||
last_word.next_to(brace, UP, SMALL_BUFF)
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
FadeInFromDown(last_word),
|
||||
)
|
||||
for k in range(1, len(number_words) + 1):
|
||||
self.remove(last_word)
|
||||
last_word = number_words[:k].copy()
|
||||
last_word.next_to(brace, UP, SMALL_BUFF)
|
||||
self.add(last_word)
|
||||
self.wait(0.4)
|
||||
self.wait()
|
||||
self.remove(last_word)
|
||||
self.add(number_words)
|
||||
group.add(brace, number_words)
|
||||
self.play(group.to_corner, DL)
|
||||
|
||||
self.block1 = block1
|
||||
self.block2 = block2
|
||||
self.block_setup_group = group
|
||||
|
||||
def show_galactic_black_holes(self):
|
||||
black_hole = SVGMobject(file_name="black_hole")
|
||||
black_hole.set_color(BLACK)
|
||||
black_hole.set_sheen(0.2, UL)
|
||||
black_hole.set_height(1)
|
||||
black_holes = VGroup(*[
|
||||
black_hole.copy() for k in range(10)
|
||||
])
|
||||
black_holes.arrange_submobjects_in_grid(5, 2)
|
||||
black_holes.to_corner(DR)
|
||||
random.shuffle(black_holes.submobjects)
|
||||
for bh in black_holes:
|
||||
bh.save_state()
|
||||
bh.scale(3)
|
||||
bh.set_fill(DARK_GREY, 0)
|
||||
|
||||
equals = TexMobject("=")
|
||||
equals.scale(2)
|
||||
equals.next_to(self.block1, RIGHT)
|
||||
|
||||
words = TextMobject("10x Sgr A$^*$ \\\\ supermassive \\\\ black hole")
|
||||
words.next_to(equals, RIGHT)
|
||||
self.add(words)
|
||||
|
||||
self.play(
|
||||
Write(equals),
|
||||
Write(words),
|
||||
LaggedStart(
|
||||
Restore, black_holes,
|
||||
run_time=3
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.black_hole_words = VGroup(equals, words)
|
||||
self.black_holes = black_holes
|
||||
|
||||
def show_total_count(self):
|
||||
digits = self.pi_digits_group[0]
|
||||
to_fade = self.pi_digits_group[1:]
|
||||
tex_string = "{:,}".format(31415926535897932384)
|
||||
number = TexMobject(tex_string)
|
||||
number.scale(1.5)
|
||||
number.to_edge(UP)
|
||||
|
||||
commas = VGroup(*[
|
||||
mob
|
||||
for c, mob in zip(tex_string, number)
|
||||
if c is ","
|
||||
])
|
||||
dots = VGroup(*[
|
||||
mob
|
||||
for c, mob in zip(digits.get_tex_string(), digits)
|
||||
if c is "."
|
||||
])
|
||||
|
||||
self.play(FadeOut(to_fade))
|
||||
self.play(
|
||||
ReplacementTransform(
|
||||
VGroup(*filter(lambda m: m not in dots, digits)),
|
||||
VGroup(*filter(lambda m: m not in commas, number)),
|
||||
),
|
||||
ReplacementTransform(
|
||||
dots, commas,
|
||||
submobject_mode="lagged_start",
|
||||
run_time=2
|
||||
)
|
||||
)
|
||||
|
||||
group0 = number[:2].copy()
|
||||
group1 = number[3:3 + 9 + 2].copy()
|
||||
group2 = number[-(9 + 2):].copy()
|
||||
for group in group0, group1, group2:
|
||||
group.set_background_stroke(color=BLUE, width=5)
|
||||
self.add(group)
|
||||
self.wait(0.5)
|
||||
self.remove(group)
|
||||
|
||||
|
||||
class BlocksAndWallExampleGalacticMass(BlocksAndWallExample):
|
||||
CONFIG = {
|
||||
"sliding_blocks_config": {
|
||||
"block1_config": {
|
||||
"mass": 1e10,
|
||||
"velocity": -1,
|
||||
"label_text": "$100^{(20 - 1)}$\\,kg",
|
||||
"width": 2,
|
||||
},
|
||||
},
|
||||
"wait_time": 25,
|
||||
"counter_group_shift_vect": 5 * LEFT,
|
||||
"count_clacks": False,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
super().setup()
|
||||
words = TextMobject(
|
||||
"Burst of $10^{38}$ clacks per second"
|
||||
)
|
||||
words.scale(1.5)
|
||||
words.to_edge(UP)
|
||||
self.add(words)
|
||||
|
||||
|
||||
class CompareAlgorithmToPhysics(PiCreatureScene):
|
||||
def construct(self):
|
||||
morty = self.pi_creature
|
||||
right_pic = ImageMobject(
|
||||
self.get_image_file_path().replace(
|
||||
str(self), "PiComputingAlgorithmsAxes"
|
||||
)
|
||||
)
|
||||
right_rect = SurroundingRectangle(right_pic, buff=0, color=WHITE)
|
||||
right_pic.add(right_rect)
|
||||
right_pic.set_height(3)
|
||||
right_pic.next_to(morty, UR)
|
||||
right_pic.shift_onto_screen()
|
||||
|
||||
left_rect = right_rect.copy()
|
||||
left_rect.next_to(morty, UL)
|
||||
left_rect.shift_onto_screen()
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(right_pic),
|
||||
morty.change, "raise_right_hand",
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(left_rect),
|
||||
morty.change, "raise_left_hand",
|
||||
)
|
||||
self.wait()
|
||||
|
||||
digits = TexMobject("3.141592653589793238462643383279502884197...")
|
||||
digits.set_width(FRAME_WIDTH - 1)
|
||||
digits.to_edge(UP)
|
||||
self.play(
|
||||
FadeOutAndShift(right_pic, 5 * RIGHT),
|
||||
# FadeOutAndShift(left_rect, 5 * LEFT),
|
||||
FadeOut(left_rect),
|
||||
PiCreatureBubbleIntroduction(
|
||||
morty, "This doesn't seem \\\\ like me...",
|
||||
bubble_class=ThoughtBubble,
|
||||
bubble_kwargs={"direction": LEFT},
|
||||
target_mode="pondering",
|
||||
look_at_arg=left_rect,
|
||||
),
|
||||
LaggedStart(
|
||||
FadeInFrom, digits,
|
||||
lambda m: (m, LEFT),
|
||||
run_time=5,
|
||||
lag_ratio=0.2,
|
||||
)
|
||||
)
|
||||
self.blink()
|
||||
self.wait()
|
||||
self.play(morty.change, "confused", left_rect)
|
||||
self.wait(5)
|
||||
|
||||
def create_pi_creature(self):
|
||||
return Mortimer().flip().to_edge(DOWN)
|
||||
|
||||
|
||||
class AskAboutWhy(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
circle = Circle(radius=2, color=YELLOW)
|
||||
circle.next_to(self.teacher, UL)
|
||||
ke_conservation = TexMobject(
|
||||
"\\frac{1}{2}m_1 v_1^2 + "
|
||||
"\\frac{1}{2}m_2 v_2^2 = \\text{const.}"
|
||||
)
|
||||
ke_conservation.move_to(circle)
|
||||
|
||||
self.student_says("But why?")
|
||||
self.change_student_modes(
|
||||
"erm", "raise_left_hand", "sassy",
|
||||
added_anims=[self.teacher.change, "happy"]
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(circle),
|
||||
RemovePiCreatureBubble(self.students[1]),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
)
|
||||
self.change_all_student_modes(
|
||||
"pondering", look_at_arg=circle
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
Write(ke_conservation),
|
||||
circle.stretch, 1.5, 0,
|
||||
)
|
||||
self.change_all_student_modes("confused")
|
||||
self.look_at(circle)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class LightBouncingNoFanning(LightBouncing):
|
||||
CONFIG = {
|
||||
"mirror_shift_vect": 2 * DOWN,
|
||||
"mirror_length": 6,
|
||||
"beam_start_x": 8,
|
||||
"beam_height": 0.5,
|
||||
}
|
||||
|
||||
|
||||
class LightBouncingFanning(LightBouncingNoFanning):
|
||||
CONFIG = {
|
||||
"show_fanning": True,
|
||||
}
|
||||
|
||||
|
||||
class NextVideo(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
|
Loading…
Add table
Reference in a new issue