mirror of
https://github.com/3b1b/manim.git
synced 2025-09-19 04:41:56 +00:00
Updates to light-bouncing clack solution
This commit is contained in:
parent
c8c003ba4b
commit
dc24c03349
6 changed files with 714 additions and 64 deletions
|
@ -2,6 +2,9 @@
|
||||||
# from active_projects.clacks import solution1
|
# from active_projects.clacks import solution1
|
||||||
from active_projects.clacks.solution2 import block_collision_scenes
|
from active_projects.clacks.solution2 import block_collision_scenes
|
||||||
from active_projects.clacks.solution2 import simple_scenes
|
from active_projects.clacks.solution2 import simple_scenes
|
||||||
|
from active_projects.clacks.solution2 import wordy_scenes
|
||||||
|
from active_projects.clacks.solution2 import pi_creature_scenes
|
||||||
|
from active_projects.clacks.solution2 import position_phase_space
|
||||||
|
|
||||||
OUTPUT_DIRECTORY = "clacks_solution2"
|
OUTPUT_DIRECTORY = "clacks_solution2"
|
||||||
ALL_SCENE_CLASSES = [
|
ALL_SCENE_CLASSES = [
|
||||||
|
@ -12,4 +15,7 @@ ALL_SCENE_CLASSES = [
|
||||||
block_collision_scenes.IntroducePreviousTwoVideos,
|
block_collision_scenes.IntroducePreviousTwoVideos,
|
||||||
block_collision_scenes.PreviousTwoVideos,
|
block_collision_scenes.PreviousTwoVideos,
|
||||||
simple_scenes.TwoSolutionsWrapper,
|
simple_scenes.TwoSolutionsWrapper,
|
||||||
|
wordy_scenes.ConnectionToOptics,
|
||||||
|
pi_creature_scenes.OnAnsweringTwice,
|
||||||
|
position_phase_space.IntroducePositionPhaseSpace,
|
||||||
]
|
]
|
|
@ -1,6 +1,4 @@
|
||||||
from big_ol_pile_of_manim_imports import *
|
from big_ol_pile_of_manim_imports import *
|
||||||
import subprocess
|
|
||||||
from pydub import AudioSegment
|
|
||||||
|
|
||||||
|
|
||||||
class Block(Square):
|
class Block(Square):
|
||||||
|
@ -370,27 +368,6 @@ class BlocksAndWallScene(Scene):
|
||||||
if self.include_sound:
|
if self.include_sound:
|
||||||
self.add_clack_sounds(self.clack_data)
|
self.add_clack_sounds(self.clack_data)
|
||||||
|
|
||||||
# TODO, this no longer works
|
|
||||||
# should use Scene.add_sound instead
|
|
||||||
def combine_movie_files(self):
|
|
||||||
Scene.combine_movie_files(self)
|
|
||||||
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")
|
|
||||||
commands = [
|
|
||||||
"ffmpeg",
|
|
||||||
"-i", movie_path,
|
|
||||||
"-i", sound_file_path,
|
|
||||||
"-c:v", "copy", "-c:a", "aac",
|
|
||||||
'-loglevel', 'error',
|
|
||||||
"-strict", "experimental",
|
|
||||||
temp_path,
|
|
||||||
]
|
|
||||||
subprocess.call(commands)
|
|
||||||
subprocess.call(["rm", sound_file_path])
|
|
||||||
subprocess.call(["mv", temp_path, movie_path])
|
|
||||||
|
|
||||||
# Animated scenes
|
# Animated scenes
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,47 @@
|
||||||
from big_ol_pile_of_manim_imports import *
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
|
||||||
|
|
||||||
class NewSceneName(TeacherStudentsScene):
|
class OnAnsweringTwice(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass
|
question = TextMobject("Why $\\pi$?")
|
||||||
|
question.move_to(self.screen)
|
||||||
|
question.to_edge(UP)
|
||||||
|
other_questions = VGroup(
|
||||||
|
TextMobject("Frequency of collisions?"),
|
||||||
|
TextMobject("Efficient simulation?"),
|
||||||
|
TextMobject("Time until last collision?"),
|
||||||
|
)
|
||||||
|
for mob in other_questions:
|
||||||
|
mob.move_to(self.hold_up_spot, DOWN)
|
||||||
|
|
||||||
|
self.add(question)
|
||||||
|
|
||||||
|
self.student_says(
|
||||||
|
"But we already \\\\ solved it",
|
||||||
|
bubble_kwargs={"direction": LEFT},
|
||||||
|
target_mode="raise_left_hand",
|
||||||
|
added_anims=[self.teacher.change, "thinking"]
|
||||||
|
)
|
||||||
|
self.change_student_modes("sassy", "angry")
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
RemovePiCreatureBubble(self.students[2]),
|
||||||
|
self.get_student_changes("erm", "erm"),
|
||||||
|
ApplyMethod(
|
||||||
|
question.move_to, self.hold_up_spot, DOWN,
|
||||||
|
path_arc=-90 * DEGREES,
|
||||||
|
),
|
||||||
|
self.teacher.change, "raise_right_hand",
|
||||||
|
)
|
||||||
|
shown_questions = VGroup(question)
|
||||||
|
for oq in other_questions:
|
||||||
|
self.play(
|
||||||
|
shown_questions.shift, 0.85 * UP,
|
||||||
|
FadeInFromDown(oq),
|
||||||
|
self.get_student_changes(
|
||||||
|
*["pondering"] * 3,
|
||||||
|
look_at_arg=oq
|
||||||
|
)
|
||||||
|
)
|
||||||
|
shown_questions.add(oq)
|
||||||
|
self.wait(3)
|
||||||
|
|
464
active_projects/clacks/solution2/position_phase_space.py
Normal file
464
active_projects/clacks/solution2/position_phase_space.py
Normal file
|
@ -0,0 +1,464 @@
|
||||||
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
from active_projects.clacks.question import Block
|
||||||
|
from active_projects.clacks.question import Wall
|
||||||
|
|
||||||
|
|
||||||
|
class PositionPhaseSpaceScene(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"rescale_coordinates": True,
|
||||||
|
"wall_x": -6,
|
||||||
|
"wall_config": {
|
||||||
|
"height": 1.6,
|
||||||
|
"tick_spacing": 0.35,
|
||||||
|
"tick_length": 0.2,
|
||||||
|
},
|
||||||
|
"wall_height": 1.5,
|
||||||
|
"floor_y": -3.5,
|
||||||
|
"block1_config": {
|
||||||
|
"mass": 10,
|
||||||
|
"distance": 7,
|
||||||
|
"velocity": 1,
|
||||||
|
"width": 1.6,
|
||||||
|
},
|
||||||
|
"block2_config": {
|
||||||
|
"mass": 1,
|
||||||
|
"distance": 4,
|
||||||
|
},
|
||||||
|
"axes_config": {
|
||||||
|
"x_min": -0.5,
|
||||||
|
"x_max": 31,
|
||||||
|
"y_min": -0.5,
|
||||||
|
"y_max": 10.5,
|
||||||
|
"x_axis_config": {
|
||||||
|
"unit_size": 0.4,
|
||||||
|
"tick_frequency": 2,
|
||||||
|
},
|
||||||
|
"y_axis_config": {
|
||||||
|
"unit_size": 0.4,
|
||||||
|
"tick_frequency": 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"axes_center": 5 * LEFT + 0.65 * DOWN,
|
||||||
|
"ps_dot_config": {
|
||||||
|
"fill_color": RED,
|
||||||
|
"background_stroke_width": 1,
|
||||||
|
"background_stroke_color": BLACK,
|
||||||
|
"radius": 0.05,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.all_items = [
|
||||||
|
self.get_floor(),
|
||||||
|
self.get_wall(),
|
||||||
|
self.get_blocks(),
|
||||||
|
self.get_axes(),
|
||||||
|
self.get_phase_space_point(),
|
||||||
|
self.get_phase_space_x_line(),
|
||||||
|
self.get_phase_space_y_line(),
|
||||||
|
self.get_phase_space_dot(),
|
||||||
|
self.get_phase_space_d1_label(),
|
||||||
|
self.get_phase_space_d2_label(),
|
||||||
|
self.get_d1_brace(),
|
||||||
|
self.get_d2_brace(),
|
||||||
|
self.get_d1_label(),
|
||||||
|
self.get_d2_label(),
|
||||||
|
self.get_d1_eq_d2_line(),
|
||||||
|
self.get_d1_eq_d2_label(),
|
||||||
|
self.get_d2_eq_w2_line(),
|
||||||
|
self.get_d2_eq_w2_label(),
|
||||||
|
self.get_time_tracker(),
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_corner(self):
|
||||||
|
return self.wall_x * RIGHT + self.floor_y * UP
|
||||||
|
|
||||||
|
def get_mass_ratio(self):
|
||||||
|
return op.truediv(
|
||||||
|
self.block1.mass,
|
||||||
|
self.block2.mass,
|
||||||
|
)
|
||||||
|
|
||||||
|
def d1_to_x(self, d1):
|
||||||
|
if self.rescale_coordinates:
|
||||||
|
d1 *= np.sqrt(self.block1.mass)
|
||||||
|
return d1
|
||||||
|
|
||||||
|
def d2_to_y(self, d2):
|
||||||
|
if self.rescale_coordinates:
|
||||||
|
d2 *= np.sqrt(self.block2.mass)
|
||||||
|
return d2
|
||||||
|
|
||||||
|
def ds_to_point(self, d1, d2):
|
||||||
|
return self.axes.coords_to_point(
|
||||||
|
self.d1_to_x(d1), self.d2_to_y(d2),
|
||||||
|
)
|
||||||
|
|
||||||
|
def point_to_ds(self, point):
|
||||||
|
x, y = self.axes.point_to_coords(point)
|
||||||
|
if self.rescale_coordinates:
|
||||||
|
x /= np.sqrt(self.block1.mass)
|
||||||
|
y /= np.sqrt(self.block2.mass)
|
||||||
|
return (x, y)
|
||||||
|
|
||||||
|
def get_d1(self):
|
||||||
|
return self.get_ds()[0]
|
||||||
|
|
||||||
|
def get_d2(self):
|
||||||
|
return self.get_ds()[1]
|
||||||
|
|
||||||
|
def get_ds(self):
|
||||||
|
return self.point_to_ds(self.ps_point.get_location())
|
||||||
|
|
||||||
|
def tie_blocks_to_ps_point(self):
|
||||||
|
def update_blocks(blocks):
|
||||||
|
d1, d2 = self.point_to_ds(self.ps_point.get_location())
|
||||||
|
b1, b2 = blocks
|
||||||
|
corner = self.get_corner()
|
||||||
|
b1.move_to(corner + d1 * RIGHT, DL)
|
||||||
|
b2.move_to(corner + d2 * RIGHT, DR)
|
||||||
|
self.blocks.add_updater(update_blocks)
|
||||||
|
|
||||||
|
def time_to_ds(self, time):
|
||||||
|
# Deals in its own phase space, different
|
||||||
|
# from the one displayed
|
||||||
|
m1 = self.block1.mass
|
||||||
|
m2 = self.block2.mass
|
||||||
|
v1 = self.block1.velocity
|
||||||
|
# v2 = self.block2.velocity
|
||||||
|
d1 = self.block1_config["distance"]
|
||||||
|
d2 = self.block2_config["distance"]
|
||||||
|
w2 = self.block2.width
|
||||||
|
ps_speed = np.sqrt(m1) * abs(v1)
|
||||||
|
theta = np.arctan(np.sqrt(m2 / m1))
|
||||||
|
|
||||||
|
def ds_to_ps_point(d1, d2):
|
||||||
|
return np.array([
|
||||||
|
d1 * np.sqrt(m1),
|
||||||
|
d2 * np.sqrt(m2),
|
||||||
|
0
|
||||||
|
])
|
||||||
|
|
||||||
|
def ps_point_to_ds(point):
|
||||||
|
return (
|
||||||
|
point[0] / np.sqrt(m1),
|
||||||
|
point[1] / np.sqrt(m2),
|
||||||
|
)
|
||||||
|
|
||||||
|
ps_point = ds_to_ps_point(d1, d2 + w2)
|
||||||
|
wedge_corner = ds_to_ps_point(w2, w2)
|
||||||
|
ps_point -= wedge_corner
|
||||||
|
# Pass into the mirror worlds
|
||||||
|
ps_point += time * ps_speed * LEFT
|
||||||
|
# Reflect back to the real world
|
||||||
|
angle = angle_of_vector(ps_point)
|
||||||
|
n = int(angle / theta)
|
||||||
|
if n % 2 == 0:
|
||||||
|
ps_point = rotate_vector(ps_point, -n * theta)
|
||||||
|
else:
|
||||||
|
ps_point = rotate_vector(
|
||||||
|
ps_point,
|
||||||
|
-(n + 1) * theta,
|
||||||
|
)
|
||||||
|
ps_point[1] = abs(ps_point[1])
|
||||||
|
ps_point += wedge_corner
|
||||||
|
return ps_point_to_ds(ps_point)
|
||||||
|
|
||||||
|
def get_clack_flashes(self):
|
||||||
|
pass # TODO
|
||||||
|
|
||||||
|
# Mobject getters
|
||||||
|
def get_floor(self):
|
||||||
|
floor = self.floor = Line(
|
||||||
|
self.wall_x * RIGHT,
|
||||||
|
FRAME_WIDTH * RIGHT / 2,
|
||||||
|
stroke_color=WHITE,
|
||||||
|
stroke_width=3,
|
||||||
|
)
|
||||||
|
floor.move_to(self.get_corner(), LEFT)
|
||||||
|
return floor
|
||||||
|
|
||||||
|
def get_wall(self):
|
||||||
|
wall = self.wall = Wall(**self.wall_config)
|
||||||
|
wall.move_to(self.get_corner(), DR)
|
||||||
|
return wall
|
||||||
|
|
||||||
|
def get_blocks(self):
|
||||||
|
blocks = self.blocks = VGroup()
|
||||||
|
for n in [1, 2]:
|
||||||
|
config = getattr(self, "block{}_config".format(n))
|
||||||
|
block = Block(**config)
|
||||||
|
block.move_to(self.get_corner(), DL)
|
||||||
|
block.shift(config["distance"] * RIGHT)
|
||||||
|
block.label.move_to(block)
|
||||||
|
block.label.set_fill(BLACK)
|
||||||
|
block.label.set_stroke(WHITE, 3, background=True)
|
||||||
|
self.blocks.add(block)
|
||||||
|
self.block1, self.block2 = blocks
|
||||||
|
return blocks
|
||||||
|
|
||||||
|
def get_axes(self):
|
||||||
|
axes = self.axes = Axes(**self.axes_config)
|
||||||
|
axes.set_stroke(LIGHT_GREY, 2)
|
||||||
|
axes.shift(
|
||||||
|
self.axes_center - axes.coords_to_point(0, 0)
|
||||||
|
)
|
||||||
|
axes.add(self.get_axes_labels(axes))
|
||||||
|
return axes
|
||||||
|
|
||||||
|
def get_axes_labels(self, axes):
|
||||||
|
x_label = TexMobject("x = ", "d_1")
|
||||||
|
y_label = TexMobject("y = ", "d_2")
|
||||||
|
labels = VGroup(x_label, y_label)
|
||||||
|
if self.rescale_coordinates:
|
||||||
|
additions = map(TexMobject, [
|
||||||
|
"\\sqrt{m_1}", "\\sqrt{m_2}"
|
||||||
|
])
|
||||||
|
for label, addition in zip(labels, additions):
|
||||||
|
addition.move_to(label[1], DL)
|
||||||
|
label[1].next_to(
|
||||||
|
addition, RIGHT, SMALL_BUFF,
|
||||||
|
aligned_edge=DOWN
|
||||||
|
)
|
||||||
|
addition[2:].set_color(BLUE)
|
||||||
|
label.add(addition)
|
||||||
|
x_label.next_to(axes.x_axis.get_right(), DL, MED_SMALL_BUFF)
|
||||||
|
y_label.next_to(axes.y_axis.get_top(), DR, MED_SMALL_BUFF)
|
||||||
|
for label in labels:
|
||||||
|
label.shift_onto_screen()
|
||||||
|
return labels
|
||||||
|
|
||||||
|
def get_phase_space_point(self):
|
||||||
|
ps_point = self.ps_point = VectorizedPoint()
|
||||||
|
ps_point.move_to(self.ds_to_point(
|
||||||
|
self.block1.distance,
|
||||||
|
self.block2.distance + self.block2.width
|
||||||
|
))
|
||||||
|
self.tie_blocks_to_ps_point()
|
||||||
|
return ps_point
|
||||||
|
|
||||||
|
def get_phase_space_x_line(self):
|
||||||
|
def get_x_line():
|
||||||
|
origin = self.axes.coords_to_point(0, 0)
|
||||||
|
point = self.ps_point.get_location()
|
||||||
|
y_axis_point = np.array(origin)
|
||||||
|
y_axis_point[1] = point[1]
|
||||||
|
return DashedLine(
|
||||||
|
y_axis_point, point,
|
||||||
|
color=GREEN,
|
||||||
|
stroke_width=2,
|
||||||
|
)
|
||||||
|
self.x_line = updating_mobject_from_func(get_x_line)
|
||||||
|
return self.x_line
|
||||||
|
|
||||||
|
def get_phase_space_y_line(self):
|
||||||
|
def get_y_line():
|
||||||
|
origin = self.axes.coords_to_point(0, 0)
|
||||||
|
point = self.ps_point.get_location()
|
||||||
|
x_axis_point = np.array(origin)
|
||||||
|
x_axis_point[0] = point[0]
|
||||||
|
return DashedLine(
|
||||||
|
x_axis_point, point,
|
||||||
|
color=RED,
|
||||||
|
stroke_width=2,
|
||||||
|
)
|
||||||
|
self.y_line = updating_mobject_from_func(get_y_line)
|
||||||
|
return self.y_line
|
||||||
|
|
||||||
|
def get_phase_space_dot(self):
|
||||||
|
self.ps_dot = ps_dot = Dot(**self.ps_dot_config)
|
||||||
|
ps_dot.add_updater(lambda m: m.move_to(self.ps_point))
|
||||||
|
return ps_dot
|
||||||
|
|
||||||
|
def get_d_label(self, n, get_d):
|
||||||
|
label = VGroup(
|
||||||
|
TexMobject("d_{}".format(n), "="),
|
||||||
|
DecimalNumber(),
|
||||||
|
)
|
||||||
|
color = GREEN if n == 1 else RED
|
||||||
|
label[0].set_color_by_tex("d_", color)
|
||||||
|
label.scale(0.7)
|
||||||
|
|
||||||
|
def update_value(label):
|
||||||
|
lhs, rhs = label
|
||||||
|
rhs.set_value(get_d())
|
||||||
|
rhs.next_to(
|
||||||
|
lhs, RIGHT, SMALL_BUFF,
|
||||||
|
aligned_edge=DOWN,
|
||||||
|
)
|
||||||
|
label.add_updater(update_value)
|
||||||
|
return label
|
||||||
|
|
||||||
|
def get_phase_space_d_label(self, n, get_d, line, vect):
|
||||||
|
label = self.get_d_label(n, get_d)
|
||||||
|
label.add_updater(
|
||||||
|
lambda m: m.next_to(line, vect, SMALL_BUFF)
|
||||||
|
)
|
||||||
|
return label
|
||||||
|
|
||||||
|
def get_phase_space_d1_label(self):
|
||||||
|
self.ps_d1_label = self.get_phase_space_d_label(
|
||||||
|
1, self.get_d1, self.x_line, UP,
|
||||||
|
)
|
||||||
|
return self.ps_d1_label
|
||||||
|
|
||||||
|
def get_phase_space_d2_label(self):
|
||||||
|
self.ps_d2_label = self.get_phase_space_d_label(
|
||||||
|
2, self.get_d2, self.y_line, RIGHT,
|
||||||
|
)
|
||||||
|
return self.ps_d2_label
|
||||||
|
|
||||||
|
def get_d_brace(self, get_right_point):
|
||||||
|
line = Line(LEFT, RIGHT).set_width(6)
|
||||||
|
brace = Brace(line, UP)
|
||||||
|
|
||||||
|
def update_brace(brace):
|
||||||
|
right_point = get_right_point()
|
||||||
|
left_point = np.array(right_point)
|
||||||
|
left_point[0] = self.wall_x
|
||||||
|
line.put_start_and_end_on(left_point, right_point)
|
||||||
|
brace.match_width(line, stretch=True)
|
||||||
|
brace.next_to(line, UP, buff=0)
|
||||||
|
|
||||||
|
brace.add_updater(update_brace)
|
||||||
|
return brace
|
||||||
|
|
||||||
|
def get_d1_brace(self):
|
||||||
|
self.d1_brace = self.get_d_brace(
|
||||||
|
lambda: self.block1.get_corner(UL)
|
||||||
|
)
|
||||||
|
return self.d1_brace
|
||||||
|
|
||||||
|
def get_d2_brace(self):
|
||||||
|
self.d2_brace = self.get_d_brace(
|
||||||
|
lambda: self.block2.get_corner(UR)
|
||||||
|
)
|
||||||
|
# self.flip_brace_nip()
|
||||||
|
return self.d2_brace
|
||||||
|
|
||||||
|
def flip_brace_nip(self, brace):
|
||||||
|
nip_index = (len(brace) // 2) - 1
|
||||||
|
nip = brace[nip_index:nip_index + 2]
|
||||||
|
rect = brace[nip_index - 1]
|
||||||
|
center = rect.get_center()
|
||||||
|
center[0] = nip.get_center()[0]
|
||||||
|
nip.rotate(PI, about_point=center)
|
||||||
|
|
||||||
|
def get_brace_d_label(self, n, get_d, brace, vect):
|
||||||
|
label = self.get_d_label(n, get_d)
|
||||||
|
label.add_updater(
|
||||||
|
lambda m: m.next_to(brace, vect, 0)
|
||||||
|
)
|
||||||
|
return label
|
||||||
|
|
||||||
|
def get_d1_label(self):
|
||||||
|
self.d1_label = self.get_brace_d_label(
|
||||||
|
1, self.get_d1, self.d1_brace, UP
|
||||||
|
)
|
||||||
|
return self.d1_label
|
||||||
|
|
||||||
|
def get_d2_label(self):
|
||||||
|
self.d2_label = self.get_brace_d_label(
|
||||||
|
2, self.get_d2, self.d2_brace, UP
|
||||||
|
)
|
||||||
|
return self.d2_label
|
||||||
|
|
||||||
|
def get_d1_eq_d2_line(self):
|
||||||
|
start = self.ds_to_point(0, 0)
|
||||||
|
end = self.ds_to_point(15, 15)
|
||||||
|
self.d1_eq_d2_line = DashedLine(start, end)
|
||||||
|
self.d1_eq_d2_line.set_stroke(WHITE, 2)
|
||||||
|
return self.d1_eq_d2_line
|
||||||
|
|
||||||
|
def get_d1_eq_d2_label(self):
|
||||||
|
label = TexMobject("d1 = d2")
|
||||||
|
label.scale(0.75)
|
||||||
|
line = self.d1_eq_d2_line
|
||||||
|
for i in range(len(line)):
|
||||||
|
if line[i].get_top()[1] > FRAME_HEIGHT / 2:
|
||||||
|
break
|
||||||
|
label.next_to(line[i - 3], DR, SMALL_BUFF)
|
||||||
|
self.d1_eq_d2_label = label
|
||||||
|
return label
|
||||||
|
|
||||||
|
def get_d2_eq_w2_line(self):
|
||||||
|
w2 = self.block2.width
|
||||||
|
start = self.ds_to_point(0, w2)
|
||||||
|
end = self.ds_to_point(30, w2)
|
||||||
|
self.d2_eq_w2_line = DashedLine(start, end)
|
||||||
|
self.d2_eq_w2_line.set_stroke(WHITE, 2)
|
||||||
|
return self.d2_eq_w2_line
|
||||||
|
|
||||||
|
def get_d2_eq_w2_label(self):
|
||||||
|
label = TexMobject("d2 = \\text{block width}")
|
||||||
|
label.scale(0.75)
|
||||||
|
label.next_to(self.d2_eq_w2_line, UP, SMALL_BUFF)
|
||||||
|
label.to_edge(RIGHT, buff=MED_SMALL_BUFF)
|
||||||
|
self.d2_eq_w_label = label
|
||||||
|
return label
|
||||||
|
|
||||||
|
def get_time_tracker(self):
|
||||||
|
time_tracker = self.time_tracker = ValueTracker(0)
|
||||||
|
time_tracker.add_updater(
|
||||||
|
lambda m, dt: m.increment_value(dt)
|
||||||
|
)
|
||||||
|
self.get_time = time_tracker.get_value
|
||||||
|
self.add(time_tracker)
|
||||||
|
return time_tracker
|
||||||
|
|
||||||
|
|
||||||
|
class IntroducePositionPhaseSpace(PositionPhaseSpaceScene):
|
||||||
|
CONFIG = {
|
||||||
|
"rescale_coordinates": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.show_coordinates()
|
||||||
|
self.show_xy_line()
|
||||||
|
self.let_process_play_out()
|
||||||
|
|
||||||
|
self.add(*self.all_items)
|
||||||
|
self.ps_point.add_updater(
|
||||||
|
lambda m: m.move_to(self.ds_to_point(
|
||||||
|
*self.time_to_ds(self.get_time())
|
||||||
|
))
|
||||||
|
)
|
||||||
|
self.wait(10)
|
||||||
|
# self.play(Rotating(
|
||||||
|
# self.ps_point,
|
||||||
|
# about_point=self.ps_point.get_location() + RIGHT,
|
||||||
|
# run_time=3
|
||||||
|
# ))
|
||||||
|
|
||||||
|
def show_coordinates(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def show_xy_line(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def let_process_play_out(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EqualMassCase(IntroducePositionPhaseSpace):
|
||||||
|
def construct(self):
|
||||||
|
self.show_first_point()
|
||||||
|
self.up_to_first_collision()
|
||||||
|
self.ask_about_momentum_transfer()
|
||||||
|
self.up_to_second_collision()
|
||||||
|
self.up_to_third_collision()
|
||||||
|
|
||||||
|
def show_first_point(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def up_to_first_collision(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def ask_about_momentum_transfer(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def up_to_second_collision(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def up_to_third_collision(self):
|
||||||
|
pass
|
|
@ -7,42 +7,3 @@ class TwoSolutionsWrapper(Scene):
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ConnectionToOptics(Scene):
|
|
||||||
def construct(self):
|
|
||||||
e_group, m_group = k_groups = self.get_kinematics_groups()
|
|
||||||
|
|
||||||
self.add(k_groups)
|
|
||||||
|
|
||||||
def get_kinematics_groups(self):
|
|
||||||
tex_to_color_map = {
|
|
||||||
"m_1": BLUE,
|
|
||||||
"m_2": BLUE,
|
|
||||||
"v_1": RED,
|
|
||||||
"v_2": RED,
|
|
||||||
}
|
|
||||||
energy_eq = TexMobject(
|
|
||||||
"\\frac{1}{2} m_1 (v_1)^2 + "
|
|
||||||
"\\frac{1}{2} m_2 (v_2)^2 = "
|
|
||||||
"\\text{const.}",
|
|
||||||
tex_to_color_map=tex_to_color_map
|
|
||||||
)
|
|
||||||
momentum_eq = TexMobject(
|
|
||||||
"m_1 v_1 + m_2 v_2 = \\text{const.}",
|
|
||||||
tex_to_color_map=tex_to_color_map
|
|
||||||
)
|
|
||||||
energy_label = TextMobject(
|
|
||||||
"Conservation of energy"
|
|
||||||
)
|
|
||||||
momentum_label = TextMobject(
|
|
||||||
"Conservation of momentum"
|
|
||||||
)
|
|
||||||
energy_group = VGroup(energy_eq, energy_label)
|
|
||||||
momentum_group = VGroup(momentum_eq, momentum_label)
|
|
||||||
groups = VGroup(energy_group, momentum_group)
|
|
||||||
for group in groups:
|
|
||||||
group.arrange_submobjects(DOWN)
|
|
||||||
groups.arrange_submobjects(DOWN, LARGE_BUFF)
|
|
||||||
groups.to_edge(LEFT)
|
|
||||||
return groups
|
|
||||||
|
|
201
active_projects/clacks/solution2/wordy_scenes.py
Normal file
201
active_projects/clacks/solution2/wordy_scenes.py
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionToOptics(Scene):
|
||||||
|
def construct(self):
|
||||||
|
e_group, m_group = k_groups = self.get_kinematics_groups()
|
||||||
|
c_group, a_group = o_groups = self.get_optics_groups()
|
||||||
|
arrows = VGroup()
|
||||||
|
for g1, g2 in zip(k_groups, o_groups):
|
||||||
|
g2.align_to(g1, UP)
|
||||||
|
g2.to_edge(RIGHT)
|
||||||
|
arrow = TexMobject("\\Rightarrow")
|
||||||
|
arrow.scale(1.5)
|
||||||
|
arrow.move_to(interpolate(
|
||||||
|
g1[0].get_right(), g2[0].get_left(), 0.5
|
||||||
|
))
|
||||||
|
arrows.add(arrow)
|
||||||
|
everything = VGroup(k_groups, arrows, o_groups)
|
||||||
|
everything.to_edge(UP)
|
||||||
|
|
||||||
|
everything.generate_target()
|
||||||
|
everything.target.scale(0.9)
|
||||||
|
everything.target.to_edge(DOWN)
|
||||||
|
width = max([m.get_width() for m in everything.target])
|
||||||
|
width += 2 * MED_SMALL_BUFF
|
||||||
|
rects = VGroup()
|
||||||
|
for k in [0, 2]:
|
||||||
|
rect = DashedMobject(Rectangle(
|
||||||
|
height=FRAME_HEIGHT - 1.5,
|
||||||
|
width=width
|
||||||
|
), dashes_num=100)
|
||||||
|
rect.move_to(everything.target[k])
|
||||||
|
rect.to_edge(DOWN, buff=SMALL_BUFF)
|
||||||
|
rects.add(rect)
|
||||||
|
titles = VGroup(
|
||||||
|
TextMobject("Kinematics"),
|
||||||
|
TextMobject("Optics"),
|
||||||
|
)
|
||||||
|
titles.scale(1.5)
|
||||||
|
for title, rect in zip(titles, rects):
|
||||||
|
title.next_to(rect, UP)
|
||||||
|
titles[0].align_to(titles[1], UP)
|
||||||
|
|
||||||
|
self.play(FadeInFromDown(e_group))
|
||||||
|
self.play(
|
||||||
|
Write(arrows[0]),
|
||||||
|
FadeInFrom(c_group, LEFT)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(FadeInFromDown(m_group))
|
||||||
|
self.play(
|
||||||
|
Write(arrows[1]),
|
||||||
|
FadeInFrom(a_group, LEFT)
|
||||||
|
)
|
||||||
|
self.wait(4)
|
||||||
|
for k in range(2):
|
||||||
|
anims = [
|
||||||
|
ShowCreation(rects[k]),
|
||||||
|
FadeInFromDown(titles[k]),
|
||||||
|
]
|
||||||
|
if k == 0:
|
||||||
|
anims.append(MoveToTarget(everything))
|
||||||
|
self.play(*anims)
|
||||||
|
self.wait()
|
||||||
|
self.wait()
|
||||||
|
self.wait(4)
|
||||||
|
|
||||||
|
def get_kinematics_groups(self):
|
||||||
|
tex_to_color_map = {
|
||||||
|
"m_1": BLUE,
|
||||||
|
"m_2": BLUE,
|
||||||
|
"v_1": RED,
|
||||||
|
"v_2": RED,
|
||||||
|
}
|
||||||
|
energy_eq = TexMobject(
|
||||||
|
"\\frac{1}{2} m_1 (v_1)^2 + "
|
||||||
|
"\\frac{1}{2} m_2 (v_2)^2 = "
|
||||||
|
"\\text{const.}",
|
||||||
|
tex_to_color_map=tex_to_color_map
|
||||||
|
)
|
||||||
|
energy_eq.scale(0.8)
|
||||||
|
momentum_eq = TexMobject(
|
||||||
|
"m_1 v_1 + m_2 v_2 = \\text{const.}",
|
||||||
|
tex_to_color_map=tex_to_color_map
|
||||||
|
)
|
||||||
|
energy_label = TextMobject(
|
||||||
|
"Conservation of energy"
|
||||||
|
)
|
||||||
|
momentum_label = TextMobject(
|
||||||
|
"Conservation of momentum"
|
||||||
|
)
|
||||||
|
energy_group = VGroup(energy_label, energy_eq)
|
||||||
|
momentum_group = VGroup(momentum_label, momentum_eq)
|
||||||
|
groups = VGroup(energy_group, momentum_group)
|
||||||
|
for group in groups:
|
||||||
|
group.arrange_submobjects(DOWN, buff=MED_LARGE_BUFF)
|
||||||
|
group[0].set_color(GREEN)
|
||||||
|
groups.arrange_submobjects(DOWN, buff=2)
|
||||||
|
groups.to_edge(LEFT)
|
||||||
|
return groups
|
||||||
|
|
||||||
|
def get_optics_groups(self):
|
||||||
|
self.time_tracker = ValueTracker(0)
|
||||||
|
self.time_tracker.add_updater(
|
||||||
|
lambda m, dt: m.increment_value(dt)
|
||||||
|
)
|
||||||
|
self.add(self.time_tracker)
|
||||||
|
return VGroup(
|
||||||
|
self.get_speed_group(),
|
||||||
|
self.get_angle_group()
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_speed_group(self):
|
||||||
|
speed_label = TextMobject("Constant speed of light")
|
||||||
|
speed_label.set_color(YELLOW)
|
||||||
|
speed_light_template = Line(LEFT, RIGHT)
|
||||||
|
speed_light_template.fade(1)
|
||||||
|
speed_light_template.match_width(speed_label)
|
||||||
|
speed_light_template.next_to(speed_label, DOWN, MED_LARGE_BUFF)
|
||||||
|
speed_light = speed_light_template.deepcopy()
|
||||||
|
|
||||||
|
def update_speed_light(light, period=2, time_width=0.05):
|
||||||
|
time = self.time_tracker.get_value()
|
||||||
|
alpha = (time / period) % 1
|
||||||
|
# alpha = 1 - 2 * abs(alpha - 0.5)
|
||||||
|
alpha *= 1.5
|
||||||
|
a = alpha - time_width / 2
|
||||||
|
b = alpha + time_width / 2
|
||||||
|
light.pointwise_become_partial(
|
||||||
|
speed_light_template, max(a, 0), min(b, 1)
|
||||||
|
)
|
||||||
|
opacity = speed_label.family_members_with_points()[0].get_fill_opacity()
|
||||||
|
light.set_stroke(YELLOW, width=3, opacity=opacity)
|
||||||
|
# light.stretch(0.5, 0)
|
||||||
|
# point = speed_light_template.point_from_proportion(0.25)
|
||||||
|
# light.stretch(2, 0, about_point=point)
|
||||||
|
|
||||||
|
speed_light.add_updater(update_speed_light)
|
||||||
|
result = VGroup(
|
||||||
|
speed_label, speed_light_template, speed_light
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_angle_group(self):
|
||||||
|
title = VGroup(*map(TextMobject, [
|
||||||
|
"Angle of\\\\Incidence",
|
||||||
|
"=",
|
||||||
|
"Angle of\\\\Refraction",
|
||||||
|
])).arrange_submobjects(RIGHT)
|
||||||
|
title.set_color(YELLOW)
|
||||||
|
h_line = Line(LEFT, RIGHT)
|
||||||
|
h_line.match_width(title)
|
||||||
|
h_line.set_stroke(LIGHT_GREY)
|
||||||
|
h_line.set_sheen(1, UL)
|
||||||
|
points = [
|
||||||
|
h_line.get_left() + UP,
|
||||||
|
h_line.get_center(),
|
||||||
|
h_line.get_right() + UP,
|
||||||
|
]
|
||||||
|
dashed_lines = VGroup(
|
||||||
|
DashedLine(*points[0:2]), DashedLine(*points[1:3])
|
||||||
|
)
|
||||||
|
dashed_lines.set_stroke(WHITE, 2)
|
||||||
|
v_shape = VMobject()
|
||||||
|
v_shape.set_points_as_corners(points)
|
||||||
|
v_shape.fade(1)
|
||||||
|
|
||||||
|
theta = dashed_lines[1].get_angle()
|
||||||
|
arcs = VGroup(
|
||||||
|
Arc(start_angle=0, angle=theta),
|
||||||
|
Arc(start_angle=PI, angle=-theta),
|
||||||
|
)
|
||||||
|
arcs.set_stroke(WHITE, 2)
|
||||||
|
thetas = VGroup()
|
||||||
|
for v in LEFT, RIGHT:
|
||||||
|
theta = TexMobject("\\theta")
|
||||||
|
theta.next_to(arcs, v, aligned_edge=DOWN)
|
||||||
|
theta.shift(SMALL_BUFF * UP)
|
||||||
|
thetas.add(theta)
|
||||||
|
|
||||||
|
beam = VMobject()
|
||||||
|
|
||||||
|
def update_beam(beam, period=2, time_width=0.05):
|
||||||
|
time = self.time_tracker.get_value()
|
||||||
|
alpha = (time / period) % 1
|
||||||
|
alpha *= 1.5
|
||||||
|
a = alpha - time_width / 2
|
||||||
|
b = alpha + time_width / 2
|
||||||
|
beam.pointwise_become_partial(
|
||||||
|
v_shape, max(a, 0), min(b, 1)
|
||||||
|
)
|
||||||
|
opacity = title.family_members_with_points()[0].get_fill_opacity()
|
||||||
|
beam.set_stroke(YELLOW, width=3, opacity=opacity)
|
||||||
|
|
||||||
|
beam.add_updater(update_beam)
|
||||||
|
title.next_to(v_shape, UP, MED_LARGE_BUFF)
|
||||||
|
|
||||||
|
return VGroup(
|
||||||
|
title, h_line, arcs, thetas,
|
||||||
|
dashed_lines, v_shape, beam
|
||||||
|
)
|
Loading…
Add table
Reference in a new issue