mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 17:29:06 +08:00
End of brachistochrone problem
This commit is contained in:
@ -203,8 +203,12 @@ class PathSlidingScene(Scene):
|
|||||||
theta = angle_of_vector(point_b - point_a)
|
theta = angle_of_vector(point_b - point_a)
|
||||||
mobject.rotate(theta)
|
mobject.rotate(theta)
|
||||||
mobject.shift(points[index])
|
mobject.shift(points[index])
|
||||||
|
self.midslide_action(point_a, theta)
|
||||||
return mobject
|
return mobject
|
||||||
|
|
||||||
|
def midslide_action(self, point, angle):
|
||||||
|
pass
|
||||||
|
|
||||||
def write_time(self, time):
|
def write_time(self, time):
|
||||||
if hasattr(self, "time_mob"):
|
if hasattr(self, "time_mob"):
|
||||||
self.remove(self.time_mob)
|
self.remove(self.time_mob)
|
||||||
@ -594,10 +598,112 @@ class WhatGovernsSpeed(PathSlidingScene):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ThetaTInsteadOfXY(Scene):
|
||||||
|
def construct(self):
|
||||||
|
cycloid = Cycloid()
|
||||||
|
index = cycloid.get_num_points()/3
|
||||||
|
point = cycloid.points[index]
|
||||||
|
vect = cycloid.points[index+1]-point
|
||||||
|
vect /= np.linalg.norm(vect)
|
||||||
|
vect *= 3
|
||||||
|
vect_mob = Vector(point, vect)
|
||||||
|
dot = Dot(point)
|
||||||
|
xy = TexMobject("\\big( x(t), y(t) \\big)")
|
||||||
|
xy.next_to(dot, UP+RIGHT, buff = 0.1)
|
||||||
|
vert_line = Line(2*DOWN, 2*UP)
|
||||||
|
vert_line.shift(point)
|
||||||
|
angle = vect_mob.get_angle() + np.pi/2
|
||||||
|
arc = Arc(angle, radius = 1, start_angle = -np.pi/2)
|
||||||
|
arc.shift(point)
|
||||||
|
theta = TexMobject("\\theta(t)")
|
||||||
|
theta.next_to(arc, DOWN, buff = 0.1, aligned_edge = LEFT)
|
||||||
|
theta.shift(0.2*RIGHT)
|
||||||
|
|
||||||
|
self.play(ShowCreation(cycloid))
|
||||||
|
self.play(ShowCreation(dot))
|
||||||
|
self.play(ShimmerIn(xy))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
FadeOut(xy),
|
||||||
|
ShowCreation(vect_mob)
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
ShowCreation(arc),
|
||||||
|
ShowCreation(vert_line),
|
||||||
|
ShimmerIn(theta)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class DefineCurveWithKnob(PathSlidingScene):
|
||||||
|
def construct(self):
|
||||||
|
self.knob = Circle(color = BLUE_D)
|
||||||
|
self.knob.add_line(UP, DOWN)
|
||||||
|
self.knob.to_corner(UP+RIGHT)
|
||||||
|
self.knob.shift(0.5*DOWN)
|
||||||
|
self.last_angle = np.pi/2
|
||||||
|
arrow = Vector(ORIGIN, RIGHT)
|
||||||
|
arrow.next_to(self.knob, LEFT)
|
||||||
|
words = TextMobject("Turn this knob over time to define the curve")
|
||||||
|
words.next_to(arrow, LEFT)
|
||||||
|
self.path = self.get_path()
|
||||||
|
self.path.shift(1.5*DOWN)
|
||||||
|
self.path.show()
|
||||||
|
self.path.highlight(BLACK)
|
||||||
|
|
||||||
|
randy = Randolph()
|
||||||
|
randy.scale(RANDY_SCALE_VAL)
|
||||||
|
randy.shift(-randy.get_bottom())
|
||||||
|
|
||||||
|
self.play(ShimmerIn(words))
|
||||||
|
self.play(ShowCreation(arrow))
|
||||||
|
self.play(ShowCreation(self.knob))
|
||||||
|
self.dither()
|
||||||
|
self.add(self.path)
|
||||||
|
|
||||||
|
self.slide(randy, self.path)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
def get_path(self):
|
||||||
|
return Cycloid(end_theta = 2*np.pi)
|
||||||
|
|
||||||
|
def midslide_action(self, point, angle):
|
||||||
|
d_angle = angle-self.last_angle
|
||||||
|
self.knob.rotate_in_place(d_angle)
|
||||||
|
self.last_angle = angle
|
||||||
|
self.path.highlight(BLUE_D, lambda p : p[0] < point[0])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class WonkyDefineCurveWithKnob(DefineCurveWithKnob):
|
||||||
|
def get_path(self):
|
||||||
|
return ParametricFunction(
|
||||||
|
lambda t : t*RIGHT + (-0.2*t-np.sin(2*np.pi*t/6))*UP,
|
||||||
|
start = -7,
|
||||||
|
end = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SlowDefineCurveWithKnob(DefineCurveWithKnob):
|
||||||
|
def get_path(self):
|
||||||
|
return ParametricFunction(
|
||||||
|
lambda t : t*RIGHT + (np.exp(-(t+2)**2)-0.2*np.exp(t-2)),
|
||||||
|
start = -4,
|
||||||
|
end = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BumpyDefineCurveWithKnob(DefineCurveWithKnob):
|
||||||
|
def get_path(self):
|
||||||
|
|
||||||
|
result = FunctionGraph(
|
||||||
|
lambda x : 0.05*(x**2)+0.1*np.sin(2*x)
|
||||||
|
)
|
||||||
|
result.rotate(-np.pi/20)
|
||||||
|
result.scale(0.7)
|
||||||
|
result.shift(DOWN)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -502,34 +502,61 @@ class LeviSolution(CycloidScene):
|
|||||||
class EquationsForCycloid(CycloidScene):
|
class EquationsForCycloid(CycloidScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
CycloidScene.construct(self)
|
CycloidScene.construct(self)
|
||||||
equations = TexMobject("""
|
equations = TexMobject([
|
||||||
x(t) &= Rt - R\\sin(t) \\\\
|
"x(t) = Rt - R\\sin(t)",
|
||||||
y(t) &= -R + R\\cos(t)
|
"y(t) = -R + R\\cos(t)"
|
||||||
""")
|
])
|
||||||
equations.shift(2*UP)
|
top, bottom = equations.split()
|
||||||
|
bottom.next_to(top, DOWN)
|
||||||
|
equations.center()
|
||||||
|
equations.to_edge(UP, buff = 1.3)
|
||||||
|
|
||||||
self.play(ShimmerIn(equations))
|
self.play(ShimmerIn(equations))
|
||||||
self.grow_parts()
|
self.grow_parts()
|
||||||
self.draw_cycloid(rate_func = None, run_time = 5)
|
self.draw_cycloid(rate_func = None, run_time = 5)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
class SlidingObject(CycloidScene, PathSlidingScene):
|
class SlidingObject(CycloidScene, PathSlidingScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"show_time" : False,
|
"show_time" : False,
|
||||||
|
"dither_and_add" : False
|
||||||
}
|
}
|
||||||
def construct(self):
|
|
||||||
|
args_list = [(True,), (False,)]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def args_to_string(with_words):
|
||||||
|
return "WithWords" if with_words else "WithoutWords"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def string_to_args(string):
|
||||||
|
return string == "WithWords"
|
||||||
|
|
||||||
|
def construct(self, with_words):
|
||||||
CycloidScene.construct(self)
|
CycloidScene.construct(self)
|
||||||
|
|
||||||
randy = Randolph()
|
randy = Randolph()
|
||||||
randy.scale(RANDY_SCALE_VAL)
|
randy.scale(RANDY_SCALE_VAL)
|
||||||
randy.shift(-randy.get_bottom())
|
randy.shift(-randy.get_bottom())
|
||||||
|
central_randy = randy.copy()
|
||||||
start_randy = self.adjust_mobject_to_index(
|
start_randy = self.adjust_mobject_to_index(
|
||||||
randy.copy(), 1, self.cycloid.points
|
randy.copy(), 1, self.cycloid.points
|
||||||
)
|
)
|
||||||
|
|
||||||
self.play(ShowCreation(self.cycloid))
|
if with_words:
|
||||||
|
words1 = TextMobject("Trajectory due to gravity")
|
||||||
|
arrow = TexMobject("\\leftrightarrow")
|
||||||
|
words2 = TextMobject("Trajectory due \\emph{constantly} rotating wheel")
|
||||||
|
words1.next_to(arrow, LEFT)
|
||||||
|
words2.next_to(arrow, RIGHT)
|
||||||
|
words = Mobject(words1, arrow, words2)
|
||||||
|
words.scale_to_fit_width(2*SPACE_WIDTH-1)
|
||||||
|
words.to_edge(UP, buff = 0.2)
|
||||||
|
words.to_edge(LEFT)
|
||||||
|
|
||||||
|
self.play(ShowCreation(self.cycloid.copy()))
|
||||||
self.slide(randy, self.cycloid)
|
self.slide(randy, self.cycloid)
|
||||||
|
self.add(self.slider)
|
||||||
self.dither()
|
self.dither()
|
||||||
self.grow_parts()
|
self.grow_parts()
|
||||||
self.draw_cycloid()
|
self.draw_cycloid()
|
||||||
@ -538,12 +565,26 @@ class SlidingObject(CycloidScene, PathSlidingScene):
|
|||||||
self.dither()
|
self.dither()
|
||||||
self.roll_back()
|
self.roll_back()
|
||||||
self.dither()
|
self.dither()
|
||||||
radial_line = self.circle.sub_mobjects[0]
|
if with_words:
|
||||||
self.circle.add(self.slider)
|
self.play(*map(ShimmerIn, [words1, arrow, words2]))
|
||||||
self.circle.get_center = lambda : radial_line.get_start_and_end()[0]
|
self.dither()
|
||||||
self.draw_cycloid()
|
self.remove(self.circle)
|
||||||
|
start_time = len(self.frames)*self.frame_duration
|
||||||
|
self.remove(self.slider)
|
||||||
|
self.slide(central_randy, self.cycloid)
|
||||||
|
end_time = len(self.frames)*self.frame_duration
|
||||||
|
self.play_over_time_range(
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
RollAlongVector(
|
||||||
|
self.circle,
|
||||||
|
self.cycloid.points[-1]-self.cycloid.points[0],
|
||||||
|
run_time = end_time-start_time,
|
||||||
|
rate_func = None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.add(self.circle, self.slider)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,28 +317,28 @@ class JohannThinksOfFermat(Scene):
|
|||||||
|
|
||||||
class MathematiciansOfEurope(Scene):
|
class MathematiciansOfEurope(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
europe = ImageMobject("1700_Europe", invert = False)
|
europe = ImageMobject("Europe", use_cache = False)
|
||||||
self.add(europe)
|
self.add(europe)
|
||||||
self.freeze_background()
|
self.freeze_background()
|
||||||
|
|
||||||
mathematicians = [
|
mathematicians = [
|
||||||
("Newton", [-1.6, 0.6, 0]),
|
("Newton", [-1.75, -0.75, 0]),
|
||||||
("Jacob_Bernoulli",[-1, -0.75, 0]),
|
("Jacob_Bernoulli",[-0.75, -1.75, 0]),
|
||||||
("Ehrenfried_von_Tschirnhaus",[-0.5, 0.2, 0]),
|
("Ehrenfried_von_Tschirnhaus",[0.5, -0.5, 0]),
|
||||||
("Gottfried_Wilhelm_von_Leibniz",[-0.1, -0.75, 0]),
|
("Gottfried_Wilhelm_von_Leibniz",[0.2, -1.75, 0]),
|
||||||
("Guillaume_de_L'Hopital", [-1.5, -0.5, 0]),
|
("Guillaume_de_L'Hopital", [-1.75, -1.25, 0]),
|
||||||
]
|
]
|
||||||
|
|
||||||
for name, point in mathematicians:
|
for name, point in mathematicians:
|
||||||
man = ImageMobject(name, invert = False)
|
man = ImageMobject(name, invert = False)
|
||||||
|
if name == "Newton":
|
||||||
|
name = "Isaac_Newton"
|
||||||
name_mob = TextMobject(name.replace("_", " "))
|
name_mob = TextMobject(name.replace("_", " "))
|
||||||
name_mob.to_corner(UP+LEFT, buff=0.75)
|
name_mob.to_corner(UP+LEFT, buff=0.75)
|
||||||
|
self.add(name_mob)
|
||||||
man.scale_to_fit_height(4)
|
man.scale_to_fit_height(4)
|
||||||
mobject = Point(man.get_corner(UP+LEFT))
|
mobject = Point(man.get_corner(UP+LEFT))
|
||||||
self.play(
|
self.play(Transform(mobject, man))
|
||||||
DelayByOrder(Transform(mobject, man)),
|
|
||||||
ShimmerIn(name_mob)
|
|
||||||
)
|
|
||||||
man.scale(0.2)
|
man.scale(0.2)
|
||||||
man.shift(point)
|
man.shift(point)
|
||||||
self.play(Transform(mobject, man))
|
self.play(Transform(mobject, man))
|
||||||
|
@ -878,7 +878,59 @@ class WhichPathWouldLightTake(PhotonScene, TryManyPaths):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class StateSnellsLaw(PhotonScene):
|
||||||
|
def construct(self):
|
||||||
|
point_a = 3*LEFT+3*UP
|
||||||
|
point_b = 1.5*RIGHT+3*DOWN
|
||||||
|
midpoint = ORIGIN
|
||||||
|
|
||||||
|
lines, arcs, thetas = [], [], []
|
||||||
|
counter = it.count(1)
|
||||||
|
for point in point_a, point_b:
|
||||||
|
line = Line(point, midpoint, color = RED_D)
|
||||||
|
angle = np.pi/2-np.abs(np.arctan(line.get_slope()))
|
||||||
|
arc = Arc(angle, radius = 0.5).rotate(np.pi/2)
|
||||||
|
if point is point_b:
|
||||||
|
arc.rotate(np.pi)
|
||||||
|
line.reverse_points()
|
||||||
|
theta = TexMobject("\\theta_%d"%counter.next())
|
||||||
|
theta.scale(0.5)
|
||||||
|
theta.shift(2*arc.get_center())
|
||||||
|
arc.shift(midpoint)
|
||||||
|
theta.shift(midpoint)
|
||||||
|
|
||||||
|
lines.append(line)
|
||||||
|
arcs.append(arc)
|
||||||
|
thetas.append(theta)
|
||||||
|
vert_line = Line(2*UP, 2*DOWN)
|
||||||
|
vert_line.shift(midpoint)
|
||||||
|
path = Mobject(*lines).ingest_sub_mobjects()
|
||||||
|
glass = Region(lambda x, y : y < 0, color = BLUE_E)
|
||||||
|
self.add(glass)
|
||||||
|
equation = TexMobject([
|
||||||
|
"\\dfrac{\\sin(\\theta_1)}{v_{\\text{air}}}",
|
||||||
|
"=",
|
||||||
|
"\\dfrac{\\sin(\\theta_2)}{v_{\\text{water}}}",
|
||||||
|
])
|
||||||
|
equation.to_corner(UP+RIGHT)
|
||||||
|
exp1, equals, exp2 = equation.split()
|
||||||
|
snells_law = TextMobject("Snell's Law:")
|
||||||
|
snells_law.highlight(YELLOW)
|
||||||
|
snells_law.to_edge(UP)
|
||||||
|
|
||||||
|
self.play(ShimmerIn(snells_law))
|
||||||
|
self.dither()
|
||||||
|
self.play(ShowCreation(path))
|
||||||
|
self.play(self.photon_run_along_path(path))
|
||||||
|
self.dither()
|
||||||
|
self.play(ShowCreation(vert_line))
|
||||||
|
self.play(*map(ShowCreation, arcs))
|
||||||
|
self.play(*map(GrowFromCenter, thetas))
|
||||||
|
self.dither()
|
||||||
|
self.play(ShimmerIn(exp1))
|
||||||
|
self.dither()
|
||||||
|
self.play(*map(ShimmerIn, [equals, exp2]))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,8 +17,10 @@ from topics.characters import *
|
|||||||
from topics.functions import ParametricFunction, FunctionGraph
|
from topics.functions import ParametricFunction, FunctionGraph
|
||||||
from topics.number_line import *
|
from topics.number_line import *
|
||||||
from mobject.region import Region, region_from_polygon_vertices
|
from mobject.region import Region, region_from_polygon_vertices
|
||||||
|
from topics.three_dimensions import Stars
|
||||||
from scene import Scene
|
from scene import Scene
|
||||||
|
|
||||||
|
from brachistochrone.curves import Cycloid
|
||||||
|
|
||||||
class PhysicalIntuition(Scene):
|
class PhysicalIntuition(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
@ -232,9 +234,266 @@ class StayedUpAllNight(Scene):
|
|||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
class ThetaTSigmoidGraph(Scene):
|
class ThetaTGraph(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass
|
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.dither()
|
||||||
|
self.play(
|
||||||
|
Transform(q_mark, stars),
|
||||||
|
Transform(graph, line)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(Transform(graph, squiggle))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
self.play(
|
||||||
|
Transform(cycloids, lines),
|
||||||
|
Transform(x_axis, t_axis),
|
||||||
|
Transform(x_label, t_label),
|
||||||
|
Transform(y_label, theta_label),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(ShimmerIn(words))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
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 = map(TextMobject, [
|
||||||
|
"Problem statement",
|
||||||
|
"History",
|
||||||
|
"Johann Bernoulli's cleverness"
|
||||||
|
])
|
||||||
|
curr = left_brace
|
||||||
|
right_brace.words = 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.dither()
|
||||||
|
for word in brace.words:
|
||||||
|
self.play(ShimmerIn(word))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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.highlight(RED)
|
||||||
|
line = Line(point_a, point_b)
|
||||||
|
words = TextMobject("Shortest path from $A$ to $B$")
|
||||||
|
words.to_edge(UP)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ShimmerIn(words),
|
||||||
|
*map(GrowFromCenter, dots)
|
||||||
|
)
|
||||||
|
self.play(ShowCreation(path))
|
||||||
|
self.play(Transform(
|
||||||
|
path, line,
|
||||||
|
path_func = path_along_arc(np.pi)
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
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.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
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.scale_to_fit_width(6)
|
||||||
|
levi.show()
|
||||||
|
|
||||||
|
self.add(levi)
|
||||||
|
self.play(ShimmerIn(words))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -249,7 +508,5 @@ class ThetaTSigmoidGraph(Scene):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
|||||||
|
|
||||||
def snells_law_at_every_point(self, cycloid, chopped_cycloid):
|
def snells_law_at_every_point(self, cycloid, chopped_cycloid):
|
||||||
square = Square(side_length = 0.2, color = WHITE)
|
square = Square(side_length = 0.2, color = WHITE)
|
||||||
words = TextMobject(["Snell's law ", " at every point"])
|
words = TextMobject(["Snell's law ", "everywhere"])
|
||||||
snells, rest = words.split()
|
snells, rest = words.split()
|
||||||
colon = TextMobject(":")
|
colon = TextMobject(":")
|
||||||
words.next_to(square)
|
words.next_to(square)
|
||||||
|
@ -469,6 +469,100 @@ class BalanceCompetingFactors(Scene):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Challenge(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject("""
|
||||||
|
Can you find a new solution to the
|
||||||
|
Brachistochrone problem by finding
|
||||||
|
an intuitive reason that time-minimizing
|
||||||
|
curves look like straight lines in
|
||||||
|
$t$-$\\theta$ space?
|
||||||
|
"""))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Section1(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject("Section 1: Johann Bernoulli's insight"))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class Section2(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject(
|
||||||
|
"Section 2: Mark Levi's insight, and a challenge",
|
||||||
|
size = "\\large"
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class NarratorInterjection(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words1 = TexMobject("<\\text{Narrator interjection}>")
|
||||||
|
words2 = TexMobject("<\\!/\\text{Narrator interjection}>")
|
||||||
|
self.add(words1)
|
||||||
|
self.dither()
|
||||||
|
self.clear()
|
||||||
|
self.add(words2)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class ThisCouldBeTheEnd(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject([
|
||||||
|
"This could be the end\\dots",
|
||||||
|
"but\\dots"
|
||||||
|
])
|
||||||
|
for part in words.split():
|
||||||
|
self.play(ShimmerIn(part))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class MyOwnChallenge(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject("My own challenge:"))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class WarmupChallenge(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject("\\large Warm-up challenge: Confirm this for yourself"))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class FindAnotherSolution(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject("Find another brachistochrone solution\\dots"))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class ProofOfSnellsLaw(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject("Proof of Snell's law:"))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class CondensedVersion(Scene):
|
||||||
|
def construct(self):
|
||||||
|
snells = TextMobject("Snell's")
|
||||||
|
snells.shift(-snells.get_left())
|
||||||
|
snells.to_edge(UP)
|
||||||
|
for vect in [RIGHT, RIGHT, LEFT, DOWN, DOWN, DOWN]:
|
||||||
|
snells.add(snells.copy().next_to(snells, vect))
|
||||||
|
snells.ingest_sub_mobjects()
|
||||||
|
snells.show()
|
||||||
|
condensed = TextMobject("condensed")
|
||||||
|
|
||||||
|
self.add(snells)
|
||||||
|
self.dither()
|
||||||
|
self.play(DelayByOrder(
|
||||||
|
Transform(snells, condensed, run_time = 2)
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,7 +188,6 @@ class Scene(object):
|
|||||||
self.frames[index] = self.get_frame()
|
self.frames[index] = self.get_frame()
|
||||||
for animation in animations:
|
for animation in animations:
|
||||||
animation.clean_up()
|
animation.clean_up()
|
||||||
self.repaint_mojects()
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def dither(self, duration = DEFAULT_DITHER_TIME):
|
def dither(self, duration = DEFAULT_DITHER_TIME):
|
||||||
|
@ -130,8 +130,6 @@ class Mortimer(PiCreature):
|
|||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
PiCreature.__init__(self, **kwargs)
|
PiCreature.__init__(self, **kwargs)
|
||||||
# self.highlight(DARK_BROWN)
|
|
||||||
self.give_straight_face()
|
|
||||||
self.rotate(np.pi, UP)
|
self.rotate(np.pi, UP)
|
||||||
|
|
||||||
|
|
||||||
@ -139,10 +137,6 @@ class Mathematician(PiCreature):
|
|||||||
CONFIG = {
|
CONFIG = {
|
||||||
"color" : GREY,
|
"color" : GREY,
|
||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
|
||||||
PiCreature.__init__(self, **kwargs)
|
|
||||||
self.give_straight_face()
|
|
||||||
|
|
||||||
|
|
||||||
class Bubble(Mobject):
|
class Bubble(Mobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
Reference in New Issue
Block a user