Many filler animations for Brachistochrone

This commit is contained in:
Grant Sanderson
2016-03-27 13:57:52 -07:00
parent 04077971ee
commit 3faf30dfd0
9 changed files with 769 additions and 25 deletions

View File

@ -23,6 +23,9 @@ from camera import Camera
from brachistochrone.curves import * from brachistochrone.curves import *
class RollAlongVector(Animation): class RollAlongVector(Animation):
CONFIG = {
"rotation_vector" : OUT,
}
def __init__(self, mobject, vector, **kwargs): def __init__(self, mobject, vector, **kwargs):
radius = mobject.get_width()/2 radius = mobject.get_width()/2
radians = np.linalg.norm(vector)/radius radians = np.linalg.norm(vector)/radius
@ -33,7 +36,10 @@ class RollAlongVector(Animation):
def update_mobject(self, alpha): def update_mobject(self, alpha):
d_alpha = alpha - self.last_alpha d_alpha = alpha - self.last_alpha
self.last_alpha = alpha self.last_alpha = alpha
self.mobject.rotate_in_place(d_alpha*self.radians) self.mobject.rotate_in_place(
d_alpha*self.radians,
self.rotation_vector
)
self.mobject.shift(d_alpha*self.vector) self.mobject.shift(d_alpha*self.vector)
@ -73,7 +79,7 @@ class CycloidScene(Scene):
self.ceiling = Line(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT) self.ceiling = Line(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT)
self.ceiling.shift(self.cycloid.get_top()[1]*UP) self.ceiling.shift(self.cycloid.get_top()[1]*UP)
def draw_cycloid(self, run_time = 3, **kwargs): def draw_cycloid(self, run_time = 3, *anims, **kwargs):
kwargs["run_time"] = run_time kwargs["run_time"] = run_time
self.play( self.play(
RollAlongVector( RollAlongVector(
@ -81,39 +87,477 @@ class CycloidScene(Scene):
self.cycloid.points[-1]-self.cycloid.points[0], self.cycloid.points[-1]-self.cycloid.points[0],
**kwargs **kwargs
), ),
ShowCreation(self.cycloid, **kwargs) ShowCreation(self.cycloid, **kwargs),
*anims
) )
def roll_back(self, run_time = 3, *anims, **kwargs):
kwargs["run_time"] = run_time
self.play(
RollAlongVector(
self.circle,
self.cycloid.points[0]-self.cycloid.points[- 1],
rotation_vector = IN,
**kwargs
),
ShowCreation(
self.cycloid,
rate_func = lambda t : smooth(1-t),
**kwargs
),
*anims
)
self.generate_cycloid()
class IntroduceCycloid(CycloidScene): class IntroduceCycloid(CycloidScene):
def construct(self): def construct(self):
CycloidScene.construct(self) CycloidScene.construct(self)
equation = TexMobject(""" equation = TexMobject([
\\dfrac{\\sin(\\theta)}{\\sqrt{y}} = "\\dfrac{\\sin(\\theta)}{\\sqrt{y}}",
\\text{constant} "= \\text{constant}"
""") ])
sin_sqrt, const = equation.split()
new_eq = equation.copy() new_eq = equation.copy()
new_eq.to_edge(UP, buff = 1.3) new_eq.to_edge(UP, buff = 1.3)
cycloid_word = TextMobject("Cycloid") cycloid_word = TextMobject("Cycloid")
arrow = Arrow(2*UP, cycloid_word) arrow = Arrow(2*UP, cycloid_word)
arrow.reverse_points() arrow.reverse_points()
q_mark = TextMobject("?")
self.play(ShimmerIn(equation)) self.play(*map(ShimmerIn, equation.split()))
self.dither() self.dither()
self.play( self.play(
ApplyMethod(equation.shift, 2.2*UP), ApplyMethod(equation.shift, 2.2*UP),
ShowCreation(arrow) ShowCreation(arrow)
) )
q_mark.next_to(sin_sqrt)
self.play(ShimmerIn(cycloid_word)) self.play(ShimmerIn(cycloid_word))
self.dither() self.dither()
self.grow_parts() self.grow_parts()
self.draw_cycloid() self.draw_cycloid()
self.dither() self.dither()
extra_terms = [const, arrow, cycloid_word]
self.play(*[
Transform(mob, q_mark)
for mob in extra_terms
])
self.remove(*extra_terms)
self.roll_back()
q_marks, arrows = self.get_q_marks_and_arrows(sin_sqrt)
self.draw_cycloid(3,
ShowCreation(q_marks),
ShowCreation(arrows)
)
self.dither()
def get_q_marks_and_arrows(self, mob, n_marks = 10):
circle = Circle().replace(mob)
q_marks, arrows = result = [Mobject(), Mobject()]
for x in range(n_marks):
index = (x+0.5)*self.cycloid.get_num_points()/n_marks
q_point = self.cycloid.points[index]
vect = q_point-mob.get_center()
start_point = circle.get_boundary_point(vect)
arrow = Arrow(
start_point, q_point,
color = BLUE_E
)
q_marks.add(TextMobject("?").shift(q_point))
arrows.add(arrow)
for mob in result:
mob.ingest_sub_mobjects()
return result
class LeviSolution(CycloidScene):
CONFIG = {
"cycloid_fraction" : 0.25,
}
def construct(self):
CycloidScene.construct(self)
self.add(self.ceiling)
self.generate_points()
methods = [
self.draw_cycloid,
self.roll_into_position,
self.draw_p_and_c,
self.show_pendulum,
self.show_diameter,
self.show_theta,
self.show_similar_triangles,
self.show_sin_thetas,
self.show_y,
self.rearrange,
]
for method in methods:
method()
self.dither()
def generate_points(self):
index = int(self.cycloid_fraction*self.cycloid.get_num_points())
p_point = self.cycloid.points[index]
p_dot = Dot(p_point)
p_label = TexMobject("P")
p_label.next_to(p_dot, DOWN+LEFT)
c_point = self.point_a + self.cycloid_fraction*self.radius*2*np.pi*RIGHT
c_dot = Dot(c_point)
c_label = TexMobject("C")
c_label.next_to(c_dot, UP)
digest_locals(self)
def roll_into_position(self):
self.play(RollAlongVector(
self.circle,
(1-self.cycloid_fraction)*self.radius*2*np.pi*LEFT,
rotation_vector = IN,
run_time = 2
))
def draw_p_and_c(self):
radial_line = self.circle.sub_mobjects[0] ##Hacky
self.play(Transform(radial_line, self.p_dot))
self.remove(radial_line)
self.add(self.p_dot)
self.play(ShimmerIn(self.p_label))
self.dither()
self.play(Transform(self.ceiling.copy(), self.c_dot))
self.play(ShimmerIn(self.c_label))
def show_pendulum(self, arc_angle = np.pi, arc_color = GREEN):
words = TextMobject(": Instantaneous center of rotation")
words.next_to(self.c_label)
line = Line(self.p_point, self.c_point)
line_angle = line.get_angle()+np.pi
line_length = line.get_length()
line.add(self.p_dot.copy())
line.get_center = lambda : self.c_point
tangent_line = Line(3*LEFT, 3*RIGHT)
tangent_line.rotate(line_angle-np.pi/2)
tangent_line.shift(self.p_point)
tangent_line.highlight(arc_color)
right_angle_symbol = Mobject(
Line(UP, UP+RIGHT),
Line(UP+RIGHT, RIGHT)
)
right_angle_symbol.scale(0.3)
right_angle_symbol.rotate(tangent_line.get_angle()+np.pi)
right_angle_symbol.shift(self.p_point)
self.play(ShowCreation(line))
self.play(ShimmerIn(words))
self.dither()
pairs = [
(line_angle, arc_angle/2),
(line_angle+arc_angle/2, -arc_angle),
(line_angle-arc_angle/2, arc_angle/2),
]
arcs = []
for start, angle in pairs:
arc = Arc(
angle = angle,
radius = line_length,
start_angle = start,
color = GREEN
)
arc.shift(self.c_point)
self.play(
ShowCreation(arc),
ApplyMethod(
line.rotate_in_place,
angle,
path_func = path_along_arc(angle)
),
run_time = 2
)
arcs.append(arc)
self.dither()
self.play(Transform(arcs[1], tangent_line))
self.add(tangent_line)
self.play(ShowCreation(right_angle_symbol))
self.dither()
self.tangent_line = tangent_line
self.right_angle_symbol = right_angle_symbol
self.pc_line = line
self.remove(words, *arcs)
def show_diameter(self):
exceptions = [
self.circle,
self.tangent_line,
self.pc_line,
self.right_angle_symbol
]
everything = set(self.mobjects).difference(exceptions)
everything_copy = Mobject(*everything).copy()
light_everything = everything_copy.copy()
dark_everything = everything_copy.copy()
dark_everything.fade(0.8)
bottom_point = np.array(self.c_point)
bottom_point += 2*self.radius*DOWN
diameter = Line(bottom_point, self.c_point)
brace = Brace(diameter, RIGHT)
diameter_word = TextMobject("Diameter")
d_mob = TexMobject("D")
diameter_word.next_to(brace)
d_mob.next_to(diameter)
self.remove(*everything)
self.play(Transform(everything_copy, dark_everything))
self.dither()
self.play(ShowCreation(diameter))
self.play(GrowFromCenter(brace))
self.play(ShimmerIn(diameter_word))
self.dither()
self.play(*[
Transform(mob, d_mob)
for mob in brace, diameter_word
])
self.remove(brace, diameter_word)
self.add(d_mob)
self.play(Transform(everything_copy, light_everything))
self.remove(everything_copy)
self.add(*everything)
self.d_mob = d_mob
self.bottom_point = bottom_point
def show_theta(self, radius = 1):
arc = Arc(
angle = self.tangent_line.get_angle()-np.pi/2,
radius = radius,
start_angle = np.pi/2
)
theta = TexMobject("\\theta")
theta.shift(1.5*arc.get_center())
Mobject(arc, theta).shift(self.bottom_point)
self.play(
ShowCreation(arc),
ShimmerIn(theta)
)
self.arc = arc
self.theta = theta
def show_similar_triangles(self):
y_point = np.array(self.p_point)
y_point[1] = self.point_a[1]
new_arc = Arc(
angle = self.tangent_line.get_angle()-np.pi/2,
radius = 0.5,
start_angle = np.pi
)
new_arc.shift(self.c_point)
new_theta = self.theta.copy()
new_theta.next_to(new_arc, LEFT)
new_theta.shift(0.1*DOWN)
kwargs = {
"point_thickness" : 2*DEFAULT_POINT_THICKNESS,
}
triangle1 = Polygon(
self.p_point, self.c_point, self.bottom_point,
color = MAROON,
**kwargs
)
triangle2 = Polygon(
y_point, self.p_point, self.c_point,
color = WHITE,
**kwargs
)
y_line = Line(self.p_point, y_point)
self.play(
Transform(self.arc.copy(), new_arc),
Transform(self.theta.copy(), new_theta),
run_time = 3
)
self.dither()
self.play(FadeIn(triangle1))
self.dither()
self.play(Transform(triangle1, triangle2))
self.play(ApplyMethod(triangle1.highlight, MAROON))
self.dither()
self.remove(triangle1)
self.add(y_line)
self.y_line = y_line
def show_sin_thetas(self):
pc = Line(self.p_point, self.c_point)
mob = Mobject(self.theta, self.d_mob).copy()
mob.ingest_sub_mobjects()
triplets = [
(pc, "D\\sin(\\theta)", 0.5),
(self.y_line, "D\\sin^2(\\theta)", 0.7),
]
for line, tex, scale in triplets:
trig_mob = TexMobject(tex)
trig_mob.scale_to_fit_width(
scale*line.get_length()
)
trig_mob.shift(-1.2*trig_mob.get_top())
trig_mob.rotate(line.get_angle())
trig_mob.shift(line.get_center())
if line is self.y_line:
trig_mob.shift(0.1*UP)
self.play(Transform(mob, trig_mob))
self.add(trig_mob)
self.dither()
self.remove(mob)
self.d_sin_squared_theta = trig_mob
def show_y(self):
y_equals = TexMobject(["y", "="])
y_equals.shift(2*UP)
y_expression = TexMobject([
"D ", "\\sin", "^2", "(\\theta)"
])
y_expression.next_to(y_equals)
y_expression.shift(0.05*UP+0.1*RIGHT)
temp_expr = self.d_sin_squared_theta.copy()
temp_expr.rotate(-np.pi/2)
temp_expr.replace(y_expression)
y_mob = TexMobject("y")
y_mob.next_to(self.y_line, RIGHT)
y_mob.shift(0.2*UP)
self.play(
Transform(self.d_sin_squared_theta, temp_expr),
ShimmerIn(y_mob),
ShowCreation(y_equals)
)
self.remove(self.d_sin_squared_theta)
self.add(y_expression)
self.y_equals = y_equals
self.y_expression = y_expression
def rearrange(self):
sqrt_nudge = 0.2*LEFT
y, equals = self.y_equals.split()
d, sin, squared, theta = self.y_expression.split()
y_sqrt = TexMobject("\\sqrt{\\phantom{y}}")
d_sqrt = y_sqrt.copy()
y_sqrt.shift(y.get_center()+sqrt_nudge)
d_sqrt.shift(d.get_center()+sqrt_nudge)
self.play(
ShimmerIn(y_sqrt),
ShimmerIn(d_sqrt),
ApplyMethod(squared.shift, 4*UP),
ApplyMethod(theta.shift, 1.5* squared.get_width()*LEFT)
)
self.dither()
y_sqrt.add(y)
d_sqrt.add(d)
sin.add(theta)
sin_over = TexMobject("\\dfrac{\\phantom{\\sin(\\theta)}}{\\quad}")
sin_over.next_to(sin, DOWN, 0.15)
new_eq = equals.copy()
new_eq.next_to(sin_over, LEFT)
one_over = TexMobject("\\dfrac{1}{\\quad}")
one_over.next_to(new_eq, LEFT)
one_over.shift(
(sin_over.get_bottom()[1]-one_over.get_bottom()[1])*UP
)
self.play(
Transform(equals, new_eq),
ShimmerIn(sin_over),
ShimmerIn(one_over),
ApplyMethod(
d_sqrt.next_to, one_over, DOWN,
path_func = path_along_arc(-np.pi)
),
ApplyMethod(
y_sqrt.next_to, sin_over, DOWN,
path_func = path_along_arc(-np.pi)
),
run_time = 2
)
self.dither()
brace = Brace(d_sqrt, DOWN)
constant = TextMobject("Constant")
constant.next_to(brace, DOWN)
self.play(
GrowFromCenter(brace),
ShimmerIn(constant)
)
class EquationsForCycloid(CycloidScene):
def construct(self):
CycloidScene.construct(self)
equations = TexMobject("""
x(t) &= Rt - R\\sin(t) \\\\
y(t) &= -R + R\\cos(t)
""")
equations.shift(2*UP)
self.play(ShimmerIn(equations))
self.grow_parts()
self.draw_cycloid(rate_func = None, run_time = 5)
self.dither()
class SlidingObject(CycloidScene, PathSlidingScene):
CONFIG = {
"show_time" : False,
}
def construct(self):
CycloidScene.construct(self)
randy = Randolph()
randy.scale(RANDY_SCALE_VAL)
randy.shift(-randy.get_bottom())
start_randy = self.adjust_mobject_to_index(
randy.copy(), 1, self.cycloid.points
)
self.play(ShowCreation(self.cycloid))
self.slide(randy, self.cycloid)
self.dither()
self.grow_parts()
self.draw_cycloid()
self.dither()
self.play(Transform(self.slider, start_randy))
self.dither()
self.roll_back()
self.dither()
radial_line = self.circle.sub_mobjects[0]
self.circle.add(self.slider)
self.circle.get_center = lambda : radial_line.get_start_and_end()[0]
self.draw_cycloid()
self.dither()
class RotateWheel(CycloidScene):
def construct(self):
CycloidScene.construct(self)
self.circle.center()
self.play(Rotating(
self.circle,
axis = OUT,
run_time = 5,
rate_func = smooth
))

View File

@ -34,13 +34,13 @@ from scene import Scene
DEFAULT_GAUSS_BLUR_CONFIG = { DEFAULT_GAUSS_BLUR_CONFIG = {
"ksize" : (5, 5), "ksize" : (5, 5),
"sigmaX" : 10, "sigmaX" : 6,
"sigmaY" : 10, "sigmaY" : 6,
} }
DEFAULT_CANNY_CONFIG = { DEFAULT_CANNY_CONFIG = {
"threshold1" : 75, "threshold1" : 50,
"threshold2" : 150, "threshold2" : 100,
} }
DEFAULT_BLUR_RADIUS = 0.5 DEFAULT_BLUR_RADIUS = 0.5
@ -135,6 +135,7 @@ class TracePicture(Scene):
("Galileo_Galilei",), ("Galileo_Galilei",),
("Jacob_Bernoulli",), ("Jacob_Bernoulli",),
("Johann_Bernoulli2",), ("Johann_Bernoulli2",),
("Old_Newton",)
] ]
@staticmethod @staticmethod
@ -314,6 +315,109 @@ class JohannThinksOfFermat(Scene):
self.dither() self.dither()
class MathematiciansOfEurope(Scene):
def construct(self):
europe = ImageMobject("1700_Europe", invert = False)
self.add(europe)
self.freeze_background()
mathematicians = [
("Newton", [-1.6, 0.6, 0]),
("Jacob_Bernoulli",[-1, -0.75, 0]),
("Ehrenfried_von_Tschirnhaus",[-0.5, 0.2, 0]),
("Gottfried_Wilhelm_von_Leibniz",[-0.1, -0.75, 0]),
("Guillaume_de_L'Hopital", [-1.5, -0.5, 0]),
]
for name, point in mathematicians:
man = ImageMobject(name, invert = False)
name_mob = TextMobject(name.replace("_", " "))
name_mob.to_corner(UP+LEFT, buff=0.75)
man.scale_to_fit_height(4)
mobject = Point(man.get_corner(UP+LEFT))
self.play(
DelayByOrder(Transform(mobject, man)),
ShimmerIn(name_mob)
)
man.scale(0.2)
man.shift(point)
self.play(Transform(mobject, man))
self.remove(name_mob)
class OldNewtonIsDispleased(Scene):
def construct(self):
old_newton = ImageMobject("Old_Newton", invert = False)
old_newton.scale(0.8)
self.add(old_newton)
self.freeze_background()
words = TextMobject("Note the displeasure")
words.to_corner(UP+RIGHT)
face_point = 1.8*UP+0.5*LEFT
arrow = Arrow(words.get_bottom(), face_point)
self.play(ShimmerIn(words))
self.play(ShowCreation(arrow))
self.dither()
class NewtonConsideredEveryoneBeneathHim(Scene):
def construct(self):
mathematicians = [
ImageMobject(name, invert = False)
for name in [
"Old_Newton",
"Johann_Bernoulli2",
"Jacob_Bernoulli",
"Ehrenfried_von_Tschirnhaus",
"Gottfried_Wilhelm_von_Leibniz",
"Guillaume_de_L'Hopital",
]
]
newton = mathematicians.pop(0)
newton.scale(0.8)
new_newton = newton.copy()
new_newton.scale_to_fit_height(3)
new_newton.to_edge(UP)
for man in mathematicians:
man.scale_to_fit_width(1.7)
johann = mathematicians.pop(0)
johann.next_to(new_newton, DOWN)
last_left, last_right = johann, johann
for man, count in zip(mathematicians, it.count()):
if count%2 == 0:
man.next_to(last_left, LEFT)
last_left = man
else:
man.next_to(last_right, RIGHT)
last_right = man
self.play(
Transform(newton, new_newton),
GrowFromCenter(johann)
)
self.dither()
self.play(FadeIn(Mobject(*mathematicians)))
self.dither()

View File

@ -431,6 +431,27 @@ class PhtonBendsInWater(PhotonScene, ZoomedScene):
ShimmerIn(question_mark) ShimmerIn(question_mark)
) )
class LightIsFasterInAirThanWater(ShowMultiplePathsInWater):
def construct(self):
glass = Region(lambda x, y : y < 0, color = BLUE_E)
equation = TexMobject("v_{\\text{air}} > v_{\\text{water}}")
equation.to_edge(UP)
path = Line(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT)
path1 = path.copy().shift(2*UP)
path2 = path.copy().shift(2*DOWN)
self.add(glass)
self.play(ShimmerIn(equation))
self.dither()
photon_runs = []
photon_runs.append(self.photon_run_along_path(
path1, rate_func = lambda t : min(1, 1.2*t)
))
photon_runs.append(self.photon_run_along_path(path2))
self.play(*photon_runs, **{"run_time" : 2})
self.dither()
class GeometryOfGlassSituation(ShowMultiplePathsInWater): class GeometryOfGlassSituation(ShowMultiplePathsInWater):
def construct(self): def construct(self):
glass = Region(lambda x, y : y < 0, color = BLUE_E) glass = Region(lambda x, y : y < 0, color = BLUE_E)

View File

@ -13,7 +13,7 @@ from animation.transform import *
from animation.simple_animations import * from animation.simple_animations import *
from animation.playground import TurnInsideOut, Vibrate from animation.playground import TurnInsideOut, Vibrate
from topics.geometry import * from topics.geometry import *
from topics.characters import Randolph, Mathematician 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
@ -124,6 +124,117 @@ class TimeLine(Scene):
self.play(*map(FadeOut, [event_mob, date_mob, line, picture])) self.play(*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.point_thickness = 3
solution.highlight(GREY)
solution.scale_to_fit_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.scale_to_fit_width(0.8*rect.get_width())
phil_trans.next_to(Point(rect.get_top()), DOWN)
new_solution = solution.copy()
new_solution.scale_to_fit_width(phil_trans.get_width())
new_solution.next_to(phil_trans, DOWN, buff = 1)
not_newton = TextMobject("-Totally not by Newton")
not_newton.scale_to_fit_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.highlight()
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.dither()
self.clear()
self.add(newton)
clock.ingest_sub_mobjects()
self.play(Transform(clock, solution))
self.remove(clock)
self.add(solution)
self.dither()
self.play(
FadeIn(phil_trans),
Transform(solution, new_solution)
)
self.dither()
self.play(ShimmerIn(not_newton))
phil_trans.add(solution, not_newton)
self.dither()
self.play(*map(ShimmerIn, newton_complaint.split()))
self.dither()
self.play(
ShimmerIn(dunned_def),
ShowCreation(dunned_arrow)
)
self.dither()
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.dither()
self.play(ShimmerIn(johann_quote))
self.dither()
class ThetaTSigmoidGraph(Scene):
def construct(self):
pass
@ -131,3 +242,14 @@ class TimeLine(Scene):

View File

@ -137,6 +137,50 @@ class RaceLightInLayers(MultilayeredScene, PhotonScene):
for line, rate in zip(lines, rates) for line, rate in zip(lines, rates)
]) ])
class ShowDiscretePath(MultilayeredScene, PhotonScene):
CONFIG = {
"RectClass" : FilledRectangle
}
def construct(self):
self.add_layers()
self.cycloid = Cycloid(end_theta = np.pi)
self.generate_discrete_path()
self.play(ShowCreation(self.discrete_path))
self.dither()
self.play(self.photon_run_along_path(
self.discrete_path,
rate_func = rush_into,
run_time = 3
))
self.dither()
def generate_discrete_path(self):
points = self.cycloid.points
tops = [mob.get_top()[1] for mob in self.layers]
tops.append(tops[-1]-self.layers[0].get_height())
indices = [
np.argmin(np.abs(points[:, 1]-top))
for top in tops
]
self.bend_points = points[indices[1:-1]]
self.path_angles = []
self.discrete_path = Mobject1D(
color = WHITE,
density = 3*DEFAULT_POINT_DENSITY_1D
)
for start, end in zip(indices, indices[1:]):
start_point, end_point = points[start], points[end]
self.discrete_path.add_line(
start_point, end_point
)
self.path_angles.append(
angle_of_vector(start_point-end_point)-np.pi/2
)
self.discrete_path.add_line(
points[end], SPACE_WIDTH*RIGHT+(tops[-1]-0.5)*UP
)
class NLayers(MultilayeredScene): class NLayers(MultilayeredScene):
CONFIG = { CONFIG = {
@ -337,23 +381,22 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
chopped_cycloid.reverse_points() chopped_cycloid.reverse_points()
# self.play(ShowCreation(cycloid)) self.play(ShowCreation(cycloid))
# ref_mob = self.snells_law_at_every_point(cycloid, chopped_cycloid) ref_mob = self.snells_law_at_every_point(cycloid, chopped_cycloid)
ref_mob = Point()
self.show_equation(chopped_cycloid, ref_mob) self.show_equation(chopped_cycloid, ref_mob)
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"], use_cache = False) words = TextMobject(["Snell's law ", " at every point"])
words.show()
snells, rest = words.split() snells, rest = words.split()
colon = TextMobject(":") colon = TextMobject(":")
words.next_to(square) words.next_to(square)
words.shift(0.3*UP) words.shift(0.3*UP)
combo = Mobject(square, words) combo = Mobject(square, words)
combo.get_center = lambda : square.get_center() combo.get_center = lambda : square.get_center()
new_snells = snells.copy().center().to_edge(UP, buff = 1.3) new_snells = snells.copy().center().to_edge(UP, buff = 1.5)
colon.next_to(new_snells) colon.next_to(new_snells)
colon.shift(0.05*DOWN)
self.play(MoveAlongPath( self.play(MoveAlongPath(
combo, cycloid, combo, cycloid,
@ -416,10 +459,13 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
) )
y_mob = TexMobject("y").next_to(brace) y_mob = TexMobject("y").next_to(brace)
self.play(GrowFromCenter(sin)) self.play(
GrowFromCenter(sin),
ShowCreation(arc),
GrowFromCenter(theta)
)
self.play(ShowCreation(vert_line)) self.play(ShowCreation(vert_line))
self.play(ShowCreation(tangent_line)) self.play(ShowCreation(tangent_line))
self.play(ShowCreation(arc), GrowFromCenter(theta))
self.dither() self.dither()
self.play( self.play(
GrowFromCenter(sqrt_y), GrowFromCenter(sqrt_y),

View File

@ -133,6 +133,14 @@ class LetsBeHonest(Scene):
self.dither() self.dither()
class WhatIsTheBrachistochrone(Scene):
def construct(self):
self.play(ShimmerIn(TextMobject("""
So \\dots what is the Brachistochrone?
""")))
self.dither()
class DisectBrachistochroneWord(Scene): class DisectBrachistochroneWord(Scene):
def construct(self): def construct(self):
word = TextMobject(["Bra", "chis", "to", "chrone"]) word = TextMobject(["Bra", "chis", "to", "chrone"])

View File

@ -312,7 +312,7 @@ class Mobject(object):
return self.scale(height/self.get_height()) return self.scale(height/self.get_height())
def replace(self, mobject, stretch = False): def replace(self, mobject, stretch = False):
if mobject.get_num_points() == 0: if not mobject.get_num_points() and not mobject.sub_mobjects:
raise Warning("Attempting to replace mobject with no points") raise Warning("Attempting to replace mobject with no points")
return self return self
if stretch: if stretch:

View File

@ -20,7 +20,7 @@ class TexMobject(Mobject):
def generate_points(self): def generate_points(self):
image_files = tex_to_image_files( image_files = tex_to_image_files(
self.expression, self.expression,
self.size, self.size,
self.template_tex_file self.template_tex_file
) )
for image_file in image_files: for image_file in image_files:
@ -56,7 +56,6 @@ class Brace(TexMobject):
self.shift(left - self.points[0] + self.buff*DOWN) self.shift(left - self.points[0] + self.buff*DOWN)
for mob in mobject, self: for mob in mobject, self:
mob.rotate(angle) mob.rotate(angle)
def tex_hash(expression, size): def tex_hash(expression, size):

View File

@ -88,7 +88,7 @@ class Line(Mobject1D):
def get_angle(self): def get_angle(self):
start, end = self.get_start_and_end() start, end = self.get_start_and_end()
return angle_of_vector(start-end) return angle_of_vector(end-start)
class Arrow(Line): class Arrow(Line):
CONFIG = { CONFIG = {