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,
|
||||
"end_theta" : 3*np.pi/2,
|
||||
"density" : 5*DEFAULT_POINT_DENSITY_1D,
|
||||
"color" : BLUE_D
|
||||
"color" : YELLOW
|
||||
}
|
||||
def __init__(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.freeze_background()
|
||||
|
||||
cycloid = Cycloid()
|
||||
cycloid = Cycloid(end_theta = np.pi)
|
||||
cycloid.highlight(YELLOW)
|
||||
chopped_cycloid = cycloid.copy()
|
||||
n = cycloid.get_num_points()
|
||||
|
@ -337,28 +337,40 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
|||
chopped_cycloid.reverse_points()
|
||||
|
||||
|
||||
self.play(ShowCreation(cycloid))
|
||||
self.snells_law_at_every_point(cycloid, chopped_cycloid)
|
||||
self.show_equation(chopped_cycloid)
|
||||
# self.play(ShowCreation(cycloid))
|
||||
# ref_mob = self.snells_law_at_every_point(cycloid, chopped_cycloid)
|
||||
ref_mob = Point()
|
||||
self.show_equation(chopped_cycloid, ref_mob)
|
||||
|
||||
def snells_law_at_every_point(self, cycloid, chopped_cycloid):
|
||||
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.shift(0.3*UP)
|
||||
combo = Mobject(square, words)
|
||||
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(
|
||||
combo, cycloid,
|
||||
run_time = 3
|
||||
run_time = 5
|
||||
))
|
||||
self.play(MoveAlongPath(
|
||||
combo, chopped_cycloid,
|
||||
run_time = 2
|
||||
run_time = 4
|
||||
))
|
||||
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()
|
||||
return colon
|
||||
|
||||
def get_marks(self, point1, point2):
|
||||
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.scale(self.arc_radius)
|
||||
arc.shift(point1)
|
||||
self.add(arc)
|
||||
vect_angle = angle_from_vert/2 + np.pi/2
|
||||
vect = rotate_vector(RIGHT, vect_angle)
|
||||
theta.center()
|
||||
|
@ -384,24 +395,23 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
|||
return arc, theta, vert_line, tangent_line
|
||||
|
||||
|
||||
def show_equation(self, chopped_cycloid):
|
||||
point1, point2 = chopped_cycloid.points[-2:]
|
||||
def show_equation(self, chopped_cycloid, ref_mob):
|
||||
point2, point1 = chopped_cycloid.points[-2:]
|
||||
arc, theta, vert_line, tangent_line = self.get_marks(
|
||||
point1, point2
|
||||
)
|
||||
sin, sqrt_y = TexMobject([
|
||||
equation = TexMobject([
|
||||
"\\sin(\\theta)",
|
||||
"\\over \\sqrt{y}",
|
||||
]).split()
|
||||
equation = Mobject(sin, sqrt_y)
|
||||
equation.next_to(Point(self.top), DOWN)
|
||||
equation.shift(LEFT)
|
||||
])
|
||||
sin, sqrt_y = equation.split()
|
||||
equation.next_to(ref_mob)
|
||||
const = TexMobject(" = \\text{constant}")
|
||||
const.next_to(equation)
|
||||
ceil_point = np.array(point)
|
||||
ceil_point = np.array(point1)
|
||||
ceil_point[1] = self.top[1]
|
||||
brace = Brace(
|
||||
Mobject(Point(point), Point(ceil_point)),
|
||||
Mobject(Point(point1), Point(ceil_point)),
|
||||
RIGHT
|
||||
)
|
||||
y_mob = TexMobject("y").next_to(brace)
|
||||
|
@ -417,7 +427,9 @@ class ContinuouslyObeyingSnellsLaw(MultilayeredScene):
|
|||
GrowFromCenter(y_mob)
|
||||
)
|
||||
self.dither()
|
||||
self.play(ShimmerIn(const))
|
||||
self.play(Transform(
|
||||
Point(const.get_left()), const
|
||||
))
|
||||
self.dither()
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue