mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
On to cycloid animations
This commit is contained in:
parent
efcaae4d2a
commit
04077971ee
3 changed files with 158 additions and 20 deletions
|
@ -30,7 +30,7 @@ class Cycloid(ParametricFunction):
|
||||||
"radius" : 2,
|
"radius" : 2,
|
||||||
"end_theta" : 3*np.pi/2,
|
"end_theta" : 3*np.pi/2,
|
||||||
"density" : 5*DEFAULT_POINT_DENSITY_1D,
|
"density" : 5*DEFAULT_POINT_DENSITY_1D,
|
||||||
"color" : BLUE_D
|
"color" : YELLOW
|
||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
|
|
126
brachistochrone/cycloid.py
Normal file
126
brachistochrone/cycloid.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
import numpy as np
|
||||||
|
import itertools as it
|
||||||
|
|
||||||
|
from helpers import *
|
||||||
|
|
||||||
|
from mobject.tex_mobject import TexMobject, TextMobject, Brace
|
||||||
|
from mobject import Mobject, Mobject1D
|
||||||
|
from mobject.image_mobject import \
|
||||||
|
ImageMobject, MobjectFromPixelArray
|
||||||
|
from topics.three_dimensions import Stars
|
||||||
|
|
||||||
|
from animation import Animation
|
||||||
|
from animation.transform import *
|
||||||
|
from animation.simple_animations import *
|
||||||
|
from topics.geometry import *
|
||||||
|
from topics.characters import Randolph
|
||||||
|
from topics.functions import *
|
||||||
|
from mobject.region import Region
|
||||||
|
from scene import Scene
|
||||||
|
from scene.zoomed_scene import ZoomedScene
|
||||||
|
|
||||||
|
from camera import Camera
|
||||||
|
from brachistochrone.curves import *
|
||||||
|
|
||||||
|
class RollAlongVector(Animation):
|
||||||
|
def __init__(self, mobject, vector, **kwargs):
|
||||||
|
radius = mobject.get_width()/2
|
||||||
|
radians = np.linalg.norm(vector)/radius
|
||||||
|
last_alpha = 0
|
||||||
|
digest_config(self, kwargs, locals())
|
||||||
|
Animation.__init__(self, mobject, **kwargs)
|
||||||
|
|
||||||
|
def update_mobject(self, alpha):
|
||||||
|
d_alpha = alpha - self.last_alpha
|
||||||
|
self.last_alpha = alpha
|
||||||
|
self.mobject.rotate_in_place(d_alpha*self.radians)
|
||||||
|
self.mobject.shift(d_alpha*self.vector)
|
||||||
|
|
||||||
|
|
||||||
|
class CycloidScene(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"point_a" : 6*LEFT+3*UP,
|
||||||
|
"radius" : 2,
|
||||||
|
"end_theta" : 2*np.pi
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.generate_cycloid()
|
||||||
|
self.generate_circle()
|
||||||
|
self.generate_ceiling()
|
||||||
|
|
||||||
|
def grow_parts(self):
|
||||||
|
self.play(*[
|
||||||
|
ShowCreation(mob)
|
||||||
|
for mob in self.circle, self.ceiling
|
||||||
|
])
|
||||||
|
|
||||||
|
def generate_cycloid(self):
|
||||||
|
self.cycloid = Cycloid(
|
||||||
|
point_a = self.point_a,
|
||||||
|
radius = self.radius,
|
||||||
|
end_theta = self.end_theta
|
||||||
|
)
|
||||||
|
|
||||||
|
def generate_circle(self, **kwargs):
|
||||||
|
self.circle = Circle(radius = self.radius, **kwargs)
|
||||||
|
self.circle.shift(self.point_a - self.circle.get_top())
|
||||||
|
radial_line = Line(
|
||||||
|
self.circle.get_center(), self.point_a
|
||||||
|
)
|
||||||
|
self.circle.add(radial_line)
|
||||||
|
|
||||||
|
def generate_ceiling(self):
|
||||||
|
self.ceiling = Line(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT)
|
||||||
|
self.ceiling.shift(self.cycloid.get_top()[1]*UP)
|
||||||
|
|
||||||
|
def draw_cycloid(self, run_time = 3, **kwargs):
|
||||||
|
kwargs["run_time"] = run_time
|
||||||
|
self.play(
|
||||||
|
RollAlongVector(
|
||||||
|
self.circle,
|
||||||
|
self.cycloid.points[-1]-self.cycloid.points[0],
|
||||||
|
**kwargs
|
||||||
|
),
|
||||||
|
ShowCreation(self.cycloid, **kwargs)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class IntroduceCycloid(CycloidScene):
|
||||||
|
def construct(self):
|
||||||
|
CycloidScene.construct(self)
|
||||||
|
|
||||||
|
equation = TexMobject("""
|
||||||
|
\\dfrac{\\sin(\\theta)}{\\sqrt{y}} =
|
||||||
|
\\text{constant}
|
||||||
|
""")
|
||||||
|
new_eq = equation.copy()
|
||||||
|
new_eq.to_edge(UP, buff = 1.3)
|
||||||
|
cycloid_word = TextMobject("Cycloid")
|
||||||
|
arrow = Arrow(2*UP, cycloid_word)
|
||||||
|
arrow.reverse_points()
|
||||||
|
|
||||||
|
self.play(ShimmerIn(equation))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
ApplyMethod(equation.shift, 2.2*UP),
|
||||||
|
ShowCreation(arrow)
|
||||||
|
)
|
||||||
|
self.play(ShimmerIn(cycloid_word))
|
||||||
|
self.dither()
|
||||||
|
self.grow_parts()
|
||||||
|
self.draw_cycloid()
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -329,7 +329,7 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
||||||
self.add(glass)
|
self.add(glass)
|
||||||
self.freeze_background()
|
self.freeze_background()
|
||||||
|
|
||||||
cycloid = Cycloid()
|
cycloid = Cycloid(end_theta = np.pi)
|
||||||
cycloid.highlight(YELLOW)
|
cycloid.highlight(YELLOW)
|
||||||
chopped_cycloid = cycloid.copy()
|
chopped_cycloid = cycloid.copy()
|
||||||
n = cycloid.get_num_points()
|
n = cycloid.get_num_points()
|
||||||
|
@ -337,28 +337,40 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
||||||
chopped_cycloid.reverse_points()
|
chopped_cycloid.reverse_points()
|
||||||
|
|
||||||
|
|
||||||
self.play(ShowCreation(cycloid))
|
# self.play(ShowCreation(cycloid))
|
||||||
self.snells_law_at_every_point(cycloid, chopped_cycloid)
|
# ref_mob = self.snells_law_at_every_point(cycloid, chopped_cycloid)
|
||||||
self.show_equation(chopped_cycloid)
|
ref_mob = Point()
|
||||||
|
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")
|
words = TextMobject(["Snell's law", " at every point"], use_cache = False)
|
||||||
|
words.show()
|
||||||
|
snells, rest = words.split()
|
||||||
|
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)
|
||||||
|
colon.next_to(new_snells)
|
||||||
|
|
||||||
self.play(MoveAlongPath(
|
self.play(MoveAlongPath(
|
||||||
combo, cycloid,
|
combo, cycloid,
|
||||||
run_time = 3
|
run_time = 5
|
||||||
))
|
))
|
||||||
self.play(MoveAlongPath(
|
self.play(MoveAlongPath(
|
||||||
combo, chopped_cycloid,
|
combo, chopped_cycloid,
|
||||||
run_time = 2
|
run_time = 4
|
||||||
))
|
))
|
||||||
dot = Dot(combo.get_center())
|
dot = Dot(combo.get_center())
|
||||||
self.play(Transform(combo.ingest_sub_mobjects(), dot))
|
self.play(Transform(square, dot))
|
||||||
|
self.play(
|
||||||
|
Transform(snells, new_snells),
|
||||||
|
Transform(rest, colon)
|
||||||
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
return colon
|
||||||
|
|
||||||
def get_marks(self, point1, point2):
|
def get_marks(self, point1, point2):
|
||||||
vert_line = Line(2*DOWN, 2*UP)
|
vert_line = Line(2*DOWN, 2*UP)
|
||||||
|
@ -375,7 +387,6 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
||||||
arc = Arc(angle_from_vert, start_angle = np.pi/2)
|
arc = Arc(angle_from_vert, start_angle = np.pi/2)
|
||||||
arc.scale(self.arc_radius)
|
arc.scale(self.arc_radius)
|
||||||
arc.shift(point1)
|
arc.shift(point1)
|
||||||
self.add(arc)
|
|
||||||
vect_angle = angle_from_vert/2 + np.pi/2
|
vect_angle = angle_from_vert/2 + np.pi/2
|
||||||
vect = rotate_vector(RIGHT, vect_angle)
|
vect = rotate_vector(RIGHT, vect_angle)
|
||||||
theta.center()
|
theta.center()
|
||||||
|
@ -384,24 +395,23 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
||||||
return arc, theta, vert_line, tangent_line
|
return arc, theta, vert_line, tangent_line
|
||||||
|
|
||||||
|
|
||||||
def show_equation(self, chopped_cycloid):
|
def show_equation(self, chopped_cycloid, ref_mob):
|
||||||
point1, point2 = chopped_cycloid.points[-2:]
|
point2, point1 = chopped_cycloid.points[-2:]
|
||||||
arc, theta, vert_line, tangent_line = self.get_marks(
|
arc, theta, vert_line, tangent_line = self.get_marks(
|
||||||
point1, point2
|
point1, point2
|
||||||
)
|
)
|
||||||
sin, sqrt_y = TexMobject([
|
equation = TexMobject([
|
||||||
"\\sin(\\theta)",
|
"\\sin(\\theta)",
|
||||||
"\\over \\sqrt{y}",
|
"\\over \\sqrt{y}",
|
||||||
]).split()
|
])
|
||||||
equation = Mobject(sin, sqrt_y)
|
sin, sqrt_y = equation.split()
|
||||||
equation.next_to(Point(self.top), DOWN)
|
equation.next_to(ref_mob)
|
||||||
equation.shift(LEFT)
|
|
||||||
const = TexMobject(" = \\text{constant}")
|
const = TexMobject(" = \\text{constant}")
|
||||||
const.next_to(equation)
|
const.next_to(equation)
|
||||||
ceil_point = np.array(point)
|
ceil_point = np.array(point1)
|
||||||
ceil_point[1] = self.top[1]
|
ceil_point[1] = self.top[1]
|
||||||
brace = Brace(
|
brace = Brace(
|
||||||
Mobject(Point(point), Point(ceil_point)),
|
Mobject(Point(point1), Point(ceil_point)),
|
||||||
RIGHT
|
RIGHT
|
||||||
)
|
)
|
||||||
y_mob = TexMobject("y").next_to(brace)
|
y_mob = TexMobject("y").next_to(brace)
|
||||||
|
@ -417,7 +427,9 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
||||||
GrowFromCenter(y_mob)
|
GrowFromCenter(y_mob)
|
||||||
)
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(ShimmerIn(const))
|
self.play(Transform(
|
||||||
|
Point(const.get_left()), const
|
||||||
|
))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue