diff --git a/brachistochrone/curves.py b/brachistochrone/curves.py index d5733cdf..5e4459eb 100644 --- a/brachistochrone/curves.py +++ b/brachistochrone/curves.py @@ -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) diff --git a/brachistochrone/cycloid.py b/brachistochrone/cycloid.py new file mode 100644 index 00000000..fb1e4c5a --- /dev/null +++ b/brachistochrone/cycloid.py @@ -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() + + + + + + + + + + + + + + diff --git a/brachistochrone/multilayered.py b/brachistochrone/multilayered.py index 37a13939..4cd9c2d8 100644 --- a/brachistochrone/multilayered.py +++ b/brachistochrone/multilayered.py @@ -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()