More brachistochrone work, #screwgoodcommitpractices

This commit is contained in:
Grant Sanderson 2016-03-08 23:13:41 -08:00
parent 9591a7b854
commit c2e51f5383
7 changed files with 217 additions and 45 deletions

View file

@ -360,6 +360,29 @@ class NotTheCircle(PathSlidingScene):
self.dither() self.dither()
class TransitionAwayFromSlide(PathSlidingScene):
def construct(self):
randy = Randolph()
randy.scale(RANDY_SCALE_VAL)
randy.shift(-randy.get_bottom())
self.add_cycloid_end_points()
arrow = Arrow(ORIGIN, 2*RIGHT)
arrows = Mobject(*[
arrow.copy().shift(vect)
for vect in 3*LEFT, ORIGIN, 3*RIGHT
])
arrows.shift(2*SPACE_WIDTH*RIGHT)
self.add(arrows)
self.add(self.cycloid)
self.slide(randy, self.cycloid)
everything = Mobject(*self.mobjects)
self.play(ApplyMethod(
everything.shift, 4*SPACE_WIDTH*LEFT,
run_time = 2,
rate_func = rush_into
))

View file

@ -196,6 +196,7 @@ class JohannThinksHeIsBetter(Scene):
"Johann_Bernoulli2", "Johann_Bernoulli2",
"Jacob_Bernoulli", "Jacob_Bernoulli",
"Gottfried_Wilhelm_von_Leibniz", "Gottfried_Wilhelm_von_Leibniz",
"Newton"
] ]
guys = [ guys = [
ImageMobject(name, invert = False) ImageMobject(name, invert = False)
@ -226,6 +227,11 @@ class JohannThinksHeIsBetter(Scene):
bubble.pin_to(pensive_johann) bubble.pin_to(pensive_johann)
bubble.shift(DOWN) bubble.shift(DOWN)
point = Point(johann.get_corner(UP+RIGHT)) point = Point(johann.get_corner(UP+RIGHT))
upper_point = Point(comparitive_johann.get_corner(UP+RIGHT))
lightbulb = ImageMobject("Lightbulb", invert = False)
lightbulb.scale(0.1)
lightbulb.sort_points(np.linalg.norm)
lightbulb.next_to(upper_point, RIGHT)
self.add(johann) self.add(johann)
self.dither() self.dither()
@ -244,12 +250,24 @@ class JohannThinksHeIsBetter(Scene):
) )
self.dither(2) self.dither(2)
for guy in guys[2:]: for guy in guys[2:]:
self.play(DelayByOrder(Transform(
weakling, upper_point
)))
self.play( self.play(
DelayByOrder(Transform(weakling, guy)), FadeIn(guy),
ShimmerIn(guy.name_mob) ShimmerIn(guy.name_mob)
) )
self.dither(3) self.dither(3)
self.remove(guy.name_mob) self.remove(guy.name_mob)
weakling = guy
self.play(FadeOut(weakling), FadeOut(greater_than))
self.play(ShowCreation(lightbulb))
self.dither()
self.play(FadeOut(comparitive_johann), FadeOut(lightbulb))
self.play(ApplyMethod(
Mobject(johann, bubble).scale, 10,
run_time = 3
))
class NewtonVsJohann(Scene): class NewtonVsJohann(Scene):

View file

@ -70,6 +70,8 @@ class PhotonScene(Scene):
def photon_run_along_path(self, path, color = YELLOW, **kwargs): def photon_run_along_path(self, path, color = YELLOW, **kwargs):
if "rate_func" not in kwargs:
kwargs["rate_func"] = None
photon = self.wavify(path) photon = self.wavify(path)
photon.highlight(color) photon.highlight(color)
return ShowPassingFlash(photon, **kwargs) return ShowPassingFlash(photon, **kwargs)
@ -143,6 +145,26 @@ class PhotonThroughLens(MultipathPhotonScene):
for fc, sc in zip(first_contact, second_contact) for fc, sc in zip(first_contact, second_contact)
] ]
class TransitionToOptics(PhotonThroughLens):
def construct(self):
optics = TextMobject("Optics")
optics.to_edge(UP)
self.add(optics)
self.has_started = False
PhotonThroughLens.construct(self)
def play(self, *args, **kwargs):
if not self.has_started:
self.has_started = True
everything = Mobject(*self.mobjects)
vect = 2*SPACE_WIDTH*RIGHT
everything.shift(vect)
self.play(ApplyMethod(
everything.shift, -vect,
rate_func = rush_from
))
Scene.play(self, *args, **kwargs)
class PhotonOffMirror(MultipathPhotonScene): class PhotonOffMirror(MultipathPhotonScene):
def construct(self): def construct(self):
@ -172,10 +194,10 @@ class PhotonOffMirror(MultipathPhotonScene):
for anchor_point, end_point in zip(anchor_points, end_points) for anchor_point, end_point in zip(anchor_points, end_points)
] ]
class PhotonsInGlass(MultipathPhotonScene): class PhotonsInWater(MultipathPhotonScene):
def construct(self): def construct(self):
glass = Region(lambda x, y : y < 0) water = Region(lambda x, y : y < 0, color = BLUE_E)
self.highlight_region(glass, BLUE_E) self.add(water)
self.run_along_paths() self.run_along_paths()
def get_paths(self): def get_paths(self):
@ -639,11 +661,14 @@ class StraightLinesFastestInConstantMedium(PhotonScene):
self.play(*map(ShimmerIn, [left, arrow, right])) self.play(*map(ShimmerIn, [left, arrow, right]))
self.play(ShowCreation(squaggle)) self.play(ShowCreation(squaggle))
self.play(self.photon_run_along_path(
squaggle, run_time = 2, rate_func = None
))
self.play(Transform( self.play(Transform(
squaggle, line, squaggle, line,
path_func = path_along_arc(np.pi) path_func = path_along_arc(np.pi)
)) ))
self.play(self.photon_run_along_path(line)) self.play(self.photon_run_along_path(line, rate_func = None))
self.dither() self.dither()
@ -661,8 +686,9 @@ class StraightLinesFastestInConstantMedium(PhotonScene):
mob.highlight(BLUE_D) mob.highlight(BLUE_D)
return result return result
class GlassAndAir(PhotonScene): class PhtonBendsInWater(PhotonScene, ZoomedScene):
def construct(self): def construct(self):
#TODO
pass pass

View file

@ -9,20 +9,13 @@ from mobject.image_mobject import ImageMobject
from topics.three_dimensions import Stars from topics.three_dimensions import Stars
from animation import Animation from animation import Animation
from animation.transform import \ from animation.transform import *
Transform, CounterclockwiseTransform, ApplyPointwiseFunction,\ from animation.simple_animations import *
FadeIn, FadeOut, GrowFromCenter, ApplyFunction, ApplyMethod, \
ShimmerIn
from animation.simple_animations import \
ShowCreation, Homotopy, PhaseFlow, ApplyToCenters, DelayByOrder, \
ShowPassingFlash
from animation.playground import TurnInsideOut, Vibrate from animation.playground import TurnInsideOut, Vibrate
from topics.geometry import \ from topics.geometry import *
Line, Circle, Square, Grid, Rectangle, Arrow, Dot, Point, \
Arc, FilledRectangle
from topics.characters import Randolph, Mathematician from topics.characters import Randolph, Mathematician
from topics.functions import ParametricFunction, FunctionGraph from topics.functions import ParametricFunction, FunctionGraph
from topics.number_line import NumberLine, NumberPlane from topics.number_line import *
from mobject.region import Region, region_from_polygon_vertices from mobject.region import Region, region_from_polygon_vertices
from scene import Scene from scene import Scene
@ -71,7 +64,59 @@ class PhysicalIntuition(Scene):
class TimeLine(Scene):
def construct(self):
dated_events = [
{
"date" : 1696,
"text": "Johann Bernoulli poses Brachistochrone problem",
"picture" : "Johann_Bernoulli2"
},
{
"date" : 1662,
"text" : "Fermat states his principle of least time",
"picture" : "Pierre_de_Fermat"
}
]
speical_dates = [2016] + [
obj["date"] for obj in dated_events
]
centuries = range(1600, 2100, 100)
timeline = NumberLine(
numerical_radius = 300,
number_at_center = 1800,
unit_length_to_spatial_width = SPACE_WIDTH/100,
tick_frequency = 10,
numbers_with_elongated_ticks = centuries
)
timeline.add_numbers(*centuries)
centers = [
Point(timeline.number_to_point(year))
for year in speical_dates
]
timeline.add(*centers)
timeline.shift(-centers[0].get_center())
self.add(timeline)
self.dither()
for point, event in zip(centers[1:], dated_events):
self.play(ApplyMethod(
timeline.shift, -point.get_center(),
run_time = 3
))
picture = ImageMobject(event["picture"], invert = False)
picture.scale_to_fit_width(2)
picture.to_corner(UP+RIGHT)
event_mob = TextMobject(event["text"])
event_mob.shift(2*LEFT+2*UP)
arrow = Arrow(event_mob.get_bottom(), ORIGIN)
self.play(
ShimmerIn(event_mob),
ShowCreation(arrow)
)
self.play(FadeIn(picture))
self.dither()
self.play(*map(FadeOut, [event_mob, arrow, picture]))

View file

@ -11,17 +11,10 @@ from mobject.image_mobject import \
from topics.three_dimensions import Stars from topics.three_dimensions import Stars
from animation import Animation from animation import Animation
from animation.transform import \ from animation.transform import *
Transform, CounterclockwiseTransform, ApplyPointwiseFunction,\ from animation.simple_animations import *
FadeIn, FadeOut, GrowFromCenter, ApplyFunction, ApplyMethod, \
ShimmerIn
from animation.simple_animations import \
ShowCreation, Homotopy, PhaseFlow, ApplyToCenters, DelayByOrder, \
ShowPassingFlash
from animation.playground import TurnInsideOut, Vibrate from animation.playground import TurnInsideOut, Vibrate
from topics.geometry import \ from topics.geometry import *
Line, Circle, Square, Grid, Rectangle, Arrow, Dot, Point, \
Arc, FilledRectangle
from topics.characters import Randolph, Mathematician from topics.characters import Randolph, Mathematician
from topics.functions import ParametricFunction, FunctionGraph from topics.functions import ParametricFunction, FunctionGraph
from topics.number_line import NumberPlane from topics.number_line import NumberPlane
@ -405,9 +398,75 @@ class VideoProgression(Scene):
class BalanceCompetingFactors(Scene): class BalanceCompetingFactors(Scene):
def construct(self): args_list = [
factor1 = TextMobject("Factor 1") ("Short", "Steep"),
factor2 = TextMobject("Factor 2") ("Minimal time \\\\ in water", "Short path")
]
# For subclasses to turn args in the above
# list into stings which can be appended to the name
@staticmethod
def args_to_string(*words):
return "".join([word.split(" ")[0] for word in words])
@staticmethod
def string_to_args(string):
raise Exception("string_to_args Not Implemented!")
def construct(self, *words):
factor1, factor2 = [
TextMobject("Factor %d"%x).highlight(c)
for x, c in [
(1, RED_D),
(2, BLUE_D)
]
]
real_factor1, real_factor2 = map(TextMobject, words)
for word in factor1, factor2, real_factor1, real_factor2:
word.shift(0.2*UP-word.get_bottom())
for f1 in factor1, real_factor1:
f1.highlight(RED_D)
f1.shift(2*LEFT)
for f2 in factor2, real_factor2:
f2.highlight(BLUE_D)
f2.shift(2*RIGHT)
line = Line(
factor1.get_left(),
factor2.get_right()
)
line.center()
self.balancers = Mobject(factor1, factor2, line)
self.hidden_balancers = Mobject(real_factor1, real_factor2)
triangle = Polygon(RIGHT, np.sqrt(3)*UP, LEFT)
triangle.next_to(line, DOWN, buff = 0)
self.add(triangle, self.balancers)
self.rotate(1)
self.rotate(-2)
self.dither()
self.play(Transform(
factor1, real_factor1,
path_func = path_along_arc(np.pi/4)
))
self.rotate(2)
self.dither()
self.play(Transform(
factor2, real_factor2,
path_func = path_along_arc(np.pi/4)
))
self.rotate(-2)
self.dither()
self.rotate(1)
def rotate(self, factor):
angle = np.pi/11
self.play(Rotate(
self.balancers,
factor*angle,
run_time = abs(factor)
))
self.hidden_balancers.rotate(factor*angle)

View file

@ -52,7 +52,9 @@ class Scene(object):
def get_frame(self): def get_frame(self):
return self.camera.get_image() return self.camera.get_image()
def update_frame(self, mobjects, background = None, **kwargs): def update_frame(self, mobjects = None, background = None, **kwargs):
if mobjects is None:
mobjects = self.mobjects
if background is not None: if background is not None:
self.camera.set_image(background) self.camera.set_image(background)
else: else:
@ -185,7 +187,7 @@ class Scene(object):
return self return self
def dither(self, duration = DEFAULT_DITHER_TIME): def dither(self, duration = DEFAULT_DITHER_TIME):
self.update_frame(self.mobjects) self.update_frame()
self.frames += [self.get_frame()]*int(duration / self.frame_duration) self.frames += [self.get_frame()]*int(duration / self.frame_duration)
return self return self
@ -206,6 +208,7 @@ class Scene(object):
return self return self
def show_frame(self): def show_frame(self):
self.update_frame()
Image.fromarray(self.get_frame()).show() Image.fromarray(self.get_frame()).show()
def preview(self): def preview(self):

View file

@ -8,11 +8,11 @@ class NumberLine(Mobject1D):
CONFIG = { CONFIG = {
"color" : BLUE, "color" : BLUE,
"numerical_radius" : SPACE_WIDTH, "numerical_radius" : SPACE_WIDTH,
"number_at_center" : 0,
"unit_length_to_spatial_width" : 1, "unit_length_to_spatial_width" : 1,
"tick_size" : 0.1, "tick_size" : 0.1,
"tick_frequency" : 0.5, "tick_frequency" : 0.5,
"leftmost_tick" : None, "leftmost_tick" : None,
"number_at_center" : 0,
"numbers_with_elongated_ticks" : [0], "numbers_with_elongated_ticks" : [0],
"longer_tick_multiple" : 2, "longer_tick_multiple" : 2,
} }
@ -73,10 +73,10 @@ class NumberLine(Mobject1D):
def default_numbers_to_display(self): def default_numbers_to_display(self):
return self.get_tick_numbers()[::2] return self.get_tick_numbers()[::2]
def get_vertical_number_offset(self): def get_vertical_number_offset(self, direction = DOWN):
return 4*DOWN*self.tick_size return 4*direction*self.tick_size
def get_number_mobjects(self, *numbers): def get_number_mobjects(self, *numbers, **kwargs):
#TODO, handle decimals #TODO, handle decimals
if len(numbers) == 0: if len(numbers) == 0:
numbers = self.default_numbers_to_display() numbers = self.default_numbers_to_display()
@ -87,17 +87,15 @@ class NumberLine(Mobject1D):
hori_scale = self.tick_frequency*self.unit_length_to_spatial_width/mob.get_width() hori_scale = self.tick_frequency*self.unit_length_to_spatial_width/mob.get_width()
mob.scale(min(vert_scale, hori_scale)) mob.scale(min(vert_scale, hori_scale))
mob.shift(self.number_to_point(number)) mob.shift(self.number_to_point(number))
mob.shift(self.get_vertical_number_offset()) mob.shift(self.get_vertical_number_offset(**kwargs))
result.append(mob) result.append(mob)
return result return result
def add_numbers(self, *numbers): def add_numbers(self, *numbers, **kwargs):
self.add(*self.get_number_mobjects(*numbers)) self.numbers = self.get_number_mobjects(
return self *numbers, **kwargs
)
def remove_numbers(self): self.add(*self.numbers)
self.points = self.points[:self.number_of_points_without_numbers]
self.rgbs = self.rgbs[:self.number_of_points_without_numbers]
return self return self
class UnitInterval(NumberLine): class UnitInterval(NumberLine):