mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
More brachistochrone work, #screwgoodcommitpractices
This commit is contained in:
parent
9591a7b854
commit
c2e51f5383
7 changed files with 217 additions and 45 deletions
|
@ -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
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Add table
Reference in a new issue