mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
More scenes for ode1
This commit is contained in:
parent
9a452f3fee
commit
caf41f43d9
4 changed files with 563 additions and 50 deletions
|
@ -17,7 +17,8 @@ ALL_SCENE_CLASSES = [
|
|||
SmallAngleApproximationTex,
|
||||
VeryLowAnglePendulum,
|
||||
FormulasAreLies,
|
||||
FollowThisThread,
|
||||
TourOfDifferentialEquations,
|
||||
# FollowThisThread,
|
||||
StrogatzQuote,
|
||||
# Something...
|
||||
ShowGravityAcceleration,
|
||||
|
@ -40,6 +41,11 @@ ALL_SCENE_CLASSES = [
|
|||
FromODEToVectorField,
|
||||
LorenzVectorField,
|
||||
ThreeBodiesInSpace,
|
||||
AltThreeBodiesInSpace,
|
||||
ThreeBodySymbols,
|
||||
AskAboutActuallySolving,
|
||||
WriteODESolvingCode,
|
||||
TakeManyTinySteps,
|
||||
InaccurateComputation,
|
||||
HungerForExactness,
|
||||
]
|
||||
|
|
|
@ -1113,3 +1113,127 @@ class TweakMuInVectorField(ShowPendulumPhaseFlow):
|
|||
)
|
||||
self.add(animated_stream_lines)
|
||||
self.wait(self.flow_time)
|
||||
|
||||
|
||||
class TakeManyTinySteps(IntroduceVectorField):
|
||||
CONFIG = {
|
||||
"initial_theta": 60 * DEGREES,
|
||||
"initial_theta_dot": 0,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.initialize_plane()
|
||||
self.initialize_vector_field()
|
||||
field = self.vector_field
|
||||
field.set_opacity(0.35)
|
||||
self.add(self.plane, field)
|
||||
|
||||
self.take_many_time_steps()
|
||||
|
||||
def take_many_time_steps(self):
|
||||
delta_t_tracker = ValueTracker(0.5)
|
||||
get_delta_t = delta_t_tracker.get_value
|
||||
|
||||
time_tracker = ValueTracker(10)
|
||||
get_t = time_tracker.get_value
|
||||
|
||||
traj = always_redraw(
|
||||
lambda: self.get_time_step_trajectory(
|
||||
get_delta_t(), get_t()
|
||||
)
|
||||
)
|
||||
vectors = always_redraw(
|
||||
lambda: self.get_path_vectors(
|
||||
get_delta_t(), get_t()
|
||||
)
|
||||
)
|
||||
|
||||
t_label, dt_label = labels = VGroup(*[
|
||||
VGroup(
|
||||
TexMobject("{} = ".format(s)),
|
||||
DecimalNumber(0)
|
||||
).arrange(RIGHT, aligned_edge=DOWN)
|
||||
for s in ("t", "{\\Delta t}")
|
||||
])
|
||||
init_labels = VGroup(
|
||||
TexMobject(
|
||||
"\\theta_0", "= \\pi / 3",
|
||||
tex_to_color_map={"\\theta": BLUE},
|
||||
),
|
||||
TexMobject(
|
||||
"{\\dot\\theta}_0 = 0",
|
||||
tex_to_color_map={"{\\dot\\theta}": YELLOW},
|
||||
),
|
||||
)
|
||||
for group in labels, init_labels:
|
||||
for label in group:
|
||||
label.scale(1.25)
|
||||
label.add_background_rectangle()
|
||||
group.arrange(DOWN)
|
||||
group.shift(FRAME_WIDTH * RIGHT / 4)
|
||||
labels.to_edge(UP)
|
||||
init_labels.shift(2 * DOWN)
|
||||
|
||||
dt_label[-1].add_updater(
|
||||
lambda d: d.set_value(get_delta_t())
|
||||
)
|
||||
t_label[-1].add_updater(
|
||||
lambda d: d.set_value(
|
||||
int(get_t() / get_delta_t()) * get_delta_t()
|
||||
)
|
||||
)
|
||||
|
||||
self.add(traj, vectors, init_labels, labels)
|
||||
time_tracker.set_value(0)
|
||||
self.play(
|
||||
time_tracker.set_value, 10,
|
||||
run_time=5,
|
||||
rate_func=linear,
|
||||
)
|
||||
self.wait()
|
||||
t_label[-1].clear_updaters()
|
||||
self.play(
|
||||
delta_t_tracker.set_value, 0.01,
|
||||
run_time=7,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
def get_time_step_points(self, delta_t, total_time):
|
||||
plane = self.plane
|
||||
field = self.vector_field
|
||||
curr_point = plane.coords_to_point(
|
||||
self.initial_theta,
|
||||
self.initial_theta_dot,
|
||||
)
|
||||
points = [curr_point]
|
||||
t = 0
|
||||
while t < total_time:
|
||||
new_point = curr_point + field.func(curr_point) * delta_t
|
||||
points.append(new_point)
|
||||
curr_point = new_point
|
||||
t += delta_t
|
||||
return points
|
||||
|
||||
def get_time_step_trajectory(self, delta_t, total_time):
|
||||
traj = VMobject()
|
||||
traj.set_points_as_corners(
|
||||
self.get_time_step_points(delta_t, total_time)
|
||||
)
|
||||
traj.set_stroke(WHITE, 2)
|
||||
return traj
|
||||
|
||||
def get_path_vectors(self, delta_t, total_time):
|
||||
corners = self.get_time_step_points(
|
||||
delta_t, total_time
|
||||
)
|
||||
result = VGroup()
|
||||
for a1, a2 in zip(corners, corners[1:]):
|
||||
vector = Arrow(
|
||||
a1, a2, buff=0,
|
||||
)
|
||||
vector.match_style(
|
||||
self.vector_field.get_vector(a1)
|
||||
)
|
||||
result.add(vector)
|
||||
return result
|
||||
|
|
|
@ -103,6 +103,11 @@ class FormulasAreLies(PiCreatureScene):
|
|||
return You().flip().to_corner(DR)
|
||||
|
||||
|
||||
# class TourOfDifferentialEquations(Scene):
|
||||
# def construct(self):
|
||||
# pass
|
||||
|
||||
|
||||
class ProveTeacherWrong(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
tex_config = {
|
||||
|
@ -197,15 +202,183 @@ class ProveTeacherWrong(TeacherStudentsScene):
|
|||
self.wait(8)
|
||||
|
||||
|
||||
class AskAboutActuallySolving(Scene):
|
||||
class AskAboutActuallySolving(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
self.add(ode)
|
||||
morty = self.teacher
|
||||
|
||||
self.student_says(
|
||||
"Yeah, yeah, but how do\\\\"
|
||||
"Yeah yeah, but how do\\\\"
|
||||
"you acutally \\emph{solve} it?",
|
||||
student_index=1,
|
||||
target_mode="sassy",
|
||||
added_anims=[morty.change, "thinking"],
|
||||
)
|
||||
self.change_student_modes(
|
||||
"confused", "sassy", "confused",
|
||||
look_at_arg=ode,
|
||||
)
|
||||
self.wait()
|
||||
self.teacher_says(
|
||||
"What do you mean\\\\ by ``solve''?",
|
||||
target_mode="speaking",
|
||||
added_anims=[self.get_student_changes(
|
||||
*3 * ["erm"]
|
||||
)]
|
||||
)
|
||||
self.play(self.students[1].change, "angry")
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class HungerForExactness(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
students = self.students
|
||||
you = students[2]
|
||||
teacher = self.teacher
|
||||
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
left_part = ode[:5]
|
||||
friction_part = ode[5:11]
|
||||
right_part = ode[11:]
|
||||
self.add(ode)
|
||||
frictionless_group = VGroup(left_part, right_part)
|
||||
|
||||
proposed_solution = TexMobject(
|
||||
"\\theta_0\\cos((\\sqrt{g/L})t)e^{-\\mu t}"
|
||||
)
|
||||
proposed_solution.next_to(
|
||||
you.get_corner(UL), UP, buff=0.7
|
||||
)
|
||||
proposed_solution_rect = SurroundingRectangle(
|
||||
proposed_solution, buff=MED_SMALL_BUFF,
|
||||
)
|
||||
proposed_solution_rect.set_color(BLUE)
|
||||
proposed_solution_rect.round_corners()
|
||||
|
||||
solution_p1 = TexMobject(
|
||||
"""
|
||||
\\theta(t) = 2\\text{am}\\left(
|
||||
\\frac{\\sqrt{2g + Lc_1} (t + c_2)}{2\\sqrt{L}},
|
||||
\\frac{4g}{2g + Lc_1}
|
||||
\\right)
|
||||
""",
|
||||
)
|
||||
solution_p1.to_corner(UL)
|
||||
solution_p2 = TexMobject(
|
||||
"c_1, c_2 = \\text{Constants depending on initial conditions}"
|
||||
)
|
||||
solution_p2.set_color(LIGHT_GREY)
|
||||
solution_p2.scale(0.75)
|
||||
solution_p3 = TexMobject(
|
||||
"""
|
||||
\\text{am}(u, k) =
|
||||
\\int_0^u \\text{dn}(v, k)\\,dv
|
||||
"""
|
||||
)
|
||||
solution_p3.name = TextMobject(
|
||||
"(Jacobi amplitude function)"
|
||||
)
|
||||
solution_p4 = TexMobject(
|
||||
"""
|
||||
\\text{dn}(u, k) =
|
||||
\\sqrt{1 - k^2 \\sin^2(\\phi)}
|
||||
"""
|
||||
)
|
||||
solution_p4.name = TextMobject(
|
||||
"(Jacobi elliptic function)"
|
||||
)
|
||||
solution_p5 = TextMobject("Where $\\phi$ satisfies")
|
||||
solution_p6 = TexMobject(
|
||||
"""
|
||||
u = \\int_0^\\phi \\frac{dt}{\\sqrt{1 - k^2 \\sin^2(t)}}
|
||||
"""
|
||||
)
|
||||
|
||||
solution = VGroup(
|
||||
solution_p1,
|
||||
solution_p2,
|
||||
solution_p3,
|
||||
solution_p4,
|
||||
solution_p5,
|
||||
solution_p6,
|
||||
)
|
||||
solution.arrange(DOWN)
|
||||
solution.scale(0.7)
|
||||
solution.to_corner(UL, buff=MED_SMALL_BUFF)
|
||||
solution.set_stroke(width=0, background=True)
|
||||
|
||||
solution.remove(solution_p2)
|
||||
solution_p1.add(solution_p2)
|
||||
solution.remove(solution_p5)
|
||||
solution_p6.add(solution_p5)
|
||||
|
||||
for part in [solution_p3, solution_p4]:
|
||||
part.name.scale(0.7 * 0.7)
|
||||
part.name.set_color(LIGHT_GREY)
|
||||
part.name.next_to(part, RIGHT)
|
||||
part.add(part.name)
|
||||
|
||||
self.student_says(
|
||||
"Right, but like,\\\\"
|
||||
"what \\emph{is} $\\theta(t)$?",
|
||||
target_mode="sassy",
|
||||
added_anims=[teacher.change, "guilty"],
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(proposed_solution),
|
||||
RemovePiCreatureBubble(
|
||||
you,
|
||||
target_mode="raise_left_hand",
|
||||
look_at_arg=proposed_solution,
|
||||
),
|
||||
teacher.change, "pondering",
|
||||
students[0].change, "pondering",
|
||||
students[1].change, "hesitant",
|
||||
)
|
||||
self.play(ShowCreation(proposed_solution_rect))
|
||||
self.play(
|
||||
proposed_solution.shift, 3 * RIGHT,
|
||||
proposed_solution_rect.shift, 3 * RIGHT,
|
||||
you.change, "raise_right_hand", teacher.eyes,
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
self.play(
|
||||
FadeOut(proposed_solution),
|
||||
FadeOut(proposed_solution_rect),
|
||||
ode.move_to, self.hold_up_spot, DOWN,
|
||||
ode.shift, LEFT,
|
||||
teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(*3 * ["pondering"])
|
||||
)
|
||||
self.wait()
|
||||
ode.save_state()
|
||||
self.play(
|
||||
left_part.move_to, friction_part, RIGHT,
|
||||
left_part.match_y, left_part,
|
||||
friction_part.to_corner, DR,
|
||||
friction_part.fade, 0.5,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
modes = ["erm", "sad", "sad", "horrified"]
|
||||
for part, mode in zip(solution, modes):
|
||||
self.play(
|
||||
FadeInFrom(part, UP),
|
||||
self.get_student_changes(
|
||||
*3 * [mode],
|
||||
look_at_arg=part,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
self.wait(3)
|
||||
self.play(
|
||||
FadeOutAndShift(solution, 2 * LEFT),
|
||||
Restore(ode),
|
||||
self.get_student_changes(*3 * ["sick"])
|
||||
)
|
||||
self.wait(3)
|
||||
|
|
|
@ -39,28 +39,37 @@ class VectorFieldTest(Scene):
|
|||
self.wait(10)
|
||||
|
||||
|
||||
class FollowThisThread(Scene):
|
||||
class TourOfDifferentialEquations(MovingCameraScene):
|
||||
CONFIG = {
|
||||
"screen_rect_style": {
|
||||
"stroke_width": 2,
|
||||
"stroke_color": WHITE,
|
||||
"fill_opacity": 1,
|
||||
"fill_color": DARKER_GREY,
|
||||
}
|
||||
"fill_color": BLACK,
|
||||
},
|
||||
"camera_config": {"background_color": DARKER_GREY},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.show_thumbnails()
|
||||
self.show_words()
|
||||
# self.show_words()
|
||||
|
||||
def add_title(self):
|
||||
title = TextMobject(
|
||||
"A Tourist's Guide \\\\to Differential\\\\Equations"
|
||||
)
|
||||
title.scale(1.5)
|
||||
title.to_corner(UR)
|
||||
self.add(title)
|
||||
|
||||
def show_thumbnails(self):
|
||||
# TODO, replace each of these with a picture?
|
||||
thumbnails = self.thumbnails = VGroup(
|
||||
ScreenRectangle(**self.screen_rect_style),
|
||||
ScreenRectangle(**self.screen_rect_style),
|
||||
ScreenRectangle(**self.screen_rect_style),
|
||||
ScreenRectangle(**self.screen_rect_style),
|
||||
ScreenRectangle(**self.screen_rect_style),
|
||||
thumbnails = self.thumbnails = Group(
|
||||
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||
Group(ScreenRectangle(**self.screen_rect_style)),
|
||||
)
|
||||
n = len(thumbnails)
|
||||
thumbnails.set_height(1.5)
|
||||
|
@ -71,8 +80,16 @@ class FollowThisThread(Scene):
|
|||
[-3, -3, 0],
|
||||
[5, -3, 0],
|
||||
])
|
||||
line.shift(MED_SMALL_BUFF * LEFT)
|
||||
for thumbnail, a in zip(thumbnails, np.linspace(0, 1, n)):
|
||||
thumbnail.move_to(line.point_from_proportion(a))
|
||||
dots = TexMobject("\\dots")
|
||||
dots.next_to(thumbnails[-1], RIGHT)
|
||||
|
||||
self.add_heat_preview(thumbnails[1])
|
||||
self.add_fourier_series(thumbnails[2])
|
||||
self.add_matrix_exponent(thumbnails[3])
|
||||
self.add_laplace_symbol(thumbnails[4])
|
||||
|
||||
self.play(
|
||||
ShowCreation(
|
||||
|
@ -91,6 +108,14 @@ class FollowThisThread(Scene):
|
|||
], lag_ratio=1),
|
||||
run_time=5
|
||||
)
|
||||
self.play(Write(dots))
|
||||
self.wait()
|
||||
self.play(
|
||||
self.camera_frame.replace,
|
||||
thumbnails[0],
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def show_words(self):
|
||||
words = VGroup(
|
||||
|
@ -123,6 +148,71 @@ class FollowThisThread(Scene):
|
|||
)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
def add_heat_preview(self, thumbnail):
|
||||
image = ImageMobject("HeatSurfaceExample")
|
||||
image.replace(thumbnail)
|
||||
thumbnail.add(image)
|
||||
|
||||
def add_matrix_exponent(self, thumbnail):
|
||||
matrix = IntegerMatrix(
|
||||
[[3, 1], [4, 1]],
|
||||
v_buff=MED_LARGE_BUFF,
|
||||
h_buff=MED_LARGE_BUFF,
|
||||
bracket_h_buff=SMALL_BUFF,
|
||||
bracket_v_buff=SMALL_BUFF,
|
||||
)
|
||||
e = TexMobject("e")
|
||||
t = TexMobject("t")
|
||||
t.scale(1.5)
|
||||
t.next_to(matrix, RIGHT, SMALL_BUFF)
|
||||
e.scale(2)
|
||||
e.move_to(matrix.get_corner(DL), UR)
|
||||
group = VGroup(e, matrix, t)
|
||||
group.set_height(0.7 * thumbnail.get_height())
|
||||
randy = Randolph(mode="confused", height=0.75)
|
||||
randy.next_to(group, LEFT, aligned_edge=DOWN)
|
||||
randy.look_at(matrix)
|
||||
group.add(randy)
|
||||
group.move_to(thumbnail)
|
||||
thumbnail.add(group)
|
||||
|
||||
def add_fourier_series(self, thumbnail):
|
||||
colors = [BLUE, GREEN, YELLOW, RED, RED_E, PINK]
|
||||
|
||||
waves = VGroup(*[
|
||||
self.get_square_wave_approx(N, color)
|
||||
for N, color in enumerate(colors)
|
||||
])
|
||||
waves.set_stroke(width=1.5)
|
||||
waves.replace(thumbnail, stretch=True)
|
||||
waves.scale(0.8)
|
||||
waves.move_to(thumbnail)
|
||||
thumbnail.add(waves)
|
||||
|
||||
def get_square_wave_approx(self, N, color):
|
||||
return FunctionGraph(
|
||||
lambda x: sum([
|
||||
(1 / n) * np.sin(n * PI * x)
|
||||
for n in range(1, 2 * N + 3, 2)
|
||||
]),
|
||||
x_min=0,
|
||||
x_max=2,
|
||||
color=color
|
||||
)
|
||||
|
||||
def add_laplace_symbol(self, thumbnail):
|
||||
mob = TexMobject(
|
||||
"\\mathcal{L}\\left\\{f(t)\\right\\}"
|
||||
)
|
||||
mob.set_width(0.8 * thumbnail.get_width())
|
||||
mob.move_to(thumbnail)
|
||||
thumbnail.add(mob)
|
||||
|
||||
|
||||
class HeatEquationPreview(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
|
||||
class ShowGravityAcceleration(Scene):
|
||||
def construct(self):
|
||||
|
@ -395,15 +485,7 @@ class DefineODE(Scene):
|
|||
de_word = TextMobject("Differential", "Equation")
|
||||
de_word.to_edge(UP)
|
||||
|
||||
equation = TexMobject(
|
||||
"\\ddot \\theta({t})", "=",
|
||||
"-\\mu \\dot \\theta({t})",
|
||||
"-{g \\over L} \\sin\\big(\\theta({t})\\big)",
|
||||
tex_to_color_map={
|
||||
"\\theta": BLUE,
|
||||
"{t}": WHITE
|
||||
}
|
||||
)
|
||||
equation = get_ode()
|
||||
equation.next_to(de_word, DOWN)
|
||||
thetas = equation.get_parts_by_tex("\\theta")
|
||||
|
||||
|
@ -475,11 +557,18 @@ class DefineODE(Scene):
|
|||
)
|
||||
|
||||
tex_config = {
|
||||
"tex_to_color_map": {"\\theta": BLUE},
|
||||
"tex_to_color_map": {
|
||||
"{\\theta}": BLUE,
|
||||
"{\\dot\\theta}": YELLOW,
|
||||
"{\\ddot\\theta}": RED,
|
||||
},
|
||||
"height": 0.5,
|
||||
}
|
||||
theta, d_theta, dd_theta = [
|
||||
TexMobject(s + "\\theta(t)", **tex_config)
|
||||
TexMobject(
|
||||
"{" + s + "\\theta}(t)",
|
||||
**tex_config
|
||||
)
|
||||
for s in ("", "\\dot", "\\ddot")
|
||||
]
|
||||
|
||||
|
@ -500,7 +589,7 @@ class DefineODE(Scene):
|
|||
return DashedLine(
|
||||
x_point, point,
|
||||
dash_length=0.025,
|
||||
stroke_color=WHITE,
|
||||
stroke_color=BLUE,
|
||||
stroke_width=2,
|
||||
)
|
||||
|
||||
|
@ -545,7 +634,7 @@ class DefineODE(Scene):
|
|||
thetas = VGroup(theta, d_theta, dd_theta)
|
||||
|
||||
words = VGroup(
|
||||
TextMobject("= Height"),
|
||||
TextMobject("= Height").set_color(BLUE),
|
||||
TextMobject("= Slope").set_color(YELLOW),
|
||||
TextMobject("= ``Curvature''").set_color(RED),
|
||||
)
|
||||
|
@ -887,7 +976,8 @@ class LorenzVectorField(ExternallyAnimatedScene):
|
|||
|
||||
class ThreeBodiesInSpace(SpecialThreeDScene):
|
||||
CONFIG = {
|
||||
"masses": [1, 2, 3],
|
||||
"masses": [1, 6, 3],
|
||||
"colors": [RED_E, GREEN_E, BLUE_E],
|
||||
"G": 0.5,
|
||||
"play_time": 60,
|
||||
}
|
||||
|
@ -900,26 +990,48 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
|||
|
||||
def add_axes(self):
|
||||
axes = self.axes = self.get_axes()
|
||||
axes.set_stroke(width=0.5)
|
||||
self.add(axes)
|
||||
|
||||
def add_bodies(self):
|
||||
masses = self.masses
|
||||
colors = self.colors
|
||||
|
||||
bodies = self.bodies = VGroup()
|
||||
velocity_vectors = VGroup()
|
||||
|
||||
for mass in self.masses:
|
||||
body = self.get_sphere(
|
||||
checkerboard_colors=[DARK_BROWN, DARK_BROWN],
|
||||
stroke_width=0.1,
|
||||
)
|
||||
body.mass = mass
|
||||
body.set_width(0.2 * mass)
|
||||
|
||||
point = np.dot(
|
||||
2 * (np.random.random(3) - 0.5),
|
||||
centers = [
|
||||
np.dot(
|
||||
4 * (np.random.random(3) - 0.5),
|
||||
[RIGHT, UP, OUT]
|
||||
)
|
||||
velocity = normalize(np.cross(point, OUT))
|
||||
body.move_to(point)
|
||||
for x in range(len(masses))
|
||||
]
|
||||
|
||||
for mass, color, center in zip(masses, colors, centers):
|
||||
body = self.get_sphere(
|
||||
checkerboard_colors=[
|
||||
color, color
|
||||
],
|
||||
color=color,
|
||||
stroke_width=0.1,
|
||||
)
|
||||
body.set_opacity(0.75)
|
||||
body.mass = mass
|
||||
body.set_width(0.15 * np.sqrt(mass))
|
||||
|
||||
body.point = center
|
||||
body.move_to(center)
|
||||
|
||||
to_others = [
|
||||
center - center2
|
||||
for center2 in centers
|
||||
]
|
||||
velocity = 0.2 * mass * normalize(np.cross(*filter(
|
||||
lambda diff: get_norm(diff) > 0,
|
||||
to_others
|
||||
)))
|
||||
|
||||
body.velocity = velocity
|
||||
body.add_updater(self.update_body)
|
||||
|
||||
|
@ -946,27 +1058,28 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
|||
|
||||
def add_trajectories(self):
|
||||
def update_trajectory(traj, dt):
|
||||
new_point = traj.body.get_center()
|
||||
new_point = traj.body.point
|
||||
if get_norm(new_point - traj.points[-1]) > 0.01:
|
||||
traj.add_smooth_curve_to(new_point)
|
||||
|
||||
for body in self.bodies:
|
||||
traj = VMobject()
|
||||
traj.body = body
|
||||
traj.start_new_path(body.get_center())
|
||||
traj.set_stroke(WHITE, 1)
|
||||
traj.start_new_path(body.point)
|
||||
traj.set_stroke(body.color, 1, opacity=0.75)
|
||||
traj.add_updater(update_trajectory)
|
||||
self.add(traj, body)
|
||||
|
||||
def let_play(self):
|
||||
self.move_camera(
|
||||
self.set_camera_orientation(
|
||||
phi=70 * DEGREES,
|
||||
theta=-110 * DEGREES,
|
||||
run_time=3,
|
||||
)
|
||||
self.begin_ambient_camera_rotation()
|
||||
for x in range(6):
|
||||
self.wait(self.play_time / 6)
|
||||
# Break it up to see partial files as
|
||||
# it's rendered
|
||||
for x in range(int(self.play_time)):
|
||||
self.wait()
|
||||
|
||||
#
|
||||
def get_velocity_vector_mob(self, body):
|
||||
|
@ -994,13 +1107,110 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
|||
for body2 in self.bodies:
|
||||
if body2 is body:
|
||||
continue
|
||||
diff = body2.get_center() - body.get_center()
|
||||
diff = body2.point - body.point
|
||||
m2 = body2.mass
|
||||
R = get_norm(diff)
|
||||
acceleration += G * m2 * diff / (R**3)
|
||||
|
||||
body.shift(body.velocity * dt)
|
||||
body.velocity += acceleration * dt
|
||||
num_mid_steps = 100
|
||||
for x in range(num_mid_steps):
|
||||
body.point += body.velocity * dt / num_mid_steps
|
||||
body.velocity += acceleration * dt / num_mid_steps
|
||||
body.move_to(body.point)
|
||||
return body
|
||||
|
||||
|
||||
class AltThreeBodiesInSpace(ThreeBodiesInSpace):
|
||||
CONFIG = {
|
||||
"random_seed": 6,
|
||||
"masses": [1, 2, 6],
|
||||
}
|
||||
|
||||
|
||||
class DefineODECopy(DefineODE):
|
||||
pass
|
||||
|
||||
|
||||
class WriteODESolvingCode(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
|
||||
class InaccurateComputation(Scene):
|
||||
def construct(self):
|
||||
h_line = DashedLine(LEFT_SIDE, RIGHT_SIDE)
|
||||
h_line.to_edge(UP, buff=1.5)
|
||||
words = VGroup(
|
||||
TextMobject("Real number"),
|
||||
TextMobject("IEEE 754\\\\representation"),
|
||||
TextMobject("Error"),
|
||||
)
|
||||
for i, word in zip([-1, 0, 1], words):
|
||||
word.next_to(h_line, UP)
|
||||
word.shift(i * FRAME_WIDTH * RIGHT / 3)
|
||||
|
||||
lines = VGroup(*[
|
||||
DashedLine(TOP, BOTTOM)
|
||||
for x in range(4)
|
||||
])
|
||||
lines.arrange(RIGHT)
|
||||
lines.stretch_to_fit_width(FRAME_WIDTH)
|
||||
|
||||
self.add(h_line, lines[1:-1], words)
|
||||
|
||||
numbers = VGroup(
|
||||
TexMobject("\\pi").scale(2),
|
||||
TexMobject("e^{\\sqrt{163}\\pi}").scale(1.5),
|
||||
)
|
||||
numbers.set_color(YELLOW)
|
||||
numbers.set_stroke(width=0, background=True)
|
||||
|
||||
bit_strings = VGroup(
|
||||
TexMobject(
|
||||
"01000000",
|
||||
"01001001",
|
||||
"00001111",
|
||||
"11011011",
|
||||
),
|
||||
TexMobject(
|
||||
"01011100",
|
||||
"01101001",
|
||||
"00101110",
|
||||
"00011001",
|
||||
)
|
||||
)
|
||||
for mob in bit_strings:
|
||||
mob.arrange(DOWN, buff=SMALL_BUFF)
|
||||
for word in mob:
|
||||
for submob, bit in zip(word, word.get_tex_string()):
|
||||
if bit == "0":
|
||||
submob.set_color(LIGHT_GREY)
|
||||
errors = VGroup(
|
||||
TexMobject(
|
||||
"\\approx 8.7422 \\times 10^{-8}"
|
||||
),
|
||||
TexMobject(
|
||||
"\\approx 5{,}289{,}803{,}032.00",
|
||||
),
|
||||
)
|
||||
errors.set_color(RED)
|
||||
|
||||
content = VGroup(numbers, bit_strings, errors)
|
||||
|
||||
for group, word in zip(content, words):
|
||||
group[1].shift(3 * DOWN)
|
||||
group.move_to(DOWN)
|
||||
group.match_x(word)
|
||||
|
||||
self.play(*map(Write, numbers))
|
||||
self.wait()
|
||||
self.play(
|
||||
TransformFromCopy(numbers, bit_strings),
|
||||
lag_ratio=0.01,
|
||||
run_time=2,
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFrom(errors, 3 * LEFT))
|
||||
self.wait()
|
||||
|
||||
|
||||
class NewSceneName(Scene):
|
||||
|
|
Loading…
Add table
Reference in a new issue