3b1b-manim/active_projects/wallis_g.py

304 lines
9 KiB
Python
Raw Normal View History

2018-04-09 16:17:14 -07:00
from big_ol_pile_of_manim_imports import *
from once_useful_constructs.light import AmbientLight
from once_useful_constructs.light import Lighthouse
from once_useful_constructs.light import SwitchOn
# from once_useful_constructs.light import LightSource
2018-04-09 23:33:17 -07:00
class IntroduceDistanceProduct(MovingCameraScene):
2018-04-09 16:17:14 -07:00
CONFIG = {
"ambient_light_config": {
"opacity_function": inverse_quadratic(1, 1.1, 1),
2018-04-09 23:33:17 -07:00
"num_levels": 100,
# "num_levels": 10,
"light_radius": 10,
# "radius": 1,
"max_opacity": 0.4,
2018-04-09 16:17:14 -07:00
"color": YELLOW,
},
2018-04-09 23:33:17 -07:00
"num_lighthouses": 6,
2018-04-09 16:17:14 -07:00
"circle_radius": 3,
"observer_color": MAROON_B,
"lighthouse_height": 0.5,
2018-04-09 23:33:17 -07:00
"camera_class": MovingCamera,
2018-04-09 16:17:14 -07:00
}
def construct(self):
self.draw_circle_with_points()
self.turn_into_lighthouses_and_observer()
self.show_sum_of_inverse_squares()
def draw_circle_with_points(self):
circle = Circle(color=BLUE)
circle.scale(self.circle_radius)
lh_dots = self.lh_dots = VGroup(*[
Dot().move_to(circle.point_from_proportion(alpha))
for alpha in np.arange(0, 1, 1.0 / self.num_lighthouses)
])
lh_dot_arrows = VGroup(*[
Arrow(*[
interpolate(circle.get_center(), dot.get_center(), a)
for a in 0.6, 0.9
], buff=0)
for dot in lh_dots
])
evenly_space_dots_label = TextMobject("Evenly-spaced \\\\ dots")
evenly_space_dots_label.scale_to_fit_width(0.5 * circle.get_width())
evenly_space_dots_label.move_to(circle)
special_dot = self.special_dot = Dot(color=self.observer_color)
special_dot.move_to(circle.point_from_proportion(0.04))
special_dot_arrow = Vector(DL)
special_dot_arrow.next_to(special_dot, UR, SMALL_BUFF)
special_dot_arrow.match_color(special_dot)
special_dot_label = TextMobject("Special dot")
special_dot_label.next_to(
special_dot_arrow.get_start(), UP, SMALL_BUFF)
special_dot_label.match_color(special_dot)
special_dot.save_state()
special_dot.next_to(special_dot_arrow, UR)
special_dot.set_fill(opacity=0)
self.play(ShowCreation(circle))
self.play(
LaggedStart(ShowCreation, lh_dots),
LaggedStart(GrowArrow, lh_dot_arrows),
Write(evenly_space_dots_label)
)
self.wait()
self.play(
special_dot.restore,
GrowArrow(special_dot_arrow),
Write(special_dot_label, run_time=1),
FadeOut(VGroup(lh_dot_arrows, evenly_space_dots_label))
)
self.wait()
self.play(FadeOut(VGroup(special_dot_arrow, special_dot_label)))
def turn_into_lighthouses_and_observer(self):
2018-04-09 23:33:17 -07:00
lighthouses = self.lighthouses = VGroup()
lights = self.lights = VGroup()
2018-04-09 16:17:14 -07:00
for dot in self.lh_dots:
point = dot.get_center()
lighthouse = Lighthouse()
lighthouse.scale_to_fit_height(self.lighthouse_height)
lighthouse.move_to(point)
lighthouses.add(lighthouse)
light = AmbientLight(
source_point=VectorizedPoint(point),
**self.ambient_light_config
)
lights.add(light)
2018-04-09 23:33:17 -07:00
observer = self.observer = PiCreature(color=self.observer_color)
2018-04-09 16:17:14 -07:00
observer.flip()
observer.move_to(self.special_dot)
observer.to_edge(RIGHT)
self.play(
LaggedStart(FadeOut, self.lh_dots),
LaggedStart(FadeIn, lighthouses),
LaggedStart(SwitchOn, lights),
)
self.wait()
self.play(FadeIn(observer))
self.play(
observer.scale_to_fit_height, 0.25,
observer.next_to, self.special_dot, RIGHT, 0.5 * SMALL_BUFF,
)
self.wait()
def show_sum_of_inverse_squares(self):
2018-04-09 23:33:17 -07:00
lines = VGroup(*[
Line(self.special_dot.get_center(), dot.get_center())
for dot in self.lh_dots
])
labels = VGroup(*[TexMobject("d_%d" % i) for i in range(len(lines))])
for label, line in zip(labels, lines):
label.scale(0.75)
vect = rotate_vector(line.get_vector(), TAU / 4)
vect *= 2 * SMALL_BUFF / np.linalg.norm(vect)
label.move_to(line.get_center() + vect)
sum_of_inverse_squares = TexMobject(*it.chain(*[
["{1", "\\over", "(", "d_%d" % i, ")", "^2}", "+"]
for i in range(len(lines))
]))
sum_of_inverse_squares.submobjects.pop(-1)
sum_of_inverse_squares.to_edge(UP)
d_terms = sum_of_inverse_squares.get_parts_by_tex("d_")
d_terms.set_color(YELLOW)
plusses = sum_of_inverse_squares.get_parts_by_tex("+")
last_term = sum_of_inverse_squares[-6:]
non_d_terms = VGroup(*filter(
lambda m: m not in d_terms and m not in last_term,
sum_of_inverse_squares
))
brace = Brace(sum_of_inverse_squares, DOWN)
brace_text = brace.get_text("Total intensity of light")
arrow = Vector(DOWN, color=WHITE).next_to(brace, DOWN)
basel_sum = TexMobject(
"{1 \\over 1^2} + ",
"{1 \\over 2^2} + ",
"{1 \\over 3^2} + ",
"{1 \\over 4^2} + ",
"\\cdots",
)
basel_sum.next_to(arrow, DOWN)
basel_cross = Cross(basel_sum)
useful_for = TextMobject("Useful for")
useful_for.next_to(arrow, RIGHT)
wallis_product = TexMobject(
"{2 \\over 1} \\cdot", "{2 \\over 3} \\cdot",
"{4 \\over 3} \\cdot", "{4 \\over 5} \\cdot",
"{6 \\over 5} \\cdot", "{6 \\over 7} \\cdot",
"\\cdots"
)
wallis_product.move_to(basel_sum)
light_rings = VGroup(*it.chain(*self.lights))
self.play(
LaggedStart(ShowCreation, lines),
LaggedStart(Write, labels),
)
circle_group = VGroup(*self.get_top_level_mobjects())
self.wait()
self.play(
ReplacementTransform(labels[-1].copy(), last_term[3]),
Write(VGroup(*it.chain(last_term[:3], last_term[4:])))
)
self.remove(last_term)
self.add(last_term)
self.wait()
self.play(
Write(non_d_terms),
ReplacementTransform(
labels[:-1].copy(),
d_terms[:-1],
),
circle_group.scale, 0.8, {"about_edge": DOWN}
)
self.wait()
self.play(LaggedStart(
ApplyMethod, light_rings,
lambda m: (m.set_fill, {"opacity": 2 * m.get_fill_opacity()}),
rate_func=there_and_back,
run_time=3,
))
self.wait()
2018-04-09 16:17:14 -07:00
2018-04-09 23:33:17 -07:00
# Mention useful just to basel problem
circle_group.save_state()
self.play(
circle_group.scale, 0.5,
circle_group.to_corner, DL,
)
self.play(
GrowFromCenter(brace),
Write(brace_text)
)
self.wait()
self.play(
FadeOut(brace_text),
GrowArrow(arrow),
FadeIn(useful_for),
FadeIn(basel_sum),
)
self.wait()
self.play(
ShowCreation(basel_cross),
FadeOut(VGroup(arrow, useful_for, brace))
)
basel_group = VGroup(basel_sum, basel_cross)
self.play(
basel_group.scale, 0.5,
basel_group.to_corner, DR,
)
self.play(Write(wallis_product))
self.wait()
# Transition to distance product
self.play(
circle_group.restore,
wallis_product.match_width, basel_sum,
wallis_product.next_to, basel_sum, UP, {"aligned_edge": RIGHT},
)
self.play(
d_terms.shift, d_terms.get_height() * UP / 2,
*[
FadeOut(mob)
for mob in sum_of_inverse_squares
if mob not in d_terms and mob not in plusses
]
)
self.wait()
self.play(
FadeOut(plusses),
d_terms.arrange_submobjects, RIGHT, 0.5 * SMALL_BUFF,
d_terms.move_to, sum_of_inverse_squares, DOWN,
)
self.wait()
# Label distance product
brace = Brace(d_terms, UP, buff=SMALL_BUFF)
distance_product_label = brace.get_text("``Distance product''")
self.play(
GrowFromCenter(brace),
Write(distance_product_label)
)
line_copies = lines.copy().set_color(RED)
self.play(LaggedStart(ShowCreationThenDestruction, line_copies))
self.wait()
self.play(LaggedStart(
ApplyFunction, light_rings,
lambda mob: (
lambda m: m.shift(MED_SMALL_BUFF * UP).set_fill(opacity=2 * m.get_fill_opacity()),
mob
),
rate_func=wiggle,
run_time=6,
))
self.wait()
2018-04-09 16:17:14 -07:00