mirror of
https://github.com/3b1b/manim.git
synced 2025-07-29 04:53:34 +08:00
304 lines
7.9 KiB
Python
304 lines
7.9 KiB
Python
from manimlib.imports import *
|
|
from active_projects.diffyq.part2.heat_equation import *
|
|
|
|
|
|
class ShowNewRuleAtDiscreteBoundary(DiscreteSetup):
|
|
CONFIG = {
|
|
"axes_config": {
|
|
"x_min": 0,
|
|
"stroke_width": 1,
|
|
"x_axis_config": {
|
|
"include_tip": False,
|
|
},
|
|
},
|
|
"freq_amplitude_pairs": [
|
|
(1, 0.5),
|
|
(2, 1),
|
|
(3, 0.5),
|
|
(4, 0.3),
|
|
],
|
|
"v_line_class": DashedLine,
|
|
"v_line_config": {
|
|
|
|
},
|
|
"step_size": 1,
|
|
"wait_time": 15,
|
|
"alpha": 0.25,
|
|
}
|
|
|
|
def construct(self):
|
|
self.add_axes()
|
|
self.set_points()
|
|
self.show_boundary_point_influenced_by_neighbor()
|
|
self.add_clock()
|
|
self.let_evolve()
|
|
|
|
def set_points(self):
|
|
axes = self.axes
|
|
for mob in axes.family_members_with_points():
|
|
if isinstance(mob, Line):
|
|
mob.set_stroke(width=1)
|
|
|
|
step_size = self.step_size
|
|
xs = np.arange(
|
|
axes.x_min,
|
|
axes.x_max + step_size,
|
|
step_size
|
|
)
|
|
|
|
dots = self.dots = self.get_dots(axes, xs)
|
|
self.v_lines = self.get_v_lines(dots)
|
|
self.rod_pieces = self.get_rod_pieces(dots)
|
|
|
|
# rod_pieces
|
|
|
|
self.add(self.dots)
|
|
self.add(self.v_lines)
|
|
self.add(self.rod_pieces)
|
|
|
|
def show_boundary_point_influenced_by_neighbor(self):
|
|
dots = self.dots
|
|
ld = dots[0]
|
|
ld_in = dots[1]
|
|
rd = dots[-1]
|
|
rd_in = dots[-2]
|
|
v_len = 0.75
|
|
l_arrow = Vector(v_len * LEFT)
|
|
l_arrow.move_to(ld.get_left(), RIGHT)
|
|
r_arrow = Vector(v_len * RIGHT)
|
|
r_arrow.move_to(rd.get_right(), LEFT)
|
|
arrows = VGroup(l_arrow, r_arrow)
|
|
q_marks = VGroup(*[
|
|
TexMobject("?").scale(1.5).next_to(
|
|
arrow, arrow.get_vector()
|
|
)
|
|
for arrow in arrows
|
|
])
|
|
|
|
arrows.set_color(YELLOW)
|
|
q_marks.set_color(YELLOW)
|
|
|
|
blocking_rects = VGroup(*[
|
|
BackgroundRectangle(VGroup(
|
|
*dots[i:-i],
|
|
*self.rod_pieces[i:-i]
|
|
))
|
|
for i in [1, 2]
|
|
])
|
|
for rect in blocking_rects:
|
|
rect.stretch(1.1, dim=1, about_edge=UP)
|
|
|
|
self.play(FadeIn(blocking_rects[0]))
|
|
self.play(
|
|
LaggedStartMap(ShowCreation, arrows),
|
|
LaggedStart(*[
|
|
FadeInFrom(q_mark, -arrow.get_vector())
|
|
for q_mark, arrow in zip(q_marks, arrows)
|
|
]),
|
|
run_time=1.5
|
|
)
|
|
self.wait()
|
|
|
|
# Point to inward neighbor
|
|
new_arrows = VGroup(*[
|
|
Arrow(
|
|
d1.get_center(),
|
|
VGroup(d1, d2).get_center(),
|
|
buff=0,
|
|
).match_style(l_arrow)
|
|
for d1, d2 in [(ld, ld_in), (rd, rd_in)]
|
|
])
|
|
new_arrows.match_style(arrows)
|
|
|
|
l_brace = Brace(VGroup(ld, ld_in), DOWN)
|
|
r_brace = Brace(VGroup(rd, rd_in), DOWN)
|
|
braces = VGroup(l_brace, r_brace)
|
|
for brace in braces:
|
|
brace.align_to(
|
|
self.axes.x_axis.get_center(), UP
|
|
)
|
|
brace.shift(SMALL_BUFF * DOWN)
|
|
brace.add(brace.get_tex("\\Delta x"))
|
|
|
|
self.play(
|
|
ReplacementTransform(arrows, new_arrows),
|
|
FadeOut(q_marks),
|
|
ReplacementTransform(*blocking_rects)
|
|
)
|
|
self.wait()
|
|
self.play(FadeInFrom(braces, UP))
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(new_arrows),
|
|
FadeOut(blocking_rects[1]),
|
|
FadeOut(braces),
|
|
)
|
|
|
|
def add_clock(self):
|
|
super().add_clock()
|
|
self.time_label.add_updater(
|
|
lambda d, dt: d.increment_value(dt)
|
|
)
|
|
VGroup(
|
|
self.clock,
|
|
self.time_label
|
|
).shift(2 * LEFT)
|
|
|
|
def let_evolve(self):
|
|
dots = self.dots
|
|
dots.add_updater(self.update_dots)
|
|
|
|
wait_time = self.wait_time
|
|
self.play(
|
|
ClockPassesTime(
|
|
self.clock,
|
|
run_time=wait_time,
|
|
hours_passed=wait_time,
|
|
),
|
|
)
|
|
|
|
#
|
|
|
|
def get_dots(self, axes, xs):
|
|
dots = VGroup(*[
|
|
Dot(axes.c2p(x, self.temp_func(x, 0)))
|
|
for x in xs
|
|
])
|
|
|
|
max_width = 0.8 * self.step_size
|
|
for dot in dots:
|
|
dot.add_updater(self.update_dot_color)
|
|
if dot.get_width() > max_width:
|
|
dot.set_width(max_width)
|
|
|
|
return dots
|
|
|
|
def get_v_lines(self, dots):
|
|
return always_redraw(lambda: VGroup(*[
|
|
self.get_v_line(dot)
|
|
for dot in dots
|
|
]))
|
|
|
|
def get_v_line(self, dot):
|
|
x_axis = self.axes.x_axis
|
|
bottom = dot.get_bottom()
|
|
x = x_axis.p2n(bottom)
|
|
proj_point = x_axis.n2p(x)
|
|
return self.v_line_class(
|
|
proj_point, bottom,
|
|
**self.v_line_config,
|
|
)
|
|
|
|
def get_rod_pieces(self, dots):
|
|
axis = self.axes.x_axis
|
|
factor = 1 - np.exp(-(0.8 / self.step_size)**2)
|
|
width = factor * self.step_size
|
|
|
|
pieces = VGroup()
|
|
for dot in dots:
|
|
piece = Line(ORIGIN, width * RIGHT)
|
|
piece.set_stroke(width=5)
|
|
piece.move_to(dot)
|
|
piece.set_y(axis.get_center()[1])
|
|
piece.dot = dot
|
|
piece.add_updater(
|
|
lambda p: p.match_color(p.dot)
|
|
)
|
|
pieces.add(piece)
|
|
return pieces
|
|
|
|
def update_dot_color(self, dot):
|
|
y = self.axes.y_axis.p2n(dot.get_center())
|
|
dot.set_color(self.y_to_color(y))
|
|
|
|
def update_dots(self, dots, dt):
|
|
for ds in zip(dots, dots[1:], dots[2:]):
|
|
points = [d.get_center() for d in ds]
|
|
x0, x1, x2 = [p[0] for p in points]
|
|
dx = x1 - x0
|
|
y0, y1, y2 = [p[1] for p in points]
|
|
|
|
self.update_dot(
|
|
dot=ds[1],
|
|
dt=dt,
|
|
mean_diff=0.5 * (y2 - 2 * y1 + y0) / dx
|
|
)
|
|
if ds[0] is dots[0]:
|
|
self.update_dot(
|
|
dot=ds[0],
|
|
dt=dt,
|
|
mean_diff=(y1 - y0) / dx
|
|
)
|
|
elif ds[-1] is dots[-1]:
|
|
self.update_dot(
|
|
dot=ds[-1],
|
|
dt=dt,
|
|
mean_diff=(y1 - y2) / dx
|
|
)
|
|
|
|
def update_dot(self, dot, dt, mean_diff):
|
|
dot.shift(mean_diff * self.alpha * dt * UP)
|
|
|
|
|
|
class DiscreteEvolutionPoint25(ShowNewRuleAtDiscreteBoundary):
|
|
CONFIG = {
|
|
"step_size": 0.25,
|
|
"alpha": 0.5,
|
|
"wait_time": 30,
|
|
}
|
|
|
|
def construct(self):
|
|
self.add_axes()
|
|
self.set_points()
|
|
self.add_clock()
|
|
self.let_evolve()
|
|
|
|
|
|
class DiscreteEvolutionPoint1(DiscreteEvolutionPoint25):
|
|
CONFIG = {
|
|
"step_size": 0.1,
|
|
"v_line_config": {
|
|
"stroke_width": 1,
|
|
},
|
|
"wait_time": 30,
|
|
}
|
|
|
|
|
|
class FlatEdgesForDiscreteEvolution(DiscreteEvolutionPoint1):
|
|
CONFIG = {
|
|
"wait_time": 20,
|
|
"step_size": 0.1,
|
|
}
|
|
|
|
def let_evolve(self):
|
|
lines = VGroup(*[
|
|
Line(LEFT, RIGHT)
|
|
for x in range(2)
|
|
])
|
|
lines.set_width(1.5)
|
|
lines.set_stroke(WHITE, 5, opacity=0.5)
|
|
lines.add_updater(self.update_lines)
|
|
|
|
turn_animation_into_updater(
|
|
ShowCreation(lines, run_time=2)
|
|
)
|
|
self.add(lines)
|
|
|
|
super().let_evolve()
|
|
|
|
def update_lines(self, lines):
|
|
dots = self.dots
|
|
for line, dot in zip(lines, [dots[0], dots[-1]]):
|
|
line.move_to(dot)
|
|
|
|
|
|
class FlatEdgesForDiscreteEvolutionTinySteps(FlatEdgesForDiscreteEvolution):
|
|
CONFIG = {
|
|
"step_size": 0.025,
|
|
"wait_time": 10,
|
|
"v_line_class": Line,
|
|
"v_line_config": {
|
|
"stroke_opacity": 0.5,
|
|
}
|
|
}
|