mirror of
https://github.com/3b1b/manim.git
synced 2025-09-19 04:41:56 +00:00
Finished Basel project
This commit is contained in:
parent
ebc418d2bd
commit
8b1643f55d
1 changed files with 445 additions and 136 deletions
|
@ -224,6 +224,45 @@ class ScaleLightSources(Transform):
|
||||||
|
|
||||||
Transform.__init__(self,light_sources_mob,ls_target,**kwargs)
|
Transform.__init__(self,light_sources_mob,ls_target,**kwargs)
|
||||||
|
|
||||||
|
class ThreeDSpotlight(VGroup):
|
||||||
|
CONFIG = {
|
||||||
|
"fill_color" : YELLOW,
|
||||||
|
}
|
||||||
|
def __init__(self, screen, ambient_light, source_point_func, **kwargs):
|
||||||
|
self.screen = screen
|
||||||
|
self.ambient_light = ambient_light
|
||||||
|
self.source_point_func = source_point_func
|
||||||
|
self.dr = ambient_light.radius/ambient_light.num_levels
|
||||||
|
VGroup.__init__(self, **kwargs)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
screen = self.screen
|
||||||
|
source_point = self.source_point_func()
|
||||||
|
dr = self.dr
|
||||||
|
corners = screen.get_anchors()
|
||||||
|
self.submobjects = [VGroup() for a in screen.get_anchors()]
|
||||||
|
|
||||||
|
distance = np.linalg.norm(
|
||||||
|
screen.get_center() - source_point
|
||||||
|
)
|
||||||
|
n_parts = np.ceil(distance/dr)
|
||||||
|
alphas = np.linspace(0, 1, n_parts+1)
|
||||||
|
for face, (c1, c2) in zip(self, adjacent_pairs(corners)):
|
||||||
|
face.submobjects = []
|
||||||
|
for a1, a2 in zip(alphas, alphas[1:]):
|
||||||
|
face.add(Polygon(
|
||||||
|
interpolate(source_point, c1, a1),
|
||||||
|
interpolate(source_point, c1, a2),
|
||||||
|
interpolate(source_point, c2, a2),
|
||||||
|
interpolate(source_point, c2, a1),
|
||||||
|
fill_color = self.fill_color,
|
||||||
|
fill_opacity = self.ambient_light.opacity_function(a1*distance),
|
||||||
|
stroke_width = 0
|
||||||
|
))
|
||||||
|
|
||||||
|
class ContinualThreeDLightConeUpdate(ContinualAnimation):
|
||||||
|
def update(self, dt):
|
||||||
|
self.mobject.update()
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
@ -236,7 +275,7 @@ class ThinkAboutPondScene(PiCreatureScene):
|
||||||
randy.to_corner(DOWN+LEFT)
|
randy.to_corner(DOWN+LEFT)
|
||||||
bubble = ThoughtBubble(
|
bubble = ThoughtBubble(
|
||||||
width = 11,
|
width = 11,
|
||||||
height = 7,
|
height = 8,
|
||||||
)
|
)
|
||||||
circles = bubble[:3]
|
circles = bubble[:3]
|
||||||
angle = -15*DEGREES
|
angle = -15*DEGREES
|
||||||
|
@ -245,6 +284,12 @@ class ThinkAboutPondScene(PiCreatureScene):
|
||||||
for circle in circles:
|
for circle in circles:
|
||||||
circle.rotate(-angle)
|
circle.rotate(-angle)
|
||||||
bubble.pin_to(randy)
|
bubble.pin_to(randy)
|
||||||
|
bubble.shift(DOWN)
|
||||||
|
bubble[:3].rotate(np.pi, axis = UP+2*RIGHT, about_edge = UP+LEFT)
|
||||||
|
bubble[:3].scale(0.7, about_edge = DOWN+RIGHT)
|
||||||
|
bubble[:3].shift(1.5*DOWN)
|
||||||
|
for oval in bubble[:3]:
|
||||||
|
oval.rotate(TAU/3)
|
||||||
|
|
||||||
self.play(
|
self.play(
|
||||||
randy.change, "thinking",
|
randy.change, "thinking",
|
||||||
|
@ -252,7 +297,7 @@ class ThinkAboutPondScene(PiCreatureScene):
|
||||||
)
|
)
|
||||||
self.wait(2)
|
self.wait(2)
|
||||||
self.play(randy.change, "happy", bubble)
|
self.play(randy.change, "happy", bubble)
|
||||||
self.wait(2)
|
self.wait(4)
|
||||||
self.play(randy.change, "hooray", bubble)
|
self.play(randy.change, "hooray", bubble)
|
||||||
self.wait(2)
|
self.wait(2)
|
||||||
|
|
||||||
|
@ -615,7 +660,7 @@ class MathematicalWebOfConnections(PiCreatureScene):
|
||||||
jerk, randy = self.pi_creatures
|
jerk, randy = self.pi_creatures
|
||||||
|
|
||||||
words = self.words = TextMobject(
|
words = self.words = TextMobject(
|
||||||
"$\\pi$ is not",
|
"I am not",
|
||||||
"fundamentally \\\\",
|
"fundamentally \\\\",
|
||||||
"about circles"
|
"about circles"
|
||||||
)
|
)
|
||||||
|
@ -657,9 +702,8 @@ class MathematicalWebOfConnections(PiCreatureScene):
|
||||||
formula_equals_x = formula.get_part_by_tex("=").get_center()[0]
|
formula_equals_x = formula.get_part_by_tex("=").get_center()[0]
|
||||||
formula.shift((basel_equals_x - formula_equals_x)*RIGHT)
|
formula.shift((basel_equals_x - formula_equals_x)*RIGHT)
|
||||||
|
|
||||||
formulas.move_to(randy)
|
formulas.to_corner(UP+RIGHT)
|
||||||
formulas.to_edge(UP)
|
formulas.shift(2*LEFT)
|
||||||
formulas.shift_onto_screen()
|
|
||||||
self.formulas = formulas
|
self.formulas = formulas
|
||||||
|
|
||||||
self.play(
|
self.play(
|
||||||
|
@ -1165,6 +1209,9 @@ class IntroduceScreen(Scene):
|
||||||
"num_rays" : 250,
|
"num_rays" : 250,
|
||||||
"min_ray_angle" : 0,
|
"min_ray_angle" : 0,
|
||||||
"max_ray_angle" : TAU,
|
"max_ray_angle" : TAU,
|
||||||
|
"source_point" : 2.5*LEFT,
|
||||||
|
"observer_point" : 3.5*RIGHT,
|
||||||
|
"screen_height" : 2,
|
||||||
}
|
}
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.setup_elements()
|
self.setup_elements()
|
||||||
|
@ -1174,24 +1221,17 @@ class IntroduceScreen(Scene):
|
||||||
|
|
||||||
def setup_elements(self):
|
def setup_elements(self):
|
||||||
SCREEN_SIZE = 3.0
|
SCREEN_SIZE = 3.0
|
||||||
source_point = self.source_point = 2.5*LEFT
|
source_point = self.source_point
|
||||||
observer_point = 3.5*RIGHT
|
observer_point = self.observer_point,
|
||||||
|
|
||||||
# Light source
|
# Light source
|
||||||
|
light_source = self.light_source = self.get_light_source()
|
||||||
light_source = self.light_source = LightSource(
|
|
||||||
opacity_function = inverse_quadratic(1,2,1),
|
|
||||||
num_levels = self.num_levels,
|
|
||||||
radius = self.radius,
|
|
||||||
max_opacity_ambient = AMBIENT_FULL,
|
|
||||||
)
|
|
||||||
|
|
||||||
light_source.move_source_to(source_point)
|
|
||||||
|
|
||||||
# Screen
|
# Screen
|
||||||
|
|
||||||
screen = self.screen = Rectangle(
|
screen = self.screen = Rectangle(
|
||||||
width = 0.05,
|
width = 0.05,
|
||||||
height = 2,
|
height = self.screen_height,
|
||||||
mark_paths_closed = True,
|
mark_paths_closed = True,
|
||||||
fill_color = WHITE,
|
fill_color = WHITE,
|
||||||
fill_opacity = 1.0,
|
fill_opacity = 1.0,
|
||||||
|
@ -1333,6 +1373,16 @@ class IntroduceScreen(Scene):
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
||||||
|
def get_light_source(self):
|
||||||
|
light_source = LightSource(
|
||||||
|
opacity_function = inverse_quadratic(1,2,1),
|
||||||
|
num_levels = self.num_levels,
|
||||||
|
radius = self.radius,
|
||||||
|
max_opacity_ambient = AMBIENT_FULL,
|
||||||
|
)
|
||||||
|
light_source.move_source_to(self.source_point)
|
||||||
|
return light_source
|
||||||
|
|
||||||
def shoot_rays(self, show_creation_kwargs = None):
|
def shoot_rays(self, show_creation_kwargs = None):
|
||||||
if show_creation_kwargs is None:
|
if show_creation_kwargs is None:
|
||||||
show_creation_kwargs = {}
|
show_creation_kwargs = {}
|
||||||
|
@ -1489,6 +1539,73 @@ class EarthScene(IntroduceScreen):
|
||||||
})
|
})
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
class ShowLightInThreeDimensions(IntroduceScreen, ThreeDScene):
|
||||||
|
CONFIG = {
|
||||||
|
"num_levels" : 200,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
light_source = self.get_light_source()
|
||||||
|
screens = VGroup(
|
||||||
|
Square(),
|
||||||
|
RegularPolygon(8),
|
||||||
|
Circle().insert_n_anchor_points(25),
|
||||||
|
)
|
||||||
|
for screen in screens:
|
||||||
|
screen.scale_to_fit_height(self.screen_height)
|
||||||
|
screens.rotate(TAU/4, UP)
|
||||||
|
screens.next_to(self.observer_point, LEFT)
|
||||||
|
screens.set_stroke(WHITE, 2)
|
||||||
|
screens.set_fill(WHITE, 0.5)
|
||||||
|
screen = screens[0]
|
||||||
|
|
||||||
|
cone = ThreeDSpotlight(
|
||||||
|
screen, light_source.ambient_light,
|
||||||
|
light_source.get_source_point
|
||||||
|
)
|
||||||
|
cone_update_anim = ContinualThreeDLightConeUpdate(cone)
|
||||||
|
|
||||||
|
self.add(light_source, screen, cone)
|
||||||
|
self.add(cone_update_anim)
|
||||||
|
self.move_camera(
|
||||||
|
phi = 60*DEGREES,
|
||||||
|
theta = -155*DEGREES,
|
||||||
|
run_time = 3,
|
||||||
|
)
|
||||||
|
self.begin_ambient_camera_rotation()
|
||||||
|
kwargs = {"run_time" : 2}
|
||||||
|
self.play(screen.stretch, 0.5, 1, **kwargs)
|
||||||
|
self.play(screen.stretch, 2, 2, **kwargs)
|
||||||
|
self.play(Rotate(
|
||||||
|
screen, TAU/4,
|
||||||
|
axis = UP+OUT,
|
||||||
|
rate_func = there_and_back,
|
||||||
|
run_time = 3,
|
||||||
|
))
|
||||||
|
self.play(Transform(screen, screens[1], **kwargs))
|
||||||
|
self.play(screen.stretch, 0.5, 2, **kwargs)
|
||||||
|
self.play(Transform(screen, screens[2], **kwargs))
|
||||||
|
self.wait(2)
|
||||||
|
self.play(
|
||||||
|
screen.stretch, 0.5, 1,
|
||||||
|
screen.stretch, 2, 2,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
screen.stretch, 3, 1,
|
||||||
|
screen.stretch, 0.7, 2,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
self.wait(2)
|
||||||
|
|
||||||
|
class LightInThreeDimensionsOverlay(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject("""
|
||||||
|
``Solid angle'' \\\\
|
||||||
|
(measured in ``steradians'')
|
||||||
|
""")
|
||||||
|
self.play(Write(words))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
class InverseSquareLaw(ThreeDScene):
|
class InverseSquareLaw(ThreeDScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"screen_height" : 1.0,
|
"screen_height" : 1.0,
|
||||||
|
@ -1628,7 +1745,6 @@ class InverseSquareLaw(ThreeDScene):
|
||||||
unit_distance = self.unit_distance
|
unit_distance = self.unit_distance
|
||||||
light_indicator = self.light_indicator
|
light_indicator = self.light_indicator
|
||||||
morty = self.morty
|
morty = self.morty
|
||||||
dr = ambient_light.radius/ambient_light.num_levels
|
|
||||||
|
|
||||||
new_screen = Square(
|
new_screen = Square(
|
||||||
side_length = self.screen_height,
|
side_length = self.screen_height,
|
||||||
|
@ -1640,31 +1756,13 @@ class InverseSquareLaw(ThreeDScene):
|
||||||
new_screen.rotate(TAU/4, UP)
|
new_screen.rotate(TAU/4, UP)
|
||||||
new_screen.move_to(old_screen, IN)
|
new_screen.move_to(old_screen, IN)
|
||||||
old_screen.fade(1)
|
old_screen.fade(1)
|
||||||
screen_group = VGroup(old_screen, new_screen)
|
|
||||||
|
|
||||||
cone = VGroup(*[VGroup() for x in range(4)])
|
cone = ThreeDSpotlight(
|
||||||
cone.set_stroke(width = 0)
|
new_screen, ambient_light,
|
||||||
cone.set_fill(YELLOW, opacity = 0.5)
|
source_point_func = lambda : source_point
|
||||||
corner_directions = [OUT+UP, OUT+DOWN, IN+DOWN, IN+UP]
|
)
|
||||||
def update_cone(cone):
|
cone_update_anim = ContinualThreeDLightConeUpdate(cone)
|
||||||
corners = map(new_screen.get_corner, corner_directions)
|
|
||||||
distance = np.linalg.norm(old_screen.get_reference_point() - self.source_point)
|
|
||||||
n_parts = np.ceil(distance/dr)
|
|
||||||
alphas = np.linspace(0, 1, n_parts+1)
|
|
||||||
for face, (c1, c2) in zip(cone, adjacent_pairs(corners)):
|
|
||||||
face.submobjects = []
|
|
||||||
for a1, a2 in zip(alphas, alphas[1:]):
|
|
||||||
face.add(Polygon(
|
|
||||||
interpolate(source_point, c1, a1),
|
|
||||||
interpolate(source_point, c1, a2),
|
|
||||||
interpolate(source_point, c2, a2),
|
|
||||||
interpolate(source_point, c2, a1),
|
|
||||||
fill_color = YELLOW,
|
|
||||||
fill_opacity = ambient_light.opacity_function(a1*distance),
|
|
||||||
stroke_width = 0
|
|
||||||
))
|
|
||||||
cone_update_anim = ContinualUpdateFromFunc(cone, update_cone)
|
|
||||||
cone_update_anim.update(0)
|
|
||||||
|
|
||||||
self.remove(self.spotlight_update, self.light_indicator_update)
|
self.remove(self.spotlight_update, self.light_indicator_update)
|
||||||
self.add(
|
self.add(
|
||||||
|
@ -1690,26 +1788,41 @@ class InverseSquareLaw(ThreeDScene):
|
||||||
run_time = 2,
|
run_time = 2,
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
self.screen = screen_group
|
|
||||||
self.shift_by_distance(1)
|
|
||||||
self.shift_by_distance(-1)
|
|
||||||
self.wait()
|
|
||||||
|
|
||||||
## Create screen copies
|
## Create screen copies
|
||||||
screen_copy = new_screen.copy()
|
def get_screen_copy_group(distance):
|
||||||
four_copies = VGroup(*[new_screen.copy() for x in range(4)])
|
n = int(distance)**2
|
||||||
nine_copies = VGroup(*[new_screen.copy() for x in range(9)])
|
copies = VGroup(*[new_screen.copy() for x in range(n)])
|
||||||
def update_four_copies(four_copies):
|
copies.rotate(-TAU/4, axis = UP)
|
||||||
for mob, corner_direction in zip(four_copies, corner_directions):
|
copies.arrange_submobjects_in_grid(buff = 0)
|
||||||
mob.move_to(new_screen, corner_direction)
|
copies.rotate(TAU/4, axis = UP)
|
||||||
four_copies_update_anim = UpdateFromFunc(four_copies, update_four_copies)
|
copies.move_to(source_point, IN)
|
||||||
edge_directions = [
|
copies.shift(distance*RIGHT*unit_distance)
|
||||||
UP, UP+OUT, OUT, DOWN+OUT, DOWN, DOWN+IN, IN, UP+IN, ORIGIN
|
return copies
|
||||||
]
|
screen_copy_groups = map(get_screen_copy_group, range(1, 8))
|
||||||
def update_nine_copies(nine_copies):
|
def get_screen_copy_group_anim(n):
|
||||||
for mob, corner_direction in zip(nine_copies, edge_directions):
|
group = screen_copy_groups[n]
|
||||||
mob.move_to(new_screen, corner_direction)
|
prev_group = screen_copy_groups[n-1]
|
||||||
nine_copies_update_anim = UpdateFromFunc(nine_copies, update_nine_copies)
|
group.save_state()
|
||||||
|
group.fade(1)
|
||||||
|
group.replace(prev_group, dim_to_match = 1)
|
||||||
|
return ApplyMethod(group.restore)
|
||||||
|
|
||||||
|
# corner_directions = [UP+OUT, DOWN+OUT, DOWN+IN, UP+IN]
|
||||||
|
# edge_directions = [
|
||||||
|
# UP, UP+OUT, OUT, DOWN+OUT, DOWN, DOWN+IN, IN, UP+IN, ORIGIN
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# four_copies = VGroup(*[new_screen.copy() for x in range(4)])
|
||||||
|
# nine_copies = VGroup(*[new_screen.copy() for x in range(9)])
|
||||||
|
# def update_four_copies(four_copies):
|
||||||
|
# for mob, corner_direction in zip(four_copies, corner_directions):
|
||||||
|
# mob.move_to(new_screen, corner_direction)
|
||||||
|
# four_copies_update_anim = UpdateFromFunc(four_copies, update_four_copies)
|
||||||
|
# def update_nine_copies(nine_copies):
|
||||||
|
# for mob, corner_direction in zip(nine_copies, edge_directions):
|
||||||
|
# mob.move_to(new_screen, corner_direction)
|
||||||
|
# nine_copies_update_anim = UpdateFromFunc(nine_copies, update_nine_copies)
|
||||||
|
|
||||||
three_arrow = DoubleArrow(
|
three_arrow = DoubleArrow(
|
||||||
source_point + 4*DOWN,
|
source_point + 4*DOWN,
|
||||||
|
@ -1721,19 +1834,17 @@ class InverseSquareLaw(ThreeDScene):
|
||||||
three.next_to(three_arrow, DOWN)
|
three.next_to(three_arrow, DOWN)
|
||||||
|
|
||||||
new_screen.fade(1)
|
new_screen.fade(1)
|
||||||
self.add(
|
# self.add(
|
||||||
ContinualAnimation(screen_copy),
|
# ContinualAnimation(screen_copy),
|
||||||
ContinualAnimation(four_copies),
|
# ContinualAnimation(four_copies),
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
self.add(ContinualAnimation(screen_copy_groups[0]))
|
||||||
|
self.add(ContinualAnimation(screen_copy_groups[1]))
|
||||||
self.play(
|
self.play(
|
||||||
screen_group.scale, 2, {"about_edge" : IN + DOWN},
|
new_screen.scale, 2, {"about_edge" : IN},
|
||||||
screen_group.shift, unit_distance*RIGHT,
|
new_screen.shift, unit_distance*RIGHT,
|
||||||
UpdateFromAlphaFunc(
|
get_screen_copy_group_anim(1),
|
||||||
four_copies,
|
|
||||||
lambda nc, a : nc.set_stroke(width = a).set_fill(opacity = 0.5*a)
|
|
||||||
),
|
|
||||||
four_copies_update_anim,
|
|
||||||
screen_copy.shift, 0.25*OUT, #WHY?
|
|
||||||
run_time = 2,
|
run_time = 2,
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
@ -1744,20 +1855,40 @@ class InverseSquareLaw(ThreeDScene):
|
||||||
run_time = 10,
|
run_time = 10,
|
||||||
)
|
)
|
||||||
self.begin_ambient_camera_rotation(rate = -0.01)
|
self.begin_ambient_camera_rotation(rate = -0.01)
|
||||||
self.add(ContinualAnimation(nine_copies))
|
self.add(ContinualAnimation(screen_copy_groups[2]))
|
||||||
self.play(
|
self.play(
|
||||||
screen_group.scale, 3./2, {"about_edge" : IN + DOWN},
|
new_screen.scale, 3./2, {"about_edge" : IN},
|
||||||
screen_group.shift, unit_distance*RIGHT,
|
new_screen.shift, unit_distance*RIGHT,
|
||||||
nine_copies_update_anim,
|
get_screen_copy_group_anim(2),
|
||||||
UpdateFromAlphaFunc(
|
|
||||||
nine_copies,
|
|
||||||
lambda nc, a : nc.set_stroke(width = a).set_fill(opacity = 0.5*a)
|
|
||||||
),
|
|
||||||
GrowFromPoint(three_arrow, three_arrow.get_left()),
|
GrowFromPoint(three_arrow, three_arrow.get_left()),
|
||||||
Write(three, rate_func = squish_rate_func(smooth, 0.5, 1)),
|
Write(three, rate_func = squish_rate_func(smooth, 0.5, 1)),
|
||||||
run_time = 2,
|
run_time = 2,
|
||||||
)
|
)
|
||||||
self.wait(10)
|
self.begin_ambient_camera_rotation(rate = -0.01)
|
||||||
|
self.play(LaggedStart(
|
||||||
|
ApplyMethod, screen_copy_groups[2],
|
||||||
|
lambda m : (m.highlight, RED),
|
||||||
|
run_time = 5,
|
||||||
|
rate_func = there_and_back,
|
||||||
|
))
|
||||||
|
self.wait(2)
|
||||||
|
self.move_camera(distance = 18)
|
||||||
|
self.play(*[
|
||||||
|
ApplyMethod(mob.fade, 1)
|
||||||
|
for mob in screen_copy_groups[:2]
|
||||||
|
])
|
||||||
|
last_group = screen_copy_groups[2]
|
||||||
|
for n in range(4, len(screen_copy_groups)+1):
|
||||||
|
group = screen_copy_groups[n-1]
|
||||||
|
self.add(ContinualAnimation(group))
|
||||||
|
self.play(
|
||||||
|
new_screen.scale, float(n)/(n-1), {"about_edge" : IN},
|
||||||
|
new_screen.shift, unit_distance*RIGHT,
|
||||||
|
get_screen_copy_group_anim(n-1),
|
||||||
|
last_group.fade, 1,
|
||||||
|
)
|
||||||
|
last_group = group
|
||||||
|
self.wait()
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
@ -2189,7 +2320,25 @@ class TwoLightSourcesScene(ManipulateLightsourceSetups):
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
#Write IPT
|
#Write IPT
|
||||||
self.play(Write(theorem))
|
a_part = theorem[:2]
|
||||||
|
b_part = theorem[2:5]
|
||||||
|
h_part = theorem[5:]
|
||||||
|
for part in a_part, b_part, h_part:
|
||||||
|
part.save_state()
|
||||||
|
part.scale(3)
|
||||||
|
part.fade(1)
|
||||||
|
a_part.move_to(lsA)
|
||||||
|
b_part.move_to(lsB)
|
||||||
|
h_part.move_to(lsC)
|
||||||
|
|
||||||
|
self.play(*map(FadeOut, [lsA, lsB, lsC, indicator]))
|
||||||
|
for ls, part in (lsA, a_part), (lsB, b_part), (lsC, h_part):
|
||||||
|
self.add(ls)
|
||||||
|
self.play(
|
||||||
|
SwitchOn(ls.ambient_light, run_time = 2),
|
||||||
|
FadeIn(ls.lighthouse),
|
||||||
|
part.restore
|
||||||
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
self.play(
|
self.play(
|
||||||
Write(theorem_name),
|
Write(theorem_name),
|
||||||
|
@ -2874,7 +3023,7 @@ class PondScene(ThreeDScene):
|
||||||
self.zoomable_mobs.add(lake0)
|
self.zoomable_mobs.add(lake0)
|
||||||
|
|
||||||
# Morty and indicator
|
# Morty and indicator
|
||||||
morty = Randolph().scale(0.3)
|
morty = Mortimer().flip().scale(0.3)
|
||||||
morty.next_to(OBSERVER_POINT,DOWN)
|
morty.next_to(OBSERVER_POINT,DOWN)
|
||||||
indicator = LightIndicator(precision = 2,
|
indicator = LightIndicator(precision = 2,
|
||||||
radius = INDICATOR_RADIUS,
|
radius = INDICATOR_RADIUS,
|
||||||
|
@ -3622,6 +3771,42 @@ class PondScene(ThreeDScene):
|
||||||
self.play(randy.change,"happy")
|
self.play(randy.change,"happy")
|
||||||
self.play(randy.change,"hooray")
|
self.play(randy.change,"hooray")
|
||||||
|
|
||||||
|
class CircumferenceText(Scene):
|
||||||
|
CONFIG = {"n" : 16}
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject("Circumference %d"%self.n)
|
||||||
|
words.scale(1.25)
|
||||||
|
words.to_corner(UP+LEFT)
|
||||||
|
self.add(words)
|
||||||
|
|
||||||
|
class CenterOfLargerCircleOverlayText(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject("Center of \\\\ larger circle")
|
||||||
|
arrow = Vector(DOWN+LEFT, color = WHITE)
|
||||||
|
arrow.shift(words.get_bottom() + SMALL_BUFF*DOWN - arrow.get_start())
|
||||||
|
group = VGroup(words, arrow)
|
||||||
|
group.scale_to_fit_height(2*SPACE_HEIGHT - 1)
|
||||||
|
group.to_edge(UP)
|
||||||
|
self.add(group)
|
||||||
|
|
||||||
|
class DiameterWordOverlay(Scene):
|
||||||
|
def construct(self):
|
||||||
|
word = TextMobject("Diameter")
|
||||||
|
word.scale_to_fit_width(SPACE_WIDTH)
|
||||||
|
word.rotate(-45*DEGREES)
|
||||||
|
self.play(Write(word))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
class YayIPTApplies(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
self.teacher_says(
|
||||||
|
"Heyo! The Inverse \\\\ Pythagorean Theorem \\\\ applies!",
|
||||||
|
bubble_kwargs = {"width" : 5},
|
||||||
|
target_mode = "surprised"
|
||||||
|
)
|
||||||
|
self.change_student_modes(*3*["hooray"])
|
||||||
|
self.wait(2)
|
||||||
|
|
||||||
class WalkThroughOneMoreStep(TeacherStudentsScene):
|
class WalkThroughOneMoreStep(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says("""
|
self.student_says("""
|
||||||
|
@ -3631,6 +3816,113 @@ class WalkThroughOneMoreStep(TeacherStudentsScene):
|
||||||
self.play(self.teacher.change, "happy")
|
self.play(self.teacher.change, "happy")
|
||||||
self.wait(4)
|
self.wait(4)
|
||||||
|
|
||||||
|
class ThinkBackToHowAmazingThisIs(ThreeDScene):
|
||||||
|
CONFIG = {
|
||||||
|
"x_radius" : 100,
|
||||||
|
"max_shown_n" : 20,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.show_sum()
|
||||||
|
self.show_giant_circle()
|
||||||
|
|
||||||
|
def show_sum(self):
|
||||||
|
number_line = NumberLine(
|
||||||
|
x_min = -self.x_radius,
|
||||||
|
x_max = self.x_radius,
|
||||||
|
numbers_to_show = range(-self.max_shown_n, self.max_shown_n),
|
||||||
|
)
|
||||||
|
number_line.add_numbers()
|
||||||
|
number_line.shift(2*DOWN)
|
||||||
|
|
||||||
|
positive_dots, negative_dots = [
|
||||||
|
VGroup(*[
|
||||||
|
Dot(number_line.number_to_point(u*x))
|
||||||
|
for x in range(1, int(self.x_radius), 2)
|
||||||
|
])
|
||||||
|
for u in 1, -1
|
||||||
|
]
|
||||||
|
dot_pairs = it.starmap(VGroup, zip(positive_dots, negative_dots))
|
||||||
|
|
||||||
|
# Decimal
|
||||||
|
decimal = DecimalNumber(0, num_decimal_points = 6)
|
||||||
|
decimal.to_edge(UP)
|
||||||
|
terms = [2./(n**2) for n in range(1, 100, 2)]
|
||||||
|
partial_sums = np.cumsum(terms)
|
||||||
|
|
||||||
|
# pi^2/4 label
|
||||||
|
brace = Brace(decimal, DOWN)
|
||||||
|
pi_term = TexMobject("\pi^2 \over 4")
|
||||||
|
pi_term.next_to(brace, DOWN)
|
||||||
|
|
||||||
|
term_mobjects = VGroup()
|
||||||
|
for n in range(1, self.max_shown_n, 2):
|
||||||
|
p_term = TexMobject("\\left(\\frac{1}{%d}\\right)^2"%n)
|
||||||
|
n_term = TexMobject("\\left(\\frac{-1}{%d}\\right)^2"%n)
|
||||||
|
group = VGroup(p_term, n_term)
|
||||||
|
group.scale(0.7)
|
||||||
|
p_term.next_to(number_line.number_to_point(n), UP, LARGE_BUFF)
|
||||||
|
n_term.next_to(number_line.number_to_point(-n), UP, LARGE_BUFF)
|
||||||
|
term_mobjects.add(group)
|
||||||
|
term_mobjects.gradient_highlight(BLUE, YELLOW)
|
||||||
|
plusses = VGroup(*[
|
||||||
|
VGroup(*[
|
||||||
|
TexMobject("+").next_to(
|
||||||
|
number_line.number_to_point(u*n), UP, buff = 1.25,
|
||||||
|
)
|
||||||
|
for u in -1, 1
|
||||||
|
])
|
||||||
|
for n in range(0, self.max_shown_n, 2)
|
||||||
|
])
|
||||||
|
|
||||||
|
zoom_out = AmbientMovement(
|
||||||
|
self.camera.rotation_mobject,
|
||||||
|
direction = OUT, rate = 0.4
|
||||||
|
)
|
||||||
|
def update_decimal(decimal):
|
||||||
|
z = self.camera.rotation_mobject.get_center()[2]
|
||||||
|
decimal.scale_to_fit_height(0.07*z)
|
||||||
|
decimal.move_to(0.7*z*UP)
|
||||||
|
scale_decimal = ContinualUpdateFromFunc(decimal, update_decimal)
|
||||||
|
|
||||||
|
|
||||||
|
self.add(number_line, *dot_pairs)
|
||||||
|
self.add(zoom_out, scale_decimal)
|
||||||
|
|
||||||
|
tuples = zip(term_mobjects, plusses, partial_sums)
|
||||||
|
run_time = 1
|
||||||
|
for term_mobs, plus_pair, partial_sum in tuples:
|
||||||
|
self.play(
|
||||||
|
FadeIn(term_mobs),
|
||||||
|
Write(plus_pair, run_time = 1),
|
||||||
|
ChangeDecimalToValue(decimal, partial_sum),
|
||||||
|
run_time = run_time
|
||||||
|
)
|
||||||
|
self.wait(run_time)
|
||||||
|
run_time *= 0.9
|
||||||
|
self.play(ChangeDecimalToValue(decimal, np.pi**2/4, run_time = 5))
|
||||||
|
zoom_out.begin_wind_down()
|
||||||
|
self.wait()
|
||||||
|
self.remove(zoom_out, scale_decimal)
|
||||||
|
self.play(*map(FadeOut, it.chain(
|
||||||
|
term_mobjects, plusses,
|
||||||
|
number_line.numbers, [decimal]
|
||||||
|
)))
|
||||||
|
|
||||||
|
self.number_line = number_line
|
||||||
|
|
||||||
|
def show_giant_circle(self):
|
||||||
|
self.number_line.main_line.insert_n_anchor_points(10000)
|
||||||
|
everything = VGroup(*self.mobjects)
|
||||||
|
circle = everything.copy()
|
||||||
|
circle.move_to(ORIGIN)
|
||||||
|
circle.apply_function(
|
||||||
|
lambda (x, y, z) : complex_to_R3(7*np.exp(complex(0, 0.0315*x)))
|
||||||
|
)
|
||||||
|
circle.rotate(-TAU/4, about_point = ORIGIN)
|
||||||
|
circle.center()
|
||||||
|
|
||||||
|
self.play(Transform(everything, circle, run_time = 6))
|
||||||
|
|
||||||
class ButWait(TeacherStudentsScene):
|
class ButWait(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
|
@ -4044,50 +4336,6 @@ class ArcHighlightOverlaySceneCircumferenceSixteen(ArcHighlightOverlaySceneCircu
|
||||||
"n" : 3,
|
"n" : 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThumbnailScene(Scene):
|
|
||||||
|
|
||||||
def construct(self):
|
|
||||||
|
|
||||||
equation = TexMobject("1+{1\over 4}+{1\over 9}+{1\over 16}+{1\over 25}+\dots")
|
|
||||||
equation.scale(1.5)
|
|
||||||
equation.move_to(1.5 * UP)
|
|
||||||
q_mark = TexMobject("=?", color = LIGHT_COLOR).scale(5)
|
|
||||||
q_mark.next_to(equation, DOWN, buff = 1.5)
|
|
||||||
#equation.move_to(2 * UP)
|
|
||||||
#q_mark = TexMobject("={\pi^2\over 6}", color = LIGHT_COLOR).scale(3)
|
|
||||||
#q_mark.next_to(equation, DOWN, buff = 1)
|
|
||||||
|
|
||||||
lake_radius = 6
|
|
||||||
lake_center = ORIGIN
|
|
||||||
op_scale = 0.4
|
|
||||||
|
|
||||||
lake = Circle(
|
|
||||||
fill_color = LAKE_COLOR,
|
|
||||||
fill_opacity = LAKE_OPACITY,
|
|
||||||
radius = lake_radius,
|
|
||||||
stroke_color = LAKE_STROKE_COLOR,
|
|
||||||
stroke_width = LAKE_STROKE_WIDTH,
|
|
||||||
)
|
|
||||||
lake.move_to(lake_center)
|
|
||||||
|
|
||||||
for i in range(16):
|
|
||||||
theta = -TAU/4 + (i + 0.5) * TAU/16
|
|
||||||
pos = lake_center + lake_radius * np.array([np.cos(theta), np.sin(theta), 0])
|
|
||||||
ls = LightSource(
|
|
||||||
radius = 15.0,
|
|
||||||
num_levels = 150,
|
|
||||||
max_opacity_ambient = 1.0,
|
|
||||||
opacity_function = inverse_quadratic(1,op_scale,1)
|
|
||||||
)
|
|
||||||
ls.move_source_to(pos)
|
|
||||||
lake.add(ls.ambient_light, ls.lighthouse)
|
|
||||||
|
|
||||||
self.add(lake)
|
|
||||||
|
|
||||||
self.add(equation, q_mark)
|
|
||||||
|
|
||||||
self.wait()
|
|
||||||
|
|
||||||
class InfiniteCircleScene(PiCreatureScene):
|
class InfiniteCircleScene(PiCreatureScene):
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -4165,6 +4413,73 @@ class InfiniteCircleScene(PiCreatureScene):
|
||||||
|
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
class Credits(Scene):
|
||||||
|
def construct(self):
|
||||||
|
credits = VGroup(*[
|
||||||
|
VGroup(*map(TextMobject, pair))
|
||||||
|
for pair in [
|
||||||
|
("Primary writer and animator:", "Ben Hambrecht"),
|
||||||
|
("Editing, advising, narrating:", "Grant Sanderson"),
|
||||||
|
("Based on a paper originally by:", "Johan Wästlund"),
|
||||||
|
]
|
||||||
|
])
|
||||||
|
for credit, color in zip(credits, [MAROON_D, BLUE_D, WHITE]):
|
||||||
|
credit[1].highlight(color)
|
||||||
|
credit.arrange_submobjects(DOWN, buff = SMALL_BUFF)
|
||||||
|
|
||||||
|
credits.arrange_submobjects(DOWN, buff = LARGE_BUFF)
|
||||||
|
|
||||||
|
credits.center()
|
||||||
|
patreon_logo = PatreonLogo()
|
||||||
|
patreon_logo.to_edge(UP)
|
||||||
|
|
||||||
|
for credit in credits:
|
||||||
|
self.play(LaggedStart(FadeIn, credit[0]))
|
||||||
|
self.play(FadeIn(credit[1]))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
credits.next_to, patreon_logo.get_bottom(), DOWN, MED_LARGE_BUFF,
|
||||||
|
DrawBorderThenFill(patreon_logo)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
class Promotion(PiCreatureScene):
|
||||||
|
CONFIG = {
|
||||||
|
"seconds_to_blink" : 5,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
url = TextMobject("https://brilliant.org/3b1b/")
|
||||||
|
url.to_corner(UP+LEFT)
|
||||||
|
|
||||||
|
rect = Rectangle(height = 9, width = 16)
|
||||||
|
rect.scale_to_fit_height(5.5)
|
||||||
|
rect.next_to(url, DOWN)
|
||||||
|
rect.to_edge(LEFT)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Write(url),
|
||||||
|
self.pi_creature.change, "raise_right_hand"
|
||||||
|
)
|
||||||
|
self.play(ShowCreation(rect))
|
||||||
|
self.wait(2)
|
||||||
|
self.change_mode("thinking")
|
||||||
|
self.wait()
|
||||||
|
self.look_at(url)
|
||||||
|
self.wait(10)
|
||||||
|
self.change_mode("happy")
|
||||||
|
self.wait(10)
|
||||||
|
self.change_mode("raise_right_hand")
|
||||||
|
self.wait(10)
|
||||||
|
|
||||||
|
self.remove(rect)
|
||||||
|
self.play(
|
||||||
|
url.next_to, self.pi_creature, UP+LEFT
|
||||||
|
)
|
||||||
|
url_rect = SurroundingRectangle(url)
|
||||||
|
self.play(ShowCreation(url_rect))
|
||||||
|
self.play(FadeOut(url_rect))
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
class BaselPatreonThanks(PatreonEndScreen):
|
class BaselPatreonThanks(PatreonEndScreen):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"specific_patrons" : [
|
"specific_patrons" : [
|
||||||
|
@ -4182,7 +4497,7 @@ class BaselPatreonThanks(PatreonEndScreen):
|
||||||
"Achille Brighton",
|
"Achille Brighton",
|
||||||
"Rish Kundalia",
|
"Rish Kundalia",
|
||||||
"Yana Chernobilsky",
|
"Yana Chernobilsky",
|
||||||
"Shìmín kuāng",
|
"Shìmín Ku$\\overline{\\text{a}}$ng",
|
||||||
"Mathew Bramson",
|
"Mathew Bramson",
|
||||||
"Jerry Ling",
|
"Jerry Ling",
|
||||||
"Mustafa Mahdi",
|
"Mustafa Mahdi",
|
||||||
|
@ -4272,8 +4587,6 @@ class BaselPatreonThanks(PatreonEndScreen):
|
||||||
self.add_foreground_mobject(next_video)
|
self.add_foreground_mobject(next_video)
|
||||||
PatreonEndScreen.construct(self)
|
PatreonEndScreen.construct(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Thumbnail(Scene):
|
class Thumbnail(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"light_source_config" : {
|
"light_source_config" : {
|
||||||
|
@ -4291,7 +4604,7 @@ class Thumbnail(Scene):
|
||||||
)
|
)
|
||||||
equation.scale(1.8)
|
equation.scale(1.8)
|
||||||
equation.move_to(2*UP)
|
equation.move_to(2*UP)
|
||||||
equation.set_stroke(BLACK, 1)
|
equation.set_stroke(RED, 1)
|
||||||
answer = TexMobject("= \\frac{\\pi^2}{6}", color = LIGHT_COLOR)
|
answer = TexMobject("= \\frac{\\pi^2}{6}", color = LIGHT_COLOR)
|
||||||
answer.scale(3)
|
answer.scale(3)
|
||||||
answer.set_stroke(RED, 1)
|
answer.set_stroke(RED, 1)
|
||||||
|
@ -4336,7 +4649,3 @@ class Thumbnail(Scene):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue