mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 20:43:56 +08:00
496 lines
15 KiB
Python
496 lines
15 KiB
Python
import numpy as np
|
|
import itertools as it
|
|
|
|
from manimlib.imports import *
|
|
from old_projects.brachistochrone.curves import Cycloid
|
|
|
|
class PhysicalIntuition(Scene):
|
|
def construct(self):
|
|
n_terms = 4
|
|
def func(xxx_todo_changeme):
|
|
(x, y, ignore) = xxx_todo_changeme
|
|
z = complex(x, y)
|
|
if (np.abs(x%1 - 0.5)<0.01 and y < 0.01) or np.abs(z)<0.01:
|
|
return ORIGIN
|
|
out_z = 1./(2*np.tan(np.pi*z)*(z**2))
|
|
return out_z.real*RIGHT - out_z.imag*UP
|
|
arrows = Mobject(*[
|
|
Arrow(ORIGIN, np.sqrt(2)*point)
|
|
for point in compass_directions(4, RIGHT+UP)
|
|
])
|
|
arrows.set_color(YELLOW)
|
|
arrows.ingest_submobjects()
|
|
all_arrows = Mobject(*[
|
|
arrows.copy().scale(0.3/(x)).shift(x*RIGHT)
|
|
for x in range(1, n_terms+2)
|
|
])
|
|
terms = TexMobject([
|
|
"\\dfrac{1}{%d^2} + "%(x+1)
|
|
for x in range(n_terms)
|
|
]+["\\cdots"])
|
|
terms.shift(2*UP)
|
|
plane = NumberPlane(color = BLUE_E)
|
|
axes = Mobject(NumberLine(), NumberLine().rotate(np.pi/2))
|
|
axes.set_color(WHITE)
|
|
|
|
for term in terms.split():
|
|
self.play(ShimmerIn(term, run_time = 0.5))
|
|
self.wait()
|
|
self.play(ShowCreation(plane), ShowCreation(axes))
|
|
self.play(*[
|
|
Transform(*pair)
|
|
for pair in zip(terms.split(), all_arrows.split())
|
|
])
|
|
self.play(PhaseFlow(
|
|
func, plane,
|
|
run_time = 5,
|
|
virtual_time = 8
|
|
))
|
|
|
|
|
|
|
|
class TimeLine(Scene):
|
|
def construct(self):
|
|
dated_events = [
|
|
{
|
|
"date" : 1696,
|
|
"text": "Johann Bernoulli poses Brachistochrone problem",
|
|
"picture" : "Johann_Bernoulli2"
|
|
},
|
|
{
|
|
"date" : 1662,
|
|
"text" : "Fermat states his principle of least time",
|
|
"picture" : "Pierre_de_Fermat"
|
|
}
|
|
]
|
|
speical_dates = [2016] + [
|
|
obj["date"] for obj in dated_events
|
|
]
|
|
centuries = list(range(1600, 2100, 100))
|
|
timeline = NumberLine(
|
|
numerical_radius = 300,
|
|
number_at_center = 1800,
|
|
unit_length_to_spatial_width = FRAME_X_RADIUS/100,
|
|
tick_frequency = 10,
|
|
numbers_with_elongated_ticks = centuries
|
|
)
|
|
timeline.add_numbers(*centuries)
|
|
centers = [
|
|
Point(timeline.number_to_point(year))
|
|
for year in speical_dates
|
|
]
|
|
timeline.add(*centers)
|
|
timeline.shift(-centers[0].get_center())
|
|
|
|
self.add(timeline)
|
|
self.wait()
|
|
run_times = iter([3, 1])
|
|
for point, event in zip(centers[1:], dated_events):
|
|
self.play(ApplyMethod(
|
|
timeline.shift, -point.get_center(),
|
|
run_time = next(run_times)
|
|
))
|
|
picture = ImageMobject(event["picture"], invert = False)
|
|
picture.set_width(2)
|
|
picture.to_corner(UP+RIGHT)
|
|
event_mob = TextMobject(event["text"])
|
|
event_mob.shift(2*LEFT+2*UP)
|
|
date_mob = TexMobject(str(event["date"]))
|
|
date_mob.scale(0.5)
|
|
date_mob.shift(0.6*UP)
|
|
line = Line(event_mob.get_bottom(), 0.2*UP)
|
|
self.play(
|
|
ShimmerIn(event_mob),
|
|
ShowCreation(line),
|
|
ShimmerIn(date_mob)
|
|
)
|
|
self.play(FadeIn(picture))
|
|
self.wait(3)
|
|
self.play(*list(map(FadeOut, [event_mob, date_mob, line, picture])))
|
|
|
|
|
|
class StayedUpAllNight(Scene):
|
|
def construct(self):
|
|
clock = Circle(radius = 2, color = WHITE)
|
|
clock.add(Dot(ORIGIN))
|
|
ticks = Mobject(*[
|
|
Line(1.8*vect, 2*vect, color = GREY)
|
|
for vect in compass_directions(12)
|
|
])
|
|
clock.add(ticks)
|
|
hour_hand = Line(ORIGIN, UP)
|
|
minute_hand = Line(ORIGIN, 1.5*UP)
|
|
clock.add(hour_hand, minute_hand)
|
|
clock.to_corner(UP+RIGHT)
|
|
hour_hand.get_center = lambda : clock.get_center()
|
|
minute_hand.get_center = lambda : clock.get_center()
|
|
|
|
solution = ImageMobject(
|
|
"Newton_brachistochrone_solution2",
|
|
use_cache = False
|
|
)
|
|
solution.stroke_width = 3
|
|
solution.set_color(GREY)
|
|
solution.set_width(5)
|
|
solution.to_corner(UP+RIGHT)
|
|
newton = ImageMobject("Old_Newton", invert = False)
|
|
newton.scale(0.8)
|
|
phil_trans = TextMobject("Philosophical Transactions")
|
|
rect = Rectangle(height = 6, width = 4.5, color = WHITE)
|
|
rect.to_corner(UP+RIGHT)
|
|
rect.shift(DOWN)
|
|
phil_trans.set_width(0.8*rect.get_width())
|
|
phil_trans.next_to(Point(rect.get_top()), DOWN)
|
|
new_solution = solution.copy()
|
|
new_solution.set_width(phil_trans.get_width())
|
|
new_solution.next_to(phil_trans, DOWN, buff = 1)
|
|
not_newton = TextMobject("-Totally not by Newton")
|
|
not_newton.set_width(2.5)
|
|
not_newton.next_to(new_solution, DOWN, aligned_edge = RIGHT)
|
|
phil_trans.add(rect)
|
|
|
|
newton_complaint = TextMobject([
|
|
"``I do not love to be",
|
|
" \\emph{dunned} ",
|
|
"and teased by foreigners''"
|
|
], size = "\\small")
|
|
newton_complaint.to_edge(UP, buff = 0.2)
|
|
dunned = newton_complaint.split()[1]
|
|
dunned.set_color()
|
|
dunned_def = TextMobject("(old timey term for making \\\\ demands on someone)")
|
|
dunned_def.scale(0.7)
|
|
dunned_def.next_to(phil_trans, LEFT)
|
|
dunned_def.shift(2*UP)
|
|
dunned_arrow = Arrow(dunned_def, dunned)
|
|
|
|
johann = ImageMobject("Johann_Bernoulli2", invert = False)
|
|
johann.scale(0.4)
|
|
johann.to_edge(LEFT)
|
|
johann.shift(DOWN)
|
|
johann_quote = TextMobject("``I recognize the lion by his claw''")
|
|
johann_quote.next_to(johann, UP, aligned_edge = LEFT)
|
|
|
|
self.play(ApplyMethod(newton.to_edge, LEFT))
|
|
self.play(ShowCreation(clock))
|
|
kwargs = {
|
|
"axis" : OUT,
|
|
"rate_func" : smooth
|
|
}
|
|
self.play(
|
|
Rotating(hour_hand, radians = -2*np.pi, **kwargs),
|
|
Rotating(minute_hand, radians = -12*2*np.pi, **kwargs),
|
|
run_time = 5
|
|
)
|
|
self.wait()
|
|
self.clear()
|
|
self.add(newton)
|
|
clock.ingest_submobjects()
|
|
self.play(Transform(clock, solution))
|
|
self.remove(clock)
|
|
self.add(solution)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(phil_trans),
|
|
Transform(solution, new_solution)
|
|
)
|
|
self.wait()
|
|
self.play(ShimmerIn(not_newton))
|
|
phil_trans.add(solution, not_newton)
|
|
self.wait()
|
|
self.play(*list(map(ShimmerIn, newton_complaint.split())))
|
|
self.wait()
|
|
self.play(
|
|
ShimmerIn(dunned_def),
|
|
ShowCreation(dunned_arrow)
|
|
)
|
|
self.wait()
|
|
self.remove(dunned_def, dunned_arrow)
|
|
self.play(FadeOut(newton_complaint))
|
|
self.remove(newton_complaint)
|
|
self.play(
|
|
FadeOut(newton),
|
|
GrowFromCenter(johann)
|
|
)
|
|
self.remove(newton)
|
|
self.wait()
|
|
self.play(ShimmerIn(johann_quote))
|
|
self.wait()
|
|
|
|
|
|
class ThetaTGraph(Scene):
|
|
def construct(self):
|
|
t_axis = NumberLine()
|
|
theta_axis = NumberLine().rotate(np.pi/2)
|
|
theta_mob = TexMobject("\\theta(t)")
|
|
t_mob = TexMobject("t")
|
|
theta_mob.next_to(theta_axis, RIGHT)
|
|
theta_mob.to_edge(UP)
|
|
t_mob.next_to(t_axis, UP)
|
|
t_mob.to_edge(RIGHT)
|
|
graph = ParametricFunction(
|
|
lambda t : 4*t*RIGHT + 2*smooth(t)*UP
|
|
)
|
|
line = Line(graph.points[0], graph.points[-1], color = WHITE)
|
|
q_mark = TextMobject("?")
|
|
q_mark.next_to(Point(graph.get_center()), LEFT)
|
|
stars = Stars(color = BLACK)
|
|
stars.scale(0.1).shift(q_mark.get_center())
|
|
|
|
|
|
squiggle = ParametricFunction(
|
|
lambda t : t*RIGHT + 0.2*t*(5-t)*(np.sin(t)**2)*UP,
|
|
start = 0,
|
|
end = 5
|
|
)
|
|
|
|
self.play(
|
|
ShowCreation(t_axis),
|
|
ShowCreation(theta_axis),
|
|
ShimmerIn(theta_mob),
|
|
ShimmerIn(t_mob)
|
|
)
|
|
self.play(
|
|
ShimmerIn(q_mark),
|
|
ShowCreation(graph)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
Transform(q_mark, stars),
|
|
Transform(graph, line)
|
|
)
|
|
self.wait()
|
|
self.play(Transform(graph, squiggle))
|
|
self.wait()
|
|
|
|
|
|
class SolutionsToTheBrachistochrone(Scene):
|
|
def construct(self):
|
|
r_range = np.arange(0.5, 2, 0.25)
|
|
cycloids = Mobject(*[
|
|
Cycloid(radius = r, end_theta=2*np.pi)
|
|
for r in r_range
|
|
])
|
|
lower_left = 2*DOWN+6*LEFT
|
|
lines = Mobject(*[
|
|
Line(
|
|
lower_left,
|
|
lower_left+5*r*np.cos(np.arctan(r))*RIGHT+2*r*np.sin(np.arctan(r))*UP
|
|
)
|
|
for r in r_range
|
|
])
|
|
nl = NumberLine(numbers_with_elongated_ticks = [])
|
|
x_axis = nl.copy().shift(3*UP)
|
|
y_axis = nl.copy().rotate(np.pi/2).shift(6*LEFT)
|
|
t_axis = nl.copy().shift(2*DOWN)
|
|
x_label = TexMobject("x")
|
|
x_label.next_to(x_axis, DOWN)
|
|
x_label.to_edge(RIGHT)
|
|
y_label = TexMobject("y")
|
|
y_label.next_to(y_axis, RIGHT)
|
|
y_label.shift(2*DOWN)
|
|
t_label = TexMobject("t")
|
|
t_label.next_to(t_axis, UP)
|
|
t_label.to_edge(RIGHT)
|
|
theta_label = TexMobject("\\theta")
|
|
theta_label.next_to(y_axis, RIGHT)
|
|
theta_label.to_edge(UP)
|
|
words = TextMobject("Boundary conditions?")
|
|
words.next_to(lines, RIGHT)
|
|
words.shift(2*UP)
|
|
|
|
self.play(ShowCreation(x_axis), ShimmerIn(x_label))
|
|
self.play(ShowCreation(y_axis), ShimmerIn(y_label))
|
|
self.play(ShowCreation(cycloids))
|
|
self.wait()
|
|
self.play(
|
|
Transform(cycloids, lines),
|
|
Transform(x_axis, t_axis),
|
|
Transform(x_label, t_label),
|
|
Transform(y_label, theta_label),
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
self.play(ShimmerIn(words))
|
|
self.wait()
|
|
|
|
|
|
class VideoLayout(Scene):
|
|
def construct(self):
|
|
left, right = 5*LEFT, 5*RIGHT
|
|
top_words = TextMobject("The next 15 minutes of your life:")
|
|
top_words.to_edge(UP)
|
|
line = Line(left, right, color = BLUE_D)
|
|
for a in np.arange(0, 4./3, 1./3):
|
|
vect = interpolate(left, right, a)
|
|
line.add_line(vect+0.2*DOWN, vect+0.2*UP)
|
|
left_brace = Brace(
|
|
Mobject(
|
|
Point(left),
|
|
Point(interpolate(left, right, 2./3))
|
|
),
|
|
DOWN
|
|
)
|
|
right_brace = Brace(
|
|
Mobject(
|
|
Point(interpolate(left, right, 2./3)),
|
|
Point(right)
|
|
),
|
|
UP
|
|
)
|
|
left_brace.words = list(map(TextMobject, [
|
|
"Problem statement",
|
|
"History",
|
|
"Johann Bernoulli's cleverness"
|
|
]))
|
|
curr = left_brace
|
|
right_brace.words = list(map(TextMobject, [
|
|
"Challenge",
|
|
"Mark Levi's cleverness",
|
|
]))
|
|
for brace in left_brace, right_brace:
|
|
curr = brace
|
|
direction = DOWN if brace is left_brace else UP
|
|
for word in brace.words:
|
|
word.next_to(curr, direction)
|
|
curr = word
|
|
right_brace.words.reverse()
|
|
|
|
self.play(ShimmerIn(top_words))
|
|
self.play(ShowCreation(line))
|
|
for brace in left_brace, right_brace:
|
|
self.play(GrowFromCenter(brace))
|
|
self.wait()
|
|
for word in brace.words:
|
|
self.play(ShimmerIn(word))
|
|
self.wait()
|
|
|
|
|
|
|
|
|
|
class ShortestPathProblem(Scene):
|
|
def construct(self):
|
|
point_a, point_b = 3*LEFT, 3*RIGHT
|
|
dots = []
|
|
for point, char in [(point_a, "A"), (point_b, "B")]:
|
|
dot = Dot(point)
|
|
letter = TexMobject(char)
|
|
letter.next_to(dot, UP+LEFT)
|
|
dot.add(letter)
|
|
dots.append(dot)
|
|
|
|
path = ParametricFunction(
|
|
lambda t : (t/2 + np.cos(t))*RIGHT + np.sin(t)*UP,
|
|
start = -2*np.pi,
|
|
end = 2*np.pi
|
|
)
|
|
path.scale(6/(2*np.pi))
|
|
path.shift(point_a - path.points[0])
|
|
path.set_color(RED)
|
|
line = Line(point_a, point_b)
|
|
words = TextMobject("Shortest path from $A$ to $B$")
|
|
words.to_edge(UP)
|
|
|
|
self.play(
|
|
ShimmerIn(words),
|
|
*list(map(GrowFromCenter, dots))
|
|
)
|
|
self.play(ShowCreation(path))
|
|
self.play(Transform(
|
|
path, line,
|
|
path_func = path_along_arc(np.pi)
|
|
))
|
|
self.wait()
|
|
|
|
|
|
class MathBetterThanTalking(Scene):
|
|
def construct(self):
|
|
mathy = Mathematician()
|
|
mathy.to_corner(DOWN+LEFT)
|
|
bubble = ThoughtBubble()
|
|
bubble.pin_to(mathy)
|
|
bubble.write("Math $>$ Talking about math")
|
|
|
|
self.add(mathy)
|
|
self.play(ShowCreation(bubble))
|
|
self.play(ShimmerIn(bubble.content))
|
|
self.wait()
|
|
self.play(ApplyMethod(
|
|
mathy.blink,
|
|
rate_func = squish_rate_func(there_and_back, 0.4, 0.6)
|
|
))
|
|
|
|
|
|
class DetailsOfProofBox(Scene):
|
|
def construct(self):
|
|
rect = Rectangle(height = 4, width = 6, color = WHITE)
|
|
words = TextMobject("Details of proof")
|
|
words.to_edge(UP)
|
|
|
|
self.play(
|
|
ShowCreation(rect),
|
|
ShimmerIn(words)
|
|
)
|
|
self.wait()
|
|
|
|
|
|
|
|
class TalkedAboutSnellsLaw(Scene):
|
|
def construct(self):
|
|
randy = Randolph()
|
|
randy.to_corner(DOWN+LEFT)
|
|
morty = Mortimer()
|
|
morty.to_edge(DOWN+RIGHT)
|
|
randy.bubble = SpeechBubble().pin_to(randy)
|
|
morty.bubble = SpeechBubble().pin_to(morty)
|
|
|
|
phrases = [
|
|
"Let's talk about Snell's law",
|
|
"I love Snell's law",
|
|
"It's like running from \\\\ a beach into the ocean",
|
|
"It's like two constant \\\\ tension springs",
|
|
]
|
|
|
|
self.add(randy, morty)
|
|
talkers = it.cycle([randy, morty])
|
|
for talker, phrase in zip(talkers, phrases):
|
|
talker.bubble.write(phrase)
|
|
self.play(
|
|
FadeIn(talker.bubble),
|
|
ShimmerIn(talker.bubble.content)
|
|
)
|
|
self.play(ApplyMethod(
|
|
talker.blink,
|
|
rate_func = squish_rate_func(there_and_back)
|
|
))
|
|
self.wait()
|
|
self.remove(talker.bubble, talker.bubble.content)
|
|
|
|
|
|
class YetAnotherMarkLevi(Scene):
|
|
def construct(self):
|
|
words = TextMobject("Yet another bit of Mark Levi cleverness")
|
|
words.to_edge(UP)
|
|
levi = ImageMobject("Mark_Levi", invert = False)
|
|
levi.set_width(6)
|
|
levi.show()
|
|
|
|
self.add(levi)
|
|
self.play(ShimmerIn(words))
|
|
self.wait(2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|