mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Up to AngularMomentumArgument
This commit is contained in:
parent
c9b71afb85
commit
61d5f6f759
1 changed files with 430 additions and 48 deletions
|
@ -1,8 +1,12 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from big_ol_pile_of_manim_imports import *
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
|
||||||
|
from active_projects.div_curl import VectorField
|
||||||
|
from active_projects.div_curl import get_force_field_func
|
||||||
|
|
||||||
COBALT = "#0047AB"
|
COBALT = "#0047AB"
|
||||||
|
|
||||||
|
|
||||||
class Orbiting(ContinualAnimation):
|
class Orbiting(ContinualAnimation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"rate": 0.3,
|
"rate": 0.3,
|
||||||
|
@ -577,12 +581,14 @@ class TheMotionOfPlanets(Scene):
|
||||||
class AskAboutEllipses(TheMotionOfPlanets):
|
class AskAboutEllipses(TheMotionOfPlanets):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_config": {"background_opacity": 1},
|
"camera_config": {"background_opacity": 1},
|
||||||
|
"sun_height": 0.5,
|
||||||
"sun_center": ORIGIN,
|
"sun_center": ORIGIN,
|
||||||
"animate_sun": True,
|
"animate_sun": True,
|
||||||
"a": 3.5,
|
"a": 3.5,
|
||||||
"b": 2.0,
|
"b": 2.0,
|
||||||
"ellipse_color": WHITE,
|
"ellipse_color": WHITE,
|
||||||
"ellipse_stroke_width": 1,
|
"ellipse_stroke_width": 1,
|
||||||
|
"comet_height": 0.2,
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -600,17 +606,20 @@ class AskAboutEllipses(TheMotionOfPlanets):
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
def add_sun(self):
|
def add_sun(self):
|
||||||
sun = ImageMobject("sun", height=0.5)
|
sun = ImageMobject("sun", height=self.sun_height)
|
||||||
sun.move_to(self.sun_center)
|
sun.move_to(self.sun_center)
|
||||||
self.sun = sun
|
self.sun = sun
|
||||||
self.add(sun)
|
self.add(sun)
|
||||||
if self.animate_sun:
|
if self.animate_sun:
|
||||||
self.add(SunAnimation(sun))
|
sun_animation = SunAnimation(sun)
|
||||||
|
self.add(sun_animation)
|
||||||
|
self.add_foreground_mobjects(
|
||||||
|
sun_animation.mobject
|
||||||
|
)
|
||||||
|
|
||||||
def add_orbit(self):
|
def add_orbit(self):
|
||||||
sun = self.sun
|
sun = self.sun
|
||||||
comet = ImageMobject("comet")
|
comet = self.get_comet()
|
||||||
comet.scale_to_fit_height(0.2)
|
|
||||||
ellipse = self.get_ellipse()
|
ellipse = self.get_ellipse()
|
||||||
orbit = Orbiting(comet, sun, ellipse)
|
orbit = Orbiting(comet, sun, ellipse)
|
||||||
|
|
||||||
|
@ -798,6 +807,11 @@ class AskAboutEllipses(TheMotionOfPlanets):
|
||||||
self.wait(6)
|
self.wait(6)
|
||||||
|
|
||||||
# Helpers
|
# Helpers
|
||||||
|
def get_comet(self):
|
||||||
|
comet = ImageMobject("comet")
|
||||||
|
comet.scale_to_fit_height(self.comet_height)
|
||||||
|
return comet
|
||||||
|
|
||||||
def get_ellipse(self):
|
def get_ellipse(self):
|
||||||
a = self.a
|
a = self.a
|
||||||
b = self.b
|
b = self.b
|
||||||
|
@ -809,7 +823,7 @@ class AskAboutEllipses(TheMotionOfPlanets):
|
||||||
)
|
)
|
||||||
ellipse.stretch(fdiv(b, a), dim=1)
|
ellipse.stretch(fdiv(b, a), dim=1)
|
||||||
ellipse.move_to(
|
ellipse.move_to(
|
||||||
self.sun.get_center() + c * LEFT / 2
|
self.sun.get_center() + c * LEFT,
|
||||||
)
|
)
|
||||||
self.focus_points = [
|
self.focus_points = [
|
||||||
self.sun.get_center(),
|
self.sun.get_center(),
|
||||||
|
@ -1848,75 +1862,75 @@ class EndOfGeometryProofiness(GeometryProofLand):
|
||||||
|
|
||||||
class KeplersSecondLaw(AskAboutEllipses):
|
class KeplersSecondLaw(AskAboutEllipses):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"sun_center": 3 * RIGHT + DOWN,
|
"sun_center": 4 * RIGHT + 0.75 * DOWN,
|
||||||
"animate_sun": False,
|
"animate_sun": True,
|
||||||
"a": 5.0,
|
"a": 5.0,
|
||||||
"b": 2.5,
|
"b": 3.0,
|
||||||
"ellipse_stroke_width": 2,
|
"ellipse_stroke_width": 2,
|
||||||
"area_color": COBALT,
|
"area_color": COBALT,
|
||||||
"area_opacity": 0.75,
|
"area_opacity": 0.75,
|
||||||
"arc_color": YELLOW,
|
"arc_color": YELLOW,
|
||||||
"arc_stroke_width": 3,
|
"arc_stroke_width": 3,
|
||||||
|
"n_sample_sweeps": 5,
|
||||||
|
"fade_sample_areas": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.add_title()
|
self.add_title()
|
||||||
self.add_sun()
|
self.add_sun()
|
||||||
self.add_foreground_mobjects(self.sun)
|
|
||||||
self.add_orbit()
|
self.add_orbit()
|
||||||
self.add_foreground_mobjects(self.comet)
|
self.add_foreground_mobjects(self.comet)
|
||||||
|
|
||||||
self.show_several_sweeps()
|
self.show_several_sweeps()
|
||||||
self.contrast_close_to_far()
|
self.contrast_close_to_far()
|
||||||
|
|
||||||
|
|
||||||
def add_title(self):
|
def add_title(self):
|
||||||
title = TextMobject("Kepler's 2nd law")
|
title = TextMobject("Kepler's 2nd law:")
|
||||||
title.scale(1.0)
|
title.scale(1.0)
|
||||||
title.to_edge(UP)
|
title.to_edge(UP)
|
||||||
self.add(title)
|
self.add(title)
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
|
subtitle = TextMobject(
|
||||||
|
"Orbits sweep a constant area per unit time"
|
||||||
|
)
|
||||||
|
subtitle.next_to(title, DOWN, buff=0.2)
|
||||||
|
subtitle.set_color(BLUE)
|
||||||
|
self.add(subtitle)
|
||||||
|
|
||||||
def show_several_sweeps(self):
|
def show_several_sweeps(self):
|
||||||
n_sweeps = 3
|
|
||||||
shown_areas = VGroup()
|
shown_areas = VGroup()
|
||||||
for x in range(n_sweeps):
|
for x in range(self.n_sample_sweeps):
|
||||||
self.wait()
|
self.wait()
|
||||||
area = self.show_area_sweep()
|
area = self.show_area_sweep()
|
||||||
shown_areas.add(area)
|
shown_areas.add(area)
|
||||||
self.wait(2)
|
self.wait()
|
||||||
self.play(FadeOut(shown_areas))
|
if self.fade_sample_areas:
|
||||||
|
self.play(FadeOut(shown_areas))
|
||||||
|
|
||||||
def contrast_close_to_far(self):
|
def contrast_close_to_far(self):
|
||||||
orbit = self.orbit
|
orbit = self.orbit
|
||||||
sun_point = self.sun.get_center()
|
sun_point = self.sun.get_center()
|
||||||
|
|
||||||
start_prop = 0.8
|
start_prop = 0.9
|
||||||
self.wait_until_proportion(start_prop)
|
self.wait_until_proportion(start_prop)
|
||||||
area = self.show_area_sweep()
|
self.show_area_sweep()
|
||||||
end_prop = max(0.9, orbit.proportion)
|
end_prop = orbit.proportion
|
||||||
arc = self.get_arc(start_prop, end_prop)
|
arc = self.get_arc(start_prop, end_prop)
|
||||||
radius = Line(sun_point, arc.points[0])
|
radius = Line(sun_point, arc.points[0])
|
||||||
radius.set_color(PINK)
|
radius.set_color(WHITE)
|
||||||
|
|
||||||
|
radius_words = self.get_radius_words(radius, "Short")
|
||||||
radius_words = self.get_radius_words(
|
radius_words.next_to(radius.get_center(), LEFT, SMALL_BUFF)
|
||||||
radius, "Short"
|
|
||||||
)
|
|
||||||
|
|
||||||
arc_words = TextMobject("Long arc")
|
arc_words = TextMobject("Long arc")
|
||||||
angle = 9 * DEGREES
|
arc_words.rotate(90 * DEGREES)
|
||||||
arc_words.rotate(angle)
|
arc_words.scale(0.5)
|
||||||
arc_words.scale(0.1)
|
arc_words.next_to(RIGHT, RIGHT)
|
||||||
vect = rotate_vector(RIGHT, angle)
|
|
||||||
arc_words.next_to(vect, vect)
|
|
||||||
arc_words.apply_complex_function(np.exp)
|
arc_words.apply_complex_function(np.exp)
|
||||||
arc_words.scale(2)
|
arc_words.scale(0.8)
|
||||||
arc_words.next_to(
|
arc_words.next_to(
|
||||||
arc.point_from_proportion(0.5),
|
arc, RIGHT, buff=-SMALL_BUFF
|
||||||
rotate_vector(vect, 90 * DEGREES),
|
|
||||||
buff=-MED_SMALL_BUFF,
|
|
||||||
)
|
)
|
||||||
arc_words.match_color(arc)
|
arc_words.match_color(arc)
|
||||||
|
|
||||||
|
@ -1934,14 +1948,30 @@ class KeplersSecondLaw(AskAboutEllipses):
|
||||||
|
|
||||||
# Show narrow arc
|
# Show narrow arc
|
||||||
# (Code repetition...uck)
|
# (Code repetition...uck)
|
||||||
start_prop = 0.4
|
start_prop = 0.475
|
||||||
self.wait_until_proportion(start_prop)
|
self.wait_until_proportion(start_prop)
|
||||||
area = self.show_area_sweep()
|
self.show_area_sweep()
|
||||||
end_prop = max(0.45, orbit.proportion)
|
end_prop = orbit.proportion
|
||||||
arc = self.get_arc(start_prop, end_prop)
|
short_arc = self.get_arc(start_prop, end_prop)
|
||||||
radius = Line(sun_point, arc.points[0])
|
long_radius = Line(sun_point, short_arc.points[0])
|
||||||
radius.set_color(PINK)
|
long_radius.set_color(WHITE)
|
||||||
radius_words = self.get_radius_words(radius, "Long")
|
long_radius_words = self.get_radius_words(long_radius, "Long")
|
||||||
|
|
||||||
|
short_arc_words = TextMobject("Short arc")
|
||||||
|
short_arc_words.scale(0.5)
|
||||||
|
short_arc_words.rotate(90 * DEGREES)
|
||||||
|
short_arc_words.next_to(short_arc, LEFT, SMALL_BUFF)
|
||||||
|
short_arc_words.match_color(short_arc)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ShowCreation(long_radius),
|
||||||
|
Write(long_radius_words),
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
ShowCreation(short_arc),
|
||||||
|
Write(short_arc_words)
|
||||||
|
)
|
||||||
|
self.wait(15)
|
||||||
|
|
||||||
# Helpers
|
# Helpers
|
||||||
def show_area_sweep(self, time=1.0):
|
def show_area_sweep(self, time=1.0):
|
||||||
|
@ -1986,7 +2016,6 @@ class KeplersSecondLaw(AskAboutEllipses):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_arc(self, prop1, prop2):
|
def get_arc(self, prop1, prop2):
|
||||||
sun_point = self.sun.get_center()
|
|
||||||
ellipse = self.get_ellipse()
|
ellipse = self.get_ellipse()
|
||||||
prop1 = prop1 % 1.0
|
prop1 = prop1 % 1.0
|
||||||
prop2 = prop2 % 1.0
|
prop2 = prop2 % 1.0
|
||||||
|
@ -2019,18 +2048,371 @@ class KeplersSecondLaw(AskAboutEllipses):
|
||||||
if self.skip_animations:
|
if self.skip_animations:
|
||||||
self.orbit.proportion = prop
|
self.orbit.proportion = prop
|
||||||
else:
|
else:
|
||||||
while self.orbit.proportion < prop:
|
while (self.orbit.proportion % 1) < prop:
|
||||||
self.wait(0.2)
|
self.wait(self.frame_duration)
|
||||||
|
|
||||||
def get_radius_words(self, radius, adjective):
|
def get_radius_words(self, radius, adjective):
|
||||||
radius_words = TextMobject(
|
radius_words = TextMobject(
|
||||||
"%s radius" % adjective,
|
"%s radius" % adjective,
|
||||||
)
|
)
|
||||||
radius_words.scale_to_fit_width(
|
min_width = 0.8 * radius.get_length()
|
||||||
0.8 * radius.get_length()
|
if radius_words.get_width() > min_width:
|
||||||
)
|
radius_words.scale_to_fit_width(min_width)
|
||||||
radius_words.match_color(radius)
|
radius_words.match_color(radius)
|
||||||
radius_words.next_to(ORIGIN, DOWN, SMALL_BUFF)
|
radius_words.next_to(ORIGIN, UP, SMALL_BUFF)
|
||||||
radius_words.rotate(radius.get_angle(), about_point=ORIGIN)
|
angle = radius.get_angle()
|
||||||
|
angle = ((angle + PI) % TAU) - PI
|
||||||
|
if np.abs(angle) > PI / 2:
|
||||||
|
angle += PI
|
||||||
|
radius_words.rotate(angle, about_point=ORIGIN)
|
||||||
radius_words.shift(radius.get_center())
|
radius_words.shift(radius.get_center())
|
||||||
return radius_words
|
return radius_words
|
||||||
|
|
||||||
|
|
||||||
|
class AngularMomentumArgument(KeplersSecondLaw):
|
||||||
|
CONFIG = {
|
||||||
|
"animate_sun": False,
|
||||||
|
"sun_center": 4 * RIGHT + DOWN,
|
||||||
|
"comet_start_point": 4 * LEFT,
|
||||||
|
"comet_end_point": 5 * LEFT + DOWN,
|
||||||
|
"comet_height": 0.3,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.add_sun()
|
||||||
|
self.show_small_sweep()
|
||||||
|
self.show_sweep_dimensions()
|
||||||
|
self.show_conservation_of_angular_momentum()
|
||||||
|
|
||||||
|
def show_small_sweep(self):
|
||||||
|
sun_center = self.sun_center
|
||||||
|
comet_start = self.comet_start_point
|
||||||
|
comet_end = self.comet_end_point
|
||||||
|
triangle = Polygon(
|
||||||
|
sun_center, comet_start, comet_end,
|
||||||
|
fill_opacity=1,
|
||||||
|
fill_color=COBALT,
|
||||||
|
stroke_width=0,
|
||||||
|
)
|
||||||
|
triangle.save_state()
|
||||||
|
alt_triangle = Polygon(
|
||||||
|
sun_center,
|
||||||
|
interpolate(comet_start, comet_end, 0.9),
|
||||||
|
comet_end
|
||||||
|
)
|
||||||
|
alt_triangle.match_style(triangle)
|
||||||
|
|
||||||
|
comet = self.get_comet()
|
||||||
|
comet.move_to(comet_start)
|
||||||
|
|
||||||
|
velocity_vector = Arrow(
|
||||||
|
comet_start, comet_end,
|
||||||
|
color=WHITE,
|
||||||
|
buff=0
|
||||||
|
)
|
||||||
|
velocity_vector_label = TexMobject("\\vec{\\textbf{v}}")
|
||||||
|
velocity_vector_label.next_to(
|
||||||
|
velocity_vector.get_center(), UL,
|
||||||
|
buff=SMALL_BUFF
|
||||||
|
)
|
||||||
|
|
||||||
|
small_time_label = TextMobject(
|
||||||
|
"Small", "time", "$\\Delta t$",
|
||||||
|
)
|
||||||
|
small_time_label.to_edge(UP)
|
||||||
|
small = small_time_label.get_part_by_tex("Small")
|
||||||
|
small_rect = SurroundingRectangle(small)
|
||||||
|
|
||||||
|
self.add_foreground_mobjects(comet)
|
||||||
|
self.play(
|
||||||
|
ShowCreation(
|
||||||
|
triangle,
|
||||||
|
rate_func=lambda t: interpolate(1.0 / 3, 2.0 / 3, t)
|
||||||
|
),
|
||||||
|
MaintainPositionRelativeTo(
|
||||||
|
velocity_vector, comet
|
||||||
|
),
|
||||||
|
MaintainPositionRelativeTo(
|
||||||
|
velocity_vector_label,
|
||||||
|
velocity_vector,
|
||||||
|
),
|
||||||
|
ApplyMethod(
|
||||||
|
comet.move_to, comet_end,
|
||||||
|
rate_func=None,
|
||||||
|
),
|
||||||
|
run_time=2,
|
||||||
|
)
|
||||||
|
self.play(Write(small_time_label), run_time=2)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
Transform(triangle, alt_triangle),
|
||||||
|
ShowCreation(small_rect),
|
||||||
|
small.set_color, YELLOW,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
Restore(triangle),
|
||||||
|
FadeOut(small_rect),
|
||||||
|
small.set_color, WHITE,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
self.triangle = triangle
|
||||||
|
self.comet = comet
|
||||||
|
self.delta_t = small_time_label.get_part_by_tex(
|
||||||
|
"$\\Delta t$"
|
||||||
|
)
|
||||||
|
self.velocity_vector = velocity_vector
|
||||||
|
self.small_time_label = small_time_label
|
||||||
|
|
||||||
|
def show_sweep_dimensions(self):
|
||||||
|
triangle = self.triangle
|
||||||
|
# velocity_vector = self.velocity_vector
|
||||||
|
delta_t = self.delta_t
|
||||||
|
comet = self.comet
|
||||||
|
|
||||||
|
triangle_points = triangle.get_anchors()[:3]
|
||||||
|
top = triangle_points[1]
|
||||||
|
|
||||||
|
area_label = TexMobject(
|
||||||
|
"\\text{Area}", "=", "\\frac{1}{2}",
|
||||||
|
"\\text{Base}", "\\times", "\\text{Height}",
|
||||||
|
)
|
||||||
|
area_label.set_color_by_tex_to_color_map({
|
||||||
|
"Base": PINK,
|
||||||
|
"Height": YELLOW,
|
||||||
|
})
|
||||||
|
area_label.to_edge(UP)
|
||||||
|
equals = area_label.get_part_by_tex("=")
|
||||||
|
area_expression = TexMobject(
|
||||||
|
"=", "\\frac{1}{2}", "R", "\\times",
|
||||||
|
"\\vec{\\textbf{v}}_\\perp",
|
||||||
|
"\\Delta t",
|
||||||
|
)
|
||||||
|
area_expression.set_color_by_tex_to_color_map({
|
||||||
|
"R": PINK,
|
||||||
|
"textbf{v}": YELLOW,
|
||||||
|
})
|
||||||
|
area_expression.next_to(area_label, DOWN)
|
||||||
|
area_expression.align_to(equals, LEFT)
|
||||||
|
|
||||||
|
self.R_v_perp = VGroup(*area_expression[-4:-1])
|
||||||
|
self.R_v_perp_rect = SurroundingRectangle(
|
||||||
|
self.R_v_perp,
|
||||||
|
stroke_color=BLUE,
|
||||||
|
fill_color=BLACK,
|
||||||
|
fill_opacity=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
base = Line(triangle_points[2], triangle_points[0])
|
||||||
|
base.set_stroke(PINK, 3)
|
||||||
|
base_point = line_intersection(
|
||||||
|
base.get_start_and_end(),
|
||||||
|
[top, top + DOWN]
|
||||||
|
)
|
||||||
|
height = Line(top, base_point)
|
||||||
|
height.set_stroke(YELLOW, 3)
|
||||||
|
|
||||||
|
radius_label = TextMobject("Radius")
|
||||||
|
radius_label.next_to(base, DOWN, SMALL_BUFF)
|
||||||
|
radius_label.match_color(base)
|
||||||
|
|
||||||
|
R_term = area_expression.get_part_by_tex("R")
|
||||||
|
R_term.save_state()
|
||||||
|
R_term.move_to(radius_label[0])
|
||||||
|
R_term.set_fill(opacity=0.5)
|
||||||
|
|
||||||
|
v_perp = Arrow(*height.get_start_and_end(), buff=0)
|
||||||
|
v_perp.set_color(YELLOW)
|
||||||
|
v_perp.shift(comet.get_center() - v_perp.get_start())
|
||||||
|
v_perp_label = TexMobject(
|
||||||
|
"\\vec{\\textbf{v}}_\\perp"
|
||||||
|
)
|
||||||
|
v_perp_label.set_color(YELLOW)
|
||||||
|
v_perp_label.next_to(v_perp, RIGHT, buff=SMALL_BUFF)
|
||||||
|
|
||||||
|
v_perp_delta_t = VGroup(v_perp_label.copy(), delta_t.copy())
|
||||||
|
v_perp_delta_t.generate_target()
|
||||||
|
v_perp_delta_t.target.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
|
||||||
|
v_perp_delta_t.target.next_to(height, RIGHT, SMALL_BUFF)
|
||||||
|
self.small_time_label.add(v_perp_delta_t[1])
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeInFromDown(area_label),
|
||||||
|
self.small_time_label.scale, 0.5,
|
||||||
|
self.small_time_label.to_corner, UL,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
ShowCreation(base),
|
||||||
|
Write(radius_label),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(ShowCreation(height))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
GrowArrow(v_perp),
|
||||||
|
Write(v_perp_label, run_time=1),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(MoveToTarget(v_perp_delta_t))
|
||||||
|
self.wait()
|
||||||
|
self.play(*[
|
||||||
|
ReplacementTransform(
|
||||||
|
area_label.get_part_by_tex(tex).copy(),
|
||||||
|
area_expression.get_part_by_tex(tex),
|
||||||
|
)
|
||||||
|
for tex in "=", "\\frac{1}{2}", "\\times"
|
||||||
|
])
|
||||||
|
self.play(Restore(R_term))
|
||||||
|
self.play(ReplacementTransform(
|
||||||
|
v_perp_delta_t.copy(),
|
||||||
|
VGroup(*area_expression[-2:])
|
||||||
|
))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def show_conservation_of_angular_momentum(self):
|
||||||
|
R_v_perp = self.R_v_perp
|
||||||
|
R_v_perp_rect = self.R_v_perp_rect
|
||||||
|
sun_center = self.sun_center
|
||||||
|
comet = self.comet
|
||||||
|
comet.save_state()
|
||||||
|
|
||||||
|
vector_field = VectorField(
|
||||||
|
get_force_field_func((sun_center, -1))
|
||||||
|
)
|
||||||
|
vector_field.set_fill(opacity=0.8)
|
||||||
|
vector_field.sort_submobjects(
|
||||||
|
lambda p: -np.linalg.norm(p - sun_center)
|
||||||
|
)
|
||||||
|
|
||||||
|
stays_constant = TextMobject("Stays constant")
|
||||||
|
stays_constant.next_to(
|
||||||
|
R_v_perp_rect, DR, buff=MED_LARGE_BUFF
|
||||||
|
)
|
||||||
|
stays_constant.match_color(R_v_perp_rect)
|
||||||
|
stays_constant_arrow = Arrow(
|
||||||
|
stays_constant.get_left(),
|
||||||
|
R_v_perp_rect.get_bottom(),
|
||||||
|
color=R_v_perp_rect.get_color()
|
||||||
|
)
|
||||||
|
|
||||||
|
sun_dot = Dot(sun_center, fill_opacity=0.25)
|
||||||
|
big_dot = Dot(fill_opacity=0, radius=FRAME_WIDTH)
|
||||||
|
|
||||||
|
R_v_perp.save_state()
|
||||||
|
R_v_perp.generate_target()
|
||||||
|
R_v_perp.target.to_edge(LEFT, buff=MED_LARGE_BUFF)
|
||||||
|
lp, rp = parens = TexMobject("()")
|
||||||
|
lp.next_to(R_v_perp.target, LEFT)
|
||||||
|
rp.next_to(R_v_perp.target, RIGHT)
|
||||||
|
|
||||||
|
self.play(Transform(
|
||||||
|
big_dot, sun_dot,
|
||||||
|
run_time=1,
|
||||||
|
remover=True
|
||||||
|
))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
DrawBorderThenFill(R_v_perp_rect),
|
||||||
|
Animation(R_v_perp),
|
||||||
|
Write(stays_constant, run_time=1),
|
||||||
|
GrowArrow(stays_constant_arrow),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
foreground = VGroup(*self.get_mobjects())
|
||||||
|
self.play(
|
||||||
|
LaggedStart(GrowArrow, vector_field),
|
||||||
|
Animation(foreground)
|
||||||
|
)
|
||||||
|
for x in range(3):
|
||||||
|
self.play(
|
||||||
|
LaggedStart(
|
||||||
|
ApplyFunction, vector_field,
|
||||||
|
lambda mob: (lambda m: m.scale(1.1).set_fill(opacity=1), mob),
|
||||||
|
rate_func=there_and_back,
|
||||||
|
run_time=1
|
||||||
|
),
|
||||||
|
Animation(foreground)
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
FadeIn(parens),
|
||||||
|
MoveToTarget(R_v_perp),
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
comet.scale, 2,
|
||||||
|
comet.next_to, parens, RIGHT, {"buff": SMALL_BUFF}
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
FadeOut(parens),
|
||||||
|
R_v_perp.restore,
|
||||||
|
comet.restore,
|
||||||
|
)
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
|
|
||||||
|
class KeplersSecondLawImage(KeplersSecondLaw):
|
||||||
|
CONFIG = {
|
||||||
|
"animate_sun": False,
|
||||||
|
"n_sample_sweeps": 8,
|
||||||
|
"fade_sample_areas": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.add_sun()
|
||||||
|
self.add_foreground_mobjects(self.sun)
|
||||||
|
self.add_orbit()
|
||||||
|
self.add_foreground_mobjects(self.comet)
|
||||||
|
self.show_several_sweeps()
|
||||||
|
|
||||||
|
|
||||||
|
class HistoryOfAngularMomentum(TeacherStudentsScene):
|
||||||
|
CONFIG = {
|
||||||
|
"camera_config": {"fill_opacity": 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
am = VGroup(TextMobject("Angular momentum"))
|
||||||
|
k2l = TextMobject("Kepler's 2nd law")
|
||||||
|
arrow = Arrow(ORIGIN, RIGHT)
|
||||||
|
|
||||||
|
group = VGroup(am, arrow, k2l)
|
||||||
|
group.arrange_submobjects(RIGHT)
|
||||||
|
group.next_to(self.hold_up_spot, UL)
|
||||||
|
|
||||||
|
k2l_image = ImageMobject("Kepler2ndLaw")
|
||||||
|
k2l_image.match_width(k2l)
|
||||||
|
k2l_image.next_to(k2l, UP)
|
||||||
|
k2l.add(k2l_image)
|
||||||
|
|
||||||
|
angular_momentum_formula = TexMobject(
|
||||||
|
"R", "\\times", "m", "\\vec{\\textbf{v}}_\\perp",
|
||||||
|
)
|
||||||
|
angular_momentum_formula.set_color_by_tex_to_color_map({
|
||||||
|
"R": PINK,
|
||||||
|
"v": YELLOW,
|
||||||
|
})
|
||||||
|
angular_momentum_formula.next_to(am, UP)
|
||||||
|
am.add(angular_momentum_formula)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
self.teacher.change, "raise_right_hand",
|
||||||
|
FadeInFromDown(group),
|
||||||
|
self.get_student_changes(*3 * ["pondering"])
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
am.next_to, arrow, RIGHT,
|
||||||
|
{"index_of_submobject_to_align": 0},
|
||||||
|
k2l.next_to, arrow, LEFT,
|
||||||
|
{"index_of_submobject_to_align": 0},
|
||||||
|
path_arc=90 * DEGREES,
|
||||||
|
run_time=2
|
||||||
|
)
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
|
|
||||||
|
class FeynmanRecountingNewton(Scene):
|
||||||
|
def construct(self):
|
||||||
|
pass
|
||||||
|
|
Loading…
Add table
Reference in a new issue