mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 17:29:06 +08:00
Opening animation to lost lecture
This commit is contained in:
@ -2,51 +2,418 @@ from __future__ import absolute_import
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
|
||||
|
||||
class Orbiting(ContinualAnimation):
|
||||
CONFIG = {
|
||||
"rate": 0.3,
|
||||
}
|
||||
|
||||
def __init__(self, planet, star, ellipse, **kwargs):
|
||||
self.planet = planet
|
||||
self.star = star
|
||||
self.ellipse = ellipse
|
||||
# Proportion of the way around the ellipse
|
||||
self.proportion = 0
|
||||
ContinualAnimation.__init__(self, planet, **kwargs)
|
||||
|
||||
def update_mobject(self, dt):
|
||||
# time = self.internal_time
|
||||
rate = self.rate
|
||||
|
||||
planet = self.planet
|
||||
star = self.star
|
||||
ellipse = self.ellipse
|
||||
|
||||
rate *= 1 / np.linalg.norm(
|
||||
planet.get_center() - star.get_center()
|
||||
)
|
||||
self.proportion += rate * dt
|
||||
self.proportion = self.proportion % 1
|
||||
planet.move_to(ellipse.point_from_proportion(self.proportion))
|
||||
|
||||
# Animations
|
||||
|
||||
|
||||
class ShowEmergingEllipse(Scene):
|
||||
CONFIG = {
|
||||
"circle_radius": 3,
|
||||
"circle_color": BLUE,
|
||||
"num_lines": 100,
|
||||
"lines_stroke_width": 1,
|
||||
"eccentricity_vector": 2 * RIGHT,
|
||||
"ghost_lines_stroke_color": LIGHT_GREY,
|
||||
"ghost_lines_stroke_width": 0.5,
|
||||
"ellipse_color": PINK,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
circle = Circle(num_anchors=50, radius=3, color=BLUE)
|
||||
e_point = 2 * RIGHT
|
||||
circle = self.get_circle()
|
||||
e_point = self.get_eccentricity_point()
|
||||
e_dot = Dot(e_point, color=YELLOW)
|
||||
lines = VGroup(*[
|
||||
Line(e_point, circle.point_from_proportion(a))
|
||||
for a in np.linspace(0, 1, 4 * 49)
|
||||
])
|
||||
lines.set_stroke(width=1)
|
||||
for line in lines:
|
||||
line.generate_target()
|
||||
line.target.rotate(90 * DEGREES)
|
||||
lines = self.get_lines()
|
||||
ellipse = self.get_ellipse()
|
||||
|
||||
fade_rect = FullScreenFadeRectangle()
|
||||
line = lines[20]
|
||||
|
||||
line = lines[len(lines) / 5]
|
||||
line_dot = Dot(line.get_center(), color=YELLOW)
|
||||
line_dot.scale(0.5)
|
||||
|
||||
words = TextMobject("Rotate $90^\\circ$ \\\\ about center")
|
||||
words.add_to_back(words.copy().set_stroke(BLACK, 2))
|
||||
words.next_to(line_dot, RIGHT)
|
||||
ghost_line = self.get_ghost_lines(line)
|
||||
ghost_lines = self.get_ghost_lines(lines)
|
||||
|
||||
self.play(
|
||||
LaggedStart(ShowCreation, lines),
|
||||
Animation(VGroup(e_dot, circle))
|
||||
rot_words = TextMobject("Rotate $90^\\circ$ \\\\ about center")
|
||||
rot_words.next_to(line_dot, RIGHT)
|
||||
|
||||
elbow = VGroup(Line(UP, UL), Line(UL, LEFT))
|
||||
elbow.set_stroke(width=1)
|
||||
elbow.scale(0.2, about_point=ORIGIN)
|
||||
elbow.rotate(
|
||||
line.get_angle() - 90 * DEGREES,
|
||||
about_point=ORIGIN
|
||||
)
|
||||
self.add(lines.copy().set_stroke(LIGHT_GREY, 0.5))
|
||||
elbow.shift(line.get_center())
|
||||
|
||||
eccentric_words = TextMobject("``Eccentric'' point")
|
||||
eccentric_words.next_to(circle.get_center(), DOWN)
|
||||
|
||||
ellipse_words = TextMobject("Perfect ellipse")
|
||||
ellipse_words.next_to(ellipse, UP, SMALL_BUFF)
|
||||
|
||||
for text in rot_words, ellipse_words:
|
||||
text.add_to_back(text.copy().set_stroke(BLACK, 5))
|
||||
|
||||
shuffled_lines = VGroup(*lines)
|
||||
random.shuffle(shuffled_lines.submobjects)
|
||||
|
||||
self.play(ShowCreation(circle))
|
||||
self.play(
|
||||
FadeInAndShiftFromDirection(e_dot, LEFT),
|
||||
Write(eccentric_words, run_time=1)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(ShowCreation, shuffled_lines),
|
||||
Animation(VGroup(e_dot, circle)),
|
||||
FadeOut(eccentric_words)
|
||||
)
|
||||
self.add(ghost_lines)
|
||||
self.add(e_dot, circle)
|
||||
self.wait()
|
||||
self.play(FadeIn(fade_rect), Animation(line))
|
||||
self.play(
|
||||
FadeIn(fade_rect),
|
||||
Animation(line),
|
||||
GrowFromCenter(line_dot),
|
||||
FadeInFromDown(words)
|
||||
FadeInFromDown(rot_words),
|
||||
)
|
||||
self.wait()
|
||||
self.add(ghost_line)
|
||||
self.play(
|
||||
MoveToTarget(line, path_arc=90 * DEGREES),
|
||||
Animation(rot_words),
|
||||
ShowCreation(elbow)
|
||||
)
|
||||
self.add_foreground_mobjects(line.copy().set_stroke(LIGHT_GREY, 0.5))
|
||||
self.play(MoveToTarget(line, path_arc=90 * DEGREES))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(fade_rect),
|
||||
FadeOut(line_dot),
|
||||
FadeOut(words),
|
||||
Animation(line)
|
||||
FadeOut(rot_words),
|
||||
FadeOut(elbow),
|
||||
Animation(line),
|
||||
Animation(ghost_line)
|
||||
)
|
||||
self.play(
|
||||
LaggedStart(MoveToTarget, lines, run_time=4),
|
||||
Animation(VGroup(e_dot, circle))
|
||||
)
|
||||
self.wait()
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(ellipse),
|
||||
Write(ellipse_words, run_time=1)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def get_circle(self):
|
||||
circle = self.circle = Circle(
|
||||
radius=self.circle_radius,
|
||||
color=self.circle_color
|
||||
)
|
||||
return circle
|
||||
|
||||
def get_eccentricity_point(self):
|
||||
return self.circle.get_center() + self.eccentricity_vector
|
||||
|
||||
def get_lines(self):
|
||||
center = self.circle.get_center()
|
||||
radius = self.circle.get_width() / 2
|
||||
e_point = self.get_eccentricity_point()
|
||||
lines = VGroup(*[
|
||||
Line(
|
||||
e_point,
|
||||
center + rotate_vector(radius * RIGHT, angle)
|
||||
)
|
||||
for angle in np.linspace(0, TAU, self.num_lines)
|
||||
])
|
||||
lines.set_stroke(width=self.lines_stroke_width)
|
||||
for line in lines:
|
||||
line.generate_target()
|
||||
line.target.rotate(90 * DEGREES)
|
||||
return lines
|
||||
|
||||
def get_ghost_lines(self, lines):
|
||||
return lines.copy().set_stroke(
|
||||
color=self.ghost_lines_stroke_color,
|
||||
width=self.ghost_lines_stroke_width
|
||||
)
|
||||
|
||||
def get_ellipse(self):
|
||||
center = self.circle.get_center()
|
||||
e_point = self.get_eccentricity_point()
|
||||
radius = self.circle.get_width() / 2
|
||||
|
||||
# Ellipse parameters
|
||||
a = radius / 2
|
||||
c = np.linalg.norm(e_point - center) / 2
|
||||
b = np.sqrt(a**2 - c**2)
|
||||
|
||||
result = Circle(radius=b, color=self.ellipse_color)
|
||||
result.stretch(a / b, 0)
|
||||
result.move_to(Line(center, e_point))
|
||||
return result
|
||||
|
||||
|
||||
class FeynmanAndOrbitingPlannetOnEllipseDiagram(ShowEmergingEllipse):
|
||||
def construct(self):
|
||||
circle = self.get_circle()
|
||||
lines = self.get_lines()
|
||||
ghost_lines = self.get_ghost_lines(lines)
|
||||
for line in lines:
|
||||
MoveToTarget(line).update(1)
|
||||
ellipse = self.get_ellipse()
|
||||
e_dot = Dot(self.get_eccentricity_point())
|
||||
e_dot.set_color(YELLOW)
|
||||
|
||||
comet = ImageMobject("earth")
|
||||
comet.scale_to_fit_width(0.3)
|
||||
|
||||
feynman_cut = ImageMobject("FeynmanCut")
|
||||
feynman_cut.scale_to_fit_height(4)
|
||||
feynman_cut.next_to(ORIGIN, LEFT)
|
||||
feynman_cut.shift(UP)
|
||||
feynman_name = TextMobject("Richard Feynman")
|
||||
feynman_name.next_to(feynman_cut, DOWN)
|
||||
feynman_cut.save_state()
|
||||
feynman_cut.shift(2 * DOWN)
|
||||
feynman_rect = BackgroundRectangle(
|
||||
feynman_cut, fill_opacity=1
|
||||
)
|
||||
|
||||
group = VGroup(circle, ghost_lines, lines, e_dot, ellipse)
|
||||
|
||||
self.add(group)
|
||||
self.add(Orbiting(comet, e_dot, ellipse))
|
||||
self.add_foreground_mobjects(comet)
|
||||
self.wait()
|
||||
self.play(
|
||||
feynman_cut.restore,
|
||||
MaintainPositionRelativeTo(feynman_rect, feynman_cut),
|
||||
VFadeOut(feynman_rect),
|
||||
group.to_edge, RIGHT,
|
||||
)
|
||||
self.play(Write(feynman_name))
|
||||
self.wait()
|
||||
self.wait(10)
|
||||
|
||||
|
||||
class FeynmanFame(Scene):
|
||||
def construct(self):
|
||||
books = VGroup(
|
||||
ImageMobject("Feynman_QED_cover"),
|
||||
ImageMobject("Surely_Youre_Joking_cover"),
|
||||
ImageMobject("Feynman_Lectures_cover"),
|
||||
)
|
||||
for book in books:
|
||||
book.scale_to_fit_height(6)
|
||||
book.move_to(FRAME_WIDTH * LEFT / 4)
|
||||
|
||||
feynman_diagram = self.get_feynman_diagram()
|
||||
feynman_diagram.next_to(ORIGIN, RIGHT)
|
||||
fd_parts = VGroup(*reversed(feynman_diagram.family_members_with_points()))
|
||||
|
||||
# As a physicist
|
||||
self.play(self.get_book_intro(books[0]))
|
||||
self.play(LaggedStart(
|
||||
Write, feynman_diagram,
|
||||
run_time=4
|
||||
))
|
||||
self.wait()
|
||||
self.play(
|
||||
self.get_book_intro(books[1]),
|
||||
self.get_book_outro(books[0]),
|
||||
LaggedStart(
|
||||
ApplyMethod, fd_parts,
|
||||
lambda m: (m.scale, 0),
|
||||
run_time=1
|
||||
),
|
||||
)
|
||||
self.remove(feynman_diagram)
|
||||
self.wait()
|
||||
|
||||
# As a public figure
|
||||
safe = SVGMobject(file_name="safe", height=2)
|
||||
safe_rect = SurroundingRectangle(safe, buff=0)
|
||||
safe_rect.set_stroke(width=0)
|
||||
safe_rect.set_fill(DARK_GREY, 1)
|
||||
safe.add_to_back(safe_rect)
|
||||
|
||||
bongo = SVGMobject(file_name="bongo")
|
||||
bongo.scale_to_fit_height(1)
|
||||
bongo.set_color(WHITE)
|
||||
bongo.next_to(safe, RIGHT, LARGE_BUFF)
|
||||
|
||||
objects = VGroup(safe, bongo)
|
||||
|
||||
feynman_smile = ImageMobject("Feynman_smile")
|
||||
feynman_smile.match_width(objects)
|
||||
feynman_smile.next_to(objects, DOWN)
|
||||
|
||||
VGroup(objects, feynman_smile).next_to(ORIGIN, RIGHT)
|
||||
|
||||
joke = TextMobject(
|
||||
"``Science is the belief \\\\ in the ignorance of \\\\ experts.''"
|
||||
)
|
||||
joke.move_to(objects)
|
||||
|
||||
self.play(LaggedStart(
|
||||
DrawBorderThenFill, objects,
|
||||
lag_ratio=0.75
|
||||
))
|
||||
self.play(self.get_book_intro(feynman_smile))
|
||||
self.wait()
|
||||
self.play(
|
||||
objects.shift, 2 * UP,
|
||||
VFadeOut(objects)
|
||||
)
|
||||
self.play(Write(joke))
|
||||
self.wait(2)
|
||||
|
||||
self.play(
|
||||
self.get_book_intro(books[2]),
|
||||
self.get_book_outro(books[1]),
|
||||
LaggedStart(FadeOut, joke, run_time=1),
|
||||
ApplyMethod(
|
||||
feynman_smile.shift, FRAME_HEIGHT * DOWN,
|
||||
remover=True
|
||||
)
|
||||
)
|
||||
|
||||
# As a teacher
|
||||
feynman_teacher = ImageMobject("Feynman_teacher")
|
||||
feynman_teacher.scale_to_fit_width(FRAME_WIDTH / 2 - 1)
|
||||
feynman_teacher.next_to(ORIGIN, RIGHT)
|
||||
|
||||
self.play(self.get_book_intro(feynman_teacher))
|
||||
self.wait(3)
|
||||
|
||||
def get_book_animation(self, book,
|
||||
initial_shift,
|
||||
animated_shift,
|
||||
opacity_func
|
||||
):
|
||||
rect = BackgroundRectangle(book, fill_opacity=1)
|
||||
book.shift(initial_shift)
|
||||
|
||||
return AnimationGroup(
|
||||
ApplyMethod(book.shift, animated_shift),
|
||||
UpdateFromAlphaFunc(
|
||||
rect, lambda r, a: r.move_to(book).set_fill(
|
||||
opacity=opacity_func(a)
|
||||
),
|
||||
remover=True
|
||||
)
|
||||
)
|
||||
|
||||
def get_book_intro(self, book):
|
||||
return self.get_book_animation(
|
||||
book, 2 * DOWN, 2 * UP, lambda a: 1 - a
|
||||
)
|
||||
|
||||
def get_book_outro(self, book):
|
||||
return ApplyMethod(book.shift, FRAME_HEIGHT * UP, remover=True)
|
||||
|
||||
def get_feynman_diagram(self):
|
||||
x_min = -1.5
|
||||
x_max = 1.5
|
||||
arrow = Arrow(LEFT, RIGHT, buff=0, use_rectangular_stem=False)
|
||||
arrow.tip.move_to(arrow.get_center())
|
||||
arrows = VGroup(*[
|
||||
arrow.copy().rotate(angle).next_to(point, vect, buff=0)
|
||||
for (angle, point, vect) in [
|
||||
(-45 * DEGREES, x_min * RIGHT, UL),
|
||||
(-135 * DEGREES, x_min * RIGHT, DL),
|
||||
(-135 * DEGREES, x_max * RIGHT, UR),
|
||||
(-45 * DEGREES, x_max * RIGHT, DR),
|
||||
]
|
||||
])
|
||||
labels = VGroup(*[
|
||||
TexMobject(tex)
|
||||
for tex in ["e^-", "e^+", "\\text{\\=q}", "q"]
|
||||
])
|
||||
vects = [UR, DR, UL, DL]
|
||||
for arrow, label, vect in zip(arrows, labels, vects):
|
||||
label.next_to(arrow.get_center(), vect, buff=SMALL_BUFF)
|
||||
|
||||
wave = FunctionGraph(
|
||||
lambda x: 0.2 * np.sin(2 * TAU * x),
|
||||
x_min=x_min,
|
||||
x_max=x_max,
|
||||
)
|
||||
wave_label = TexMobject("\\gamma")
|
||||
wave_label.next_to(wave, UP, SMALL_BUFF)
|
||||
labels.add(wave_label)
|
||||
|
||||
squiggle = ParametricFunction(
|
||||
lambda t: np.array([
|
||||
t + 0.5 * np.sin(TAU * t),
|
||||
0.5 * np.cos(TAU * t),
|
||||
0,
|
||||
]),
|
||||
t_min=0,
|
||||
t_max=4,
|
||||
)
|
||||
squiggle.scale(0.25)
|
||||
squiggle.set_color(BLUE)
|
||||
squiggle.rotate(-30 * DEGREES)
|
||||
squiggle.next_to(
|
||||
arrows[2].point_from_proportion(0.75),
|
||||
DR, buff=0
|
||||
)
|
||||
squiggle_label = TexMobject("g")
|
||||
squiggle_label.next_to(squiggle, UR, buff=-MED_SMALL_BUFF)
|
||||
labels.add(squiggle_label)
|
||||
|
||||
return VGroup(arrows, wave, squiggle, labels)
|
||||
|
||||
|
||||
class FeynmanLecturesScreenCaptureFrame(Scene):
|
||||
def construct(self):
|
||||
url = TextMobject("http://www.feynmanlectures.caltech.edu/")
|
||||
url.to_edge(UP)
|
||||
|
||||
screen_rect = ScreenRectangle(height=6)
|
||||
screen_rect.next_to(url, DOWN)
|
||||
|
||||
self.add(url)
|
||||
self.play(ShowCreation(screen_rect))
|
||||
self.wait()
|
||||
|
||||
|
||||
class TheMotionOfPlanets(Scene):
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.setup_orbits()
|
||||
|
||||
def add_title(self):
|
||||
pass
|
||||
|
||||
def setup_orbits(self):
|
||||
pass
|
||||
|
Reference in New Issue
Block a user