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-10 15:58:21 -07:00
|
|
|
PRODUCT_COLOR = BLUE
|
|
|
|
CHEAP_AMBIENT_LIGHT_CONFIG = {
|
|
|
|
"num_levels": 5,
|
|
|
|
"radius": 1,
|
|
|
|
}
|
2018-04-09 16:17:14 -07:00
|
|
|
|
2018-04-10 15:58:21 -07:00
|
|
|
|
|
|
|
class DistanceProductScene(MovingCameraScene):
|
2018-04-09 16:17:14 -07:00
|
|
|
CONFIG = {
|
|
|
|
"ambient_light_config": {
|
2018-04-10 15:58:21 -07:00
|
|
|
"opacity_function": inverse_power_law(1, 1.5, 1, 4),
|
2018-04-09 23:33:17 -07:00
|
|
|
"num_levels": 100,
|
2018-04-10 15:58:21 -07:00
|
|
|
"light_radius": 5,
|
|
|
|
"max_opacity": 0.8,
|
|
|
|
"color": PRODUCT_COLOR,
|
|
|
|
},
|
|
|
|
"circle_color": BLUE,
|
|
|
|
"circle_radius": 3,
|
|
|
|
"num_lighthouses": 6,
|
|
|
|
"lighthouse_height": 0.5,
|
|
|
|
"ignored_lighthouse_indices": [],
|
|
|
|
"observer_config": {
|
|
|
|
"color": MAROON_B,
|
|
|
|
"mode": "pondering",
|
|
|
|
"height": 0.25,
|
|
|
|
"flip_at_start": True,
|
|
|
|
},
|
|
|
|
"observer_fraction": 1.0 / 3,
|
|
|
|
"d_label_height": 0.35,
|
|
|
|
"numeric_distance_label_height": 0.25,
|
|
|
|
"default_product_column_top": FRAME_WIDTH * RIGHT / 4 + 1.5 * UP,
|
|
|
|
}
|
|
|
|
|
|
|
|
def setup(self):
|
|
|
|
super(DistanceProductScene, self).setup()
|
|
|
|
self.circle = Circle(
|
|
|
|
color=self.circle_color,
|
|
|
|
radius=self.circle_radius,
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_circle_point_at_proportion(self, alpha):
|
|
|
|
radius = self.get_radius()
|
|
|
|
center = self.circle.get_center()
|
|
|
|
angle = alpha * TAU
|
|
|
|
unit_circle_point = np.cos(angle) * RIGHT + np.sin(angle) * UP
|
|
|
|
return radius * unit_circle_point + center
|
|
|
|
|
|
|
|
def get_lh_points(self):
|
|
|
|
return np.array([
|
|
|
|
self.get_circle_point_at_proportion(fdiv(i, self.num_lighthouses))
|
|
|
|
for i in range(self.num_lighthouses)
|
|
|
|
if i not in self.ignored_lighthouse_indices
|
|
|
|
])
|
|
|
|
|
|
|
|
def get_observer_point(self, fraction=None):
|
|
|
|
if fraction is None:
|
|
|
|
fraction = self.observer_fraction
|
|
|
|
return self.get_circle_point_at_proportion(fraction / self.num_lighthouses)
|
|
|
|
|
|
|
|
def get_observer(self):
|
|
|
|
observer = self.observer = PiCreature(**self.observer_config)
|
|
|
|
observer.next_to(self.get_observer_point(), RIGHT, buff=SMALL_BUFF)
|
|
|
|
return observer
|
|
|
|
|
|
|
|
def get_observer_dot(self):
|
|
|
|
self.observer_dot = Dot(
|
|
|
|
self.get_observer_point(),
|
|
|
|
color=self.observer_config["color"]
|
|
|
|
)
|
|
|
|
return self.observer_dot
|
|
|
|
|
|
|
|
def get_lighthouses(self):
|
|
|
|
self.lighthouses = VGroup()
|
|
|
|
for point in self.get_lh_points():
|
|
|
|
lighthouse = Lighthouse()
|
|
|
|
lighthouse.scale_to_fit_height(self.lighthouse_height)
|
|
|
|
lighthouse.move_to(point)
|
|
|
|
self.lighthouses.add(lighthouse)
|
|
|
|
return self.lighthouses
|
|
|
|
|
|
|
|
def get_lights(self):
|
|
|
|
self.lights = VGroup()
|
|
|
|
for point in self.get_lh_points():
|
|
|
|
light = AmbientLight(
|
|
|
|
source_point=VectorizedPoint(point),
|
|
|
|
**self.ambient_light_config
|
|
|
|
)
|
|
|
|
self.lights.add(light)
|
|
|
|
return self.lights
|
|
|
|
|
|
|
|
def get_distance_lines(self):
|
|
|
|
self.distance_lines = VGroup(*[
|
|
|
|
Line(self.get_observer_point(), point)
|
|
|
|
for point in self.get_lh_points()
|
|
|
|
])
|
|
|
|
return self.distance_lines
|
|
|
|
|
|
|
|
def get_symbolic_distance_labels(self):
|
|
|
|
if not hasattr(self, "distance_lines"):
|
|
|
|
self.get_distance_lines()
|
|
|
|
self.d_labels = VGroup()
|
|
|
|
for i, line in enumerate(self.distance_lines):
|
|
|
|
d_label = TexMobject("d_%d" % i)
|
|
|
|
d_label.scale_to_fit_height(self.d_label_height)
|
|
|
|
vect = rotate_vector(line.get_vector(), 90 * DEGREES)
|
|
|
|
vect *= 2.5 * SMALL_BUFF / np.linalg.norm(vect)
|
|
|
|
d_label.move_to(line.get_center() + vect)
|
|
|
|
self.d_labels.add(d_label)
|
|
|
|
return self.d_labels
|
|
|
|
|
|
|
|
def get_numeric_distance_labels(self, num_decimal_points=3, show_ellipsis=True):
|
|
|
|
radius = self.circle.get_width() / 2
|
|
|
|
if not hasattr(self, "distance_lines"):
|
|
|
|
self.get_distance_lines()
|
|
|
|
labels = self.numeric_distance_labels = VGroup()
|
|
|
|
for line in self.distance_lines:
|
|
|
|
label = DecimalNumber(
|
|
|
|
line.get_length() / radius,
|
|
|
|
num_decimal_points=num_decimal_points,
|
|
|
|
show_ellipsis=show_ellipsis,
|
|
|
|
)
|
|
|
|
label.scale_to_fit_height(self.numeric_distance_label_height)
|
|
|
|
max_width = 0.5 * line.get_length()
|
|
|
|
if label.get_width() > max_width:
|
|
|
|
label.scale_to_fit_width(max_width)
|
|
|
|
angle = (line.get_angle() % TAU) - TAU / 2
|
|
|
|
if np.abs(angle) > TAU / 4:
|
|
|
|
angle += np.sign(angle) * np.pi
|
|
|
|
label.angle = angle
|
|
|
|
label.next_to(line.get_center(), UP, SMALL_BUFF)
|
|
|
|
label.rotate(angle, about_point=line.get_center())
|
|
|
|
labels.add(label)
|
|
|
|
return labels
|
|
|
|
|
|
|
|
def get_circle_group(self):
|
|
|
|
group = VGroup(self.circle)
|
|
|
|
if not hasattr(self, "observer_dot"):
|
|
|
|
self.get_observer_dot()
|
|
|
|
if not hasattr(self, "observer"):
|
|
|
|
self.get_observer()
|
|
|
|
if not hasattr(self, "lighthouses"):
|
|
|
|
self.get_lighthouses()
|
|
|
|
if not hasattr(self, "lights"):
|
|
|
|
self.get_lights()
|
|
|
|
group.add(
|
|
|
|
self.observer_dot,
|
|
|
|
self.observer,
|
|
|
|
self.lighthouses,
|
|
|
|
self.lights,
|
|
|
|
)
|
|
|
|
return group
|
|
|
|
|
|
|
|
def setup_lighthouses_and_observer(self):
|
|
|
|
self.add(*self.get_circle_group())
|
|
|
|
|
|
|
|
# Numerical results
|
|
|
|
|
|
|
|
def get_radius(self):
|
|
|
|
return self.circle.get_width() / 2.0
|
|
|
|
|
|
|
|
def get_distance_product(self, fraction=None):
|
|
|
|
radius = self.get_radius()
|
|
|
|
observer_point = self.get_observer_point(fraction)
|
|
|
|
distances = [
|
|
|
|
np.linalg.norm(point - observer_point) / radius
|
|
|
|
for point in self.get_lh_points()
|
|
|
|
]
|
|
|
|
return reduce(op.mul, distances, 1.0)
|
|
|
|
|
|
|
|
# Animating methods
|
|
|
|
|
|
|
|
def add_numeric_distance_labels(self, show_line_creation=True):
|
|
|
|
anims = []
|
|
|
|
if not hasattr(self, "distance_lines"):
|
|
|
|
self.get_distance_lines()
|
|
|
|
if not hasattr(self, "numeric_distance_labels"):
|
|
|
|
self.get_numeric_distance_labels()
|
|
|
|
if show_line_creation:
|
|
|
|
anims.append(LaggedStart(ShowCreation, self.distance_lines))
|
|
|
|
anims.append(LaggedStart(FadeIn, self.numeric_distance_labels))
|
|
|
|
|
|
|
|
self.play(*anims)
|
|
|
|
|
|
|
|
def show_distance_product_in_column(self, column_top=None):
|
|
|
|
if not hasattr(self, "numeric_distance_labels"):
|
|
|
|
self.get_numeric_distance_labels()
|
|
|
|
if column_top is None:
|
|
|
|
column_top = self.default_product_column_top
|
|
|
|
labels = self.numeric_distance_labels
|
|
|
|
stacked_labels = labels.copy()
|
|
|
|
for label in stacked_labels:
|
|
|
|
label.rotate(-label.angle)
|
|
|
|
label.scale_to_fit_height(self.numeric_distance_label_height)
|
|
|
|
stacked_labels.arrange_submobjects(DOWN)
|
|
|
|
stacked_labels.move_to(column_top, UP)
|
|
|
|
|
|
|
|
h_line = Line(LEFT, RIGHT)
|
|
|
|
h_line.scale_to_fit_width(1.5 * stacked_labels.get_width())
|
|
|
|
h_line.next_to(stacked_labels, DOWN, aligned_edge=RIGHT)
|
|
|
|
times = TexMobject("\\times")
|
|
|
|
times.next_to(h_line, UP, SMALL_BUFF, aligned_edge=LEFT)
|
|
|
|
|
|
|
|
product_decimal = DecimalNumber(
|
|
|
|
self.get_distance_product(),
|
|
|
|
num_decimal_points=3,
|
|
|
|
show_ellipsis=True
|
|
|
|
)
|
|
|
|
product_decimal.scale_to_fit_height(self.numeric_distance_label_height)
|
|
|
|
product_decimal.next_to(h_line, DOWN)
|
|
|
|
product_decimal.align_to(stacked_labels, RIGHT)
|
|
|
|
product_decimal.set_color(BLUE)
|
|
|
|
|
|
|
|
self.play(ReplacementTransform(labels.copy(), stacked_labels))
|
|
|
|
self.play(
|
|
|
|
ShowCreation(h_line),
|
|
|
|
Write(times)
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ReplacementTransform(
|
|
|
|
stacked_labels.copy(),
|
|
|
|
VGroup(product_decimal)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class IntroduceDistanceProduct(DistanceProductScene):
|
|
|
|
CONFIG = {
|
|
|
|
"ambient_light_config": {
|
2018-04-09 23:33:17 -07:00
|
|
|
# "num_levels": 10,
|
|
|
|
# "radius": 1,
|
2018-04-09 16:17:14 -07:00
|
|
|
"color": YELLOW,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
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):
|
2018-04-10 15:58:21 -07:00
|
|
|
circle = self.circle
|
2018-04-09 16:17:14 -07:00
|
|
|
|
|
|
|
lh_dots = self.lh_dots = VGroup(*[
|
2018-04-10 15:58:21 -07:00
|
|
|
Dot(point) for point in self.get_lh_points()
|
2018-04-09 16:17:14 -07:00
|
|
|
])
|
|
|
|
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)
|
|
|
|
|
2018-04-10 15:58:21 -07:00
|
|
|
special_dot = self.special_dot = self.get_observer_dot()
|
2018-04-09 16:17:14 -07:00
|
|
|
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-10 15:58:21 -07:00
|
|
|
lighthouses = self.get_lighthouses()
|
|
|
|
lights = self.get_lights()
|
2018-04-09 16:17:14 -07:00
|
|
|
|
2018-04-10 15:58:21 -07:00
|
|
|
observer = self.get_observer()
|
|
|
|
observer.save_state()
|
|
|
|
observer.scale_to_fit_height(2)
|
|
|
|
observer.change_mode("happy")
|
2018-04-09 16:17:14 -07:00
|
|
|
observer.to_edge(RIGHT)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
LaggedStart(FadeOut, self.lh_dots),
|
|
|
|
LaggedStart(FadeIn, lighthouses),
|
|
|
|
LaggedStart(SwitchOn, lights),
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(FadeIn(observer))
|
2018-04-10 15:58:21 -07:00
|
|
|
self.play(observer.restore)
|
2018-04-09 16:17:14 -07:00
|
|
|
self.wait()
|
|
|
|
|
|
|
|
def show_sum_of_inverse_squares(self):
|
2018-04-10 15:58:21 -07:00
|
|
|
lines = self.get_distance_lines()
|
|
|
|
labels = self.get_symbolic_distance_labels()
|
2018-04-09 23:33:17 -07:00
|
|
|
|
|
|
|
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],
|
|
|
|
),
|
2018-04-10 15:58:21 -07:00
|
|
|
circle_group.scale, 0.8, {"about_point": FRAME_Y_RADIUS * DOWN}
|
2018-04-09 23:33:17 -07:00
|
|
|
)
|
|
|
|
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()
|
2018-04-10 15:58:21 -07:00
|
|
|
v_point = VectorizedPoint(FRAME_X_RADIUS * LEFT + FRAME_Y_RADIUS * DOWN)
|
2018-04-09 23:33:17 -07:00
|
|
|
self.play(
|
2018-04-10 15:58:21 -07:00
|
|
|
circle_group.next_to, v_point, UR, {"submobject_to_align": self.circle},
|
|
|
|
circle_group.scale, 0.5, {"about_point": v_point.get_center()},
|
2018-04-09 23:33:17 -07:00
|
|
|
)
|
|
|
|
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(
|
2018-04-10 15:58:21 -07:00
|
|
|
d_terms.shift, 0.75 * d_terms.get_height() * UP,
|
|
|
|
d_terms.set_color, PRODUCT_COLOR,
|
|
|
|
light_rings.set_fill, PRODUCT_COLOR,
|
2018-04-09 23:33:17 -07:00
|
|
|
*[
|
|
|
|
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),
|
2018-04-10 15:58:21 -07:00
|
|
|
d_terms.arrange_submobjects, RIGHT, 0.25 * SMALL_BUFF,
|
2018-04-09 23:33:17 -07:00
|
|
|
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
|
|
|
|
|
|
|
|
2018-04-10 15:58:21 -07:00
|
|
|
class Lemma1(DistanceProductScene):
|
|
|
|
CONFIG = {
|
|
|
|
"circle_radius": 2.5,
|
|
|
|
"observer_fraction": 0.5,
|
|
|
|
# "ambient_light_config": {
|
|
|
|
# "num_levels": 5,
|
|
|
|
# "radius": 1,
|
|
|
|
# },
|
|
|
|
"lighthouse_height": 0.25,
|
|
|
|
"lemma_text": "distance product = 2",
|
|
|
|
}
|
|
|
|
|
|
|
|
def construct(self):
|
|
|
|
self.add_title()
|
|
|
|
self.add_circle_group()
|
|
|
|
self.state_lemma_premise()
|
|
|
|
self.show_product()
|
|
|
|
|
|
|
|
def add_title(self):
|
|
|
|
title = self.title = TextMobject("Two lemmas:")
|
|
|
|
title.set_color(YELLOW)
|
|
|
|
title.to_edge(UP, buff=MED_SMALL_BUFF)
|
|
|
|
self.add(title)
|
|
|
|
|
|
|
|
def add_circle_group(self):
|
|
|
|
self.circle.to_corner(DL)
|
|
|
|
circle_group = self.get_circle_group()
|
|
|
|
self.play(LaggedStart(FadeIn, VGroup(*circle_group.family_members_with_points())))
|
|
|
|
|
|
|
|
def state_lemma_premise(self):
|
|
|
|
premise = TextMobject("Lemma 1: If observer is halfway between lighthouses,")
|
|
|
|
self.premise = premise
|
|
|
|
premise.next_to(self.title, DOWN)
|
|
|
|
|
|
|
|
frac = 1.0 / self.num_lighthouses
|
|
|
|
arc1, arc2 = arcs = VGroup(VMobject(), VMobject())
|
|
|
|
arc1.pointwise_become_partial(self.circle, 0, frac / 2)
|
|
|
|
arc2.pointwise_become_partial(self.circle, frac / 2, frac)
|
|
|
|
arc1.reverse_points()
|
|
|
|
arcs.set_stroke(YELLOW, 5)
|
|
|
|
show_arcs = ShowCreationThenDestruction(
|
|
|
|
arcs,
|
|
|
|
submobject_mode="all_at_once",
|
|
|
|
run_time=2,
|
|
|
|
)
|
|
|
|
|
|
|
|
self.play(Write(premise), show_arcs, run_time=2)
|
|
|
|
self.wait()
|
|
|
|
self.play(show_arcs)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
def show_product(self):
|
|
|
|
lemma = TextMobject(self.lemma_text)
|
|
|
|
lemma.set_color(BLUE)
|
|
|
|
lemma.next_to(self.premise, DOWN)
|
|
|
|
self.add_numeric_distance_labels()
|
|
|
|
self.play(Write(lemma, run_time=1))
|
|
|
|
self.show_distance_product_in_column()
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
|
|
|
|
class Lemma1With7Lighthouses(Lemma1):
|
|
|
|
CONFIG = {
|
|
|
|
"num_lighthouses": 7,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Lemma1With8Lighthouses(Lemma1):
|
|
|
|
CONFIG = {
|
|
|
|
"num_lighthouses": 8,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Lemma1With9Lighthouses(Lemma1):
|
|
|
|
CONFIG = {
|
|
|
|
"num_lighthouses": 9,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Lemma2(Lemma1):
|
|
|
|
CONFIG = {
|
|
|
|
# "ambient_light_config": CHEAP_AMBIENT_LIGHT_CONFIG,
|
|
|
|
"lemma_text": "distance product = \\# Initial lighthouses"
|
|
|
|
}
|
|
|
|
|
|
|
|
def construct(self):
|
|
|
|
self.add_title()
|
|
|
|
self.add_circle_group()
|
|
|
|
self.state_lemma_premise()
|
|
|
|
self.replace_first_lighthouse()
|
|
|
|
self.show_product()
|
|
|
|
|
|
|
|
def state_lemma_premise(self):
|
|
|
|
premise = self.premise = TextMobject(
|
|
|
|
"If the observer replaces a lighthouse,"
|
|
|
|
)
|
|
|
|
premise.next_to(self.title, DOWN)
|
|
|
|
|
|
|
|
self.play(Write(premise, run_time=1))
|
|
|
|
|
|
|
|
def replace_first_lighthouse(self):
|
|
|
|
dot = self.observer_dot
|
|
|
|
observer_anim = MaintainPositionRelativeTo(self.observer, dot)
|
|
|
|
lighthouse_group = VGroup(self.lighthouses[0], self.lights[0])
|
|
|
|
point = self.get_lh_points()[0]
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
lighthouse_group.shift, 5 * RIGHT,
|
|
|
|
lighthouse_group.fade, 1,
|
|
|
|
run_time=1.5,
|
|
|
|
rate_func=running_start,
|
|
|
|
remover=True,
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
dot.move_to, point,
|
|
|
|
observer_anim,
|
|
|
|
path_arc=(-120 * DEGREES),
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
self.ignored_lighthouse_indices = [0]
|
|
|
|
self.observer_fraction = 0
|
|
|
|
for group in self.lighthouses, self.lights:
|
|
|
|
self.lighthouses.submobjects.pop(0)
|
|
|
|
|
|
|
|
|
|
|
|
class Lemma2With7Lighthouses(Lemma2):
|
|
|
|
CONFIG = {
|
|
|
|
"num_lighthouses": 7,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Lemma2With8Lighthouses(Lemma2):
|
|
|
|
CONFIG = {
|
|
|
|
"num_lighthouses": 8,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Lemma2With9Lighthouses(Lemma2):
|
|
|
|
CONFIG = {
|
|
|
|
"num_lighthouses": 9,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class FromGeometryToAlgebra(DistanceProductScene):
|
|
|
|
CONFIG = {
|
|
|
|
"num_lighthouses": 7,
|
|
|
|
"ambient_light_config": CHEAP_AMBIENT_LIGHT_CONFIG,
|
|
|
|
}
|
|
|
|
|
|
|
|
def construct(self):
|
|
|
|
self.setup_lights()
|
|
|
|
self.point_out_evenly_spaced()
|
|
|
|
self.transition_to_complex_plane()
|
|
|
|
self.name_roots_of_unity()
|
|
|
|
|
|
|
|
def setup_lights(self):
|
|
|
|
lights = self.get_lights()
|
|
|
|
circle = self.circle
|
|
|
|
|
|
|
|
self.add(circle, lights)
|
|
|
|
|
|
|
|
def point_out_evenly_spaced(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def transition_to_complex_plane(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def name_roots_of_unity(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-04-09 16:17:14 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|