mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 21:44:19 +08:00
More progress in putnam.py
This commit is contained in:
@ -253,6 +253,7 @@ class UpdateFromAlphaFunc(UpdateFromFunc):
|
||||
def update_mobject(self, alpha):
|
||||
self.update_function(self.mobject, alpha)
|
||||
|
||||
|
||||
class MaintainPositionRelativeTo(Animation):
|
||||
CONFIG = {
|
||||
"tracked_critical_point" : ORIGIN
|
||||
|
825
putnam.py
Normal file
825
putnam.py
Normal file
@ -0,0 +1,825 @@
|
||||
from helpers import *
|
||||
|
||||
from mobject.tex_mobject import TexMobject
|
||||
from mobject import Mobject
|
||||
from mobject.image_mobject import ImageMobject
|
||||
from mobject.vectorized_mobject import *
|
||||
|
||||
from animation.animation import Animation
|
||||
from animation.transform import *
|
||||
from animation.simple_animations import *
|
||||
from animation.playground import *
|
||||
from animation.continual_animation import *
|
||||
from topics.geometry import *
|
||||
from topics.characters import *
|
||||
from topics.functions import *
|
||||
from topics.fractals import *
|
||||
from topics.number_line import *
|
||||
from topics.combinatorics import *
|
||||
from topics.numerals import *
|
||||
from topics.three_dimensions import *
|
||||
from topics.objects import *
|
||||
from topics.probability import *
|
||||
from topics.complex_numbers import *
|
||||
from topics.common_scenes import *
|
||||
from scene import Scene
|
||||
from scene.reconfigurable_scene import ReconfigurableScene
|
||||
from scene.zoomed_scene import *
|
||||
from camera import Camera
|
||||
from mobject.svg_mobject import *
|
||||
from mobject.tex_mobject import *
|
||||
from topics.graph_scene import *
|
||||
from topics.probability import *
|
||||
|
||||
class ShowExampleTest(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
class IntroducePutnam(Scene):
|
||||
CONFIG = {
|
||||
"dont_animate" : False,
|
||||
}
|
||||
def construct(self):
|
||||
title = TextMobject("Putnam Competition")
|
||||
title.to_edge(UP, buff = MED_SMALL_BUFF)
|
||||
title.highlight(BLUE)
|
||||
six_hours = TextMobject("6", "hours")
|
||||
three_hours = TextMobject("3", "hours")
|
||||
for mob in six_hours, three_hours:
|
||||
mob.next_to(title, DOWN, MED_LARGE_BUFF)
|
||||
# mob.highlight(BLUE)
|
||||
three_hours.shift(SPACE_WIDTH*LEFT/2)
|
||||
three_hours_copy = three_hours.copy()
|
||||
three_hours_copy.shift(SPACE_WIDTH*RIGHT)
|
||||
|
||||
question_groups = VGroup(*[
|
||||
VGroup(*[
|
||||
TextMobject("%s%d)"%(c, i))
|
||||
for i in range(1, 7)
|
||||
]).arrange_submobjects(DOWN, buff = MED_LARGE_BUFF)
|
||||
for c in "A", "B"
|
||||
]).arrange_submobjects(RIGHT, buff = SPACE_WIDTH - MED_SMALL_BUFF)
|
||||
question_groups.to_edge(LEFT)
|
||||
question_groups.to_edge(DOWN, MED_LARGE_BUFF)
|
||||
flat_questions = VGroup(*it.chain(*question_groups))
|
||||
|
||||
rects = VGroup()
|
||||
for questions in question_groups:
|
||||
rect = SurroundingRectangle(questions, buff = MED_SMALL_BUFF)
|
||||
rect.set_stroke(WHITE, 2)
|
||||
rect.stretch_to_fit_width(SPACE_WIDTH - 1)
|
||||
rect.move_to(questions.get_left() + MED_SMALL_BUFF*LEFT, LEFT)
|
||||
rects.add(rect)
|
||||
|
||||
out_of_tens = VGroup()
|
||||
for question in flat_questions:
|
||||
out_of_ten = TexMobject("/10")
|
||||
out_of_ten.highlight(GREEN)
|
||||
out_of_ten.move_to(question)
|
||||
dist = rects[0].get_width() - 1.2
|
||||
out_of_ten.shift(dist*RIGHT)
|
||||
out_of_tens.add(out_of_ten)
|
||||
|
||||
out_of_120 = TexMobject("/120")
|
||||
out_of_120.next_to(title, RIGHT, LARGE_BUFF)
|
||||
out_of_120.highlight(GREEN)
|
||||
|
||||
out_of_120.generate_target()
|
||||
out_of_120.target.to_edge(RIGHT, LARGE_BUFF)
|
||||
median = TexMobject("2")
|
||||
median.next_to(out_of_120.target, LEFT, SMALL_BUFF)
|
||||
median.highlight(RED)
|
||||
median.align_to(out_of_120[-1])
|
||||
median_words = TextMobject("Typical median $\\rightarrow$")
|
||||
median_words.next_to(median, LEFT)
|
||||
|
||||
difficulty_strings = [
|
||||
"Pretty hard",
|
||||
"Hard",
|
||||
"Harder",
|
||||
"Very hard",
|
||||
"Ughhh",
|
||||
"Can I go home?"
|
||||
]
|
||||
colors = color_gradient([YELLOW, RED], len(difficulty_strings))
|
||||
difficulties = VGroup()
|
||||
for i, s, color in zip(it.count(), difficulty_strings, colors):
|
||||
for question_group in question_groups:
|
||||
question = question_group[i]
|
||||
text = TextMobject("\\dots %s \\dots"%s)
|
||||
text.scale(0.7)
|
||||
text.next_to(question, RIGHT)
|
||||
text.highlight(color)
|
||||
difficulties.add(text)
|
||||
|
||||
|
||||
if self.dont_animate:
|
||||
test = VGroup()
|
||||
test.rect = rects[0]
|
||||
test.questions = question_groups[0]
|
||||
test.out_of_tens = VGroup(*out_of_tens[:6])
|
||||
test.difficulties = VGroup(*difficulties[::2])
|
||||
test.digest_mobject_attrs()
|
||||
self.test = test
|
||||
return
|
||||
|
||||
self.add(title)
|
||||
self.play(Write(six_hours))
|
||||
self.play(LaggedStart(
|
||||
GrowFromCenter, flat_questions,
|
||||
run_time = 3,
|
||||
))
|
||||
self.play(
|
||||
ReplacementTransform(six_hours, three_hours),
|
||||
ReplacementTransform(six_hours.copy(), three_hours_copy),
|
||||
*map(ShowCreation, rects)
|
||||
)
|
||||
self.dither()
|
||||
self.play(LaggedStart(
|
||||
DrawBorderThenFill, out_of_tens,
|
||||
run_time = 3,
|
||||
stroke_color = YELLOW
|
||||
))
|
||||
self.dither()
|
||||
self.play(ReplacementTransform(
|
||||
out_of_tens.copy(), VGroup(out_of_120),
|
||||
submobject_mode = "lagged_start",
|
||||
run_time = 2,
|
||||
))
|
||||
self.dither()
|
||||
self.play(
|
||||
title.next_to, median_words.copy(), LEFT, LARGE_BUFF,
|
||||
MoveToTarget(out_of_120),
|
||||
Write(median_words)
|
||||
)
|
||||
self.play(Write(median))
|
||||
self.play(Write(difficulties, run_time = 3))
|
||||
self.dither()
|
||||
|
||||
class NatureOf5sAnd6s(TeacherStudentsScene):
|
||||
CONFIG = {
|
||||
"test_scale_val" : 0.65
|
||||
}
|
||||
def construct(self):
|
||||
test = self.get_test()
|
||||
|
||||
self.students.fade(1)
|
||||
self.play(
|
||||
test.scale, self.test_scale_val,
|
||||
test.to_corner, UP+LEFT,
|
||||
FadeIn(self.teacher),
|
||||
self.get_student_changes(
|
||||
*["horrified"]*3,
|
||||
look_at_arg = test
|
||||
)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
mover = VGroup(
|
||||
test.questions[-1].copy(),
|
||||
test.difficulties[-1].copy(),
|
||||
)
|
||||
mover.generate_target()
|
||||
mover.target.scale(1./self.test_scale_val)
|
||||
mover.target.next_to(
|
||||
self.teacher.get_corner(UP+LEFT), UP,
|
||||
)
|
||||
new_words = TextMobject("\\dots Potentially very elegant \\dots")
|
||||
new_words.highlight(GREEN)
|
||||
new_words.scale_to_fit_height(mover.target[1].get_height())
|
||||
new_words.next_to(mover.target[0], RIGHT, SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
MoveToTarget(mover),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
)
|
||||
self.change_student_modes(*["pondering"]*3)
|
||||
self.play(Transform(mover[1], new_words))
|
||||
self.look_at((SPACE_WIDTH*RIGHT + SPACE_HEIGHT*UP)/2)
|
||||
self.dither(4)
|
||||
|
||||
|
||||
###
|
||||
|
||||
def get_test(self):
|
||||
prev_scene = IntroducePutnam(dont_animate = True)
|
||||
return prev_scene.test
|
||||
|
||||
class OtherVideoClips(Scene):
|
||||
def construct(self):
|
||||
rect = ScreenRectangle()
|
||||
rect.scale_to_fit_height(6.5)
|
||||
rect.center()
|
||||
rect.to_edge(DOWN)
|
||||
titles = map(TextMobject, [
|
||||
"Essence of calculus, chapter 1",
|
||||
"Pi hiding in prime regularities",
|
||||
"How do cryptocurrencies work?"
|
||||
])
|
||||
|
||||
self.add(rect)
|
||||
last_title = None
|
||||
for title in titles:
|
||||
title.to_edge(UP, buff = MED_SMALL_BUFF)
|
||||
if last_title:
|
||||
self.play(ReplacementTransform(last_title, title))
|
||||
else:
|
||||
self.play(FadeIn(title))
|
||||
self.dither(3)
|
||||
last_title = title
|
||||
|
||||
class IntroduceTetrahedron(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
class IntroduceTetrahedronSupplement(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("4", "random$^*$ points on sphere")
|
||||
title.highlight(YELLOW)
|
||||
question = TextMobject("Probability that this tetrahedron \\\\ contains the sphere's center?")
|
||||
question.next_to(title, DOWN, MED_LARGE_BUFF)
|
||||
group = VGroup(title, question)
|
||||
group.scale_to_fit_width(2*SPACE_WIDTH-1)
|
||||
group.to_edge(DOWN)
|
||||
|
||||
for n in range(1, 4):
|
||||
num = TextMobject(str(n))
|
||||
num.replace(title[0], dim_to_match = 1)
|
||||
num.highlight(YELLOW)
|
||||
self.add(num)
|
||||
self.dither(0.7)
|
||||
self.remove(num)
|
||||
self.add(title[0])
|
||||
self.play(FadeIn(title[1], submobject_mode = "lagged_start"))
|
||||
self.dither(2)
|
||||
self.play(Write(question))
|
||||
self.dither(2)
|
||||
|
||||
class IntroduceTetrahedronFootnote(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("""
|
||||
$^*$Chosen independently with a \\\\
|
||||
uniform distribution on the sphere.
|
||||
""")
|
||||
words.to_corner(UP+LEFT)
|
||||
self.add(words)
|
||||
self.dither(2)
|
||||
|
||||
class HowDoYouStart(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"How do you even start?",
|
||||
target_mode = "raise_left_hand"
|
||||
)
|
||||
self.change_student_modes("confused", "raise_left_hand", "erm")
|
||||
self.dither()
|
||||
self.teacher_says("Try a simpler case.")
|
||||
self.change_student_modes(*["thinking"]*3)
|
||||
self.dither(2)
|
||||
|
||||
class TwoDCase(Scene):
|
||||
CONFIG = {
|
||||
"random_seed" : 4,
|
||||
"radius" : 2.5,
|
||||
"center_color" : BLUE,
|
||||
"point_color" : YELLOW,
|
||||
"positive_triangle_color" : BLUE,
|
||||
"negative_triangle_color" : RED,
|
||||
"triangle_fill_opacity" : 0.25,
|
||||
"n_initial_random_choices" : 9,
|
||||
"n_p3_random_moves" : 4,
|
||||
}
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.add_circle()
|
||||
self.choose_three_random_points()
|
||||
self.simplify_further()
|
||||
self.fix_two_points_in_place()
|
||||
self.note_special_region()
|
||||
self.draw_lines_through_center()
|
||||
self.ask_about_probability_p3_lands_in_this_arc()
|
||||
self.various_arc_sizes_for_p1_p2_placements()
|
||||
self.ask_about_average_arc_size()
|
||||
self.fix_p1_in_place()
|
||||
self.overall_probability()
|
||||
|
||||
def add_title(self):
|
||||
title = TextMobject("2D Case")
|
||||
title.to_corner(UP+LEFT)
|
||||
self.add(title)
|
||||
self.set_variables_as_attrs(title)
|
||||
|
||||
def add_circle(self):
|
||||
circle = Circle(radius = self.radius, color = WHITE)
|
||||
center_dot = Dot(color = self.center_color).center()
|
||||
radius = DashedLine(ORIGIN, circle.radius*RIGHT)
|
||||
|
||||
self.add(center_dot)
|
||||
self.play(ShowCreation(radius))
|
||||
self.play(
|
||||
ShowCreation(circle),
|
||||
Rotating(radius, angle = 2*np.pi, about_point = ORIGIN),
|
||||
rate_func = smooth,
|
||||
run_time = 2,
|
||||
)
|
||||
self.play(ShowCreation(
|
||||
radius,
|
||||
rate_func = lambda t : smooth(1-t),
|
||||
remover = True
|
||||
))
|
||||
self.dither()
|
||||
|
||||
self.set_variables_as_attrs(circle, center_dot)
|
||||
|
||||
def choose_three_random_points(self):
|
||||
points = np.array([
|
||||
rotate_vector(self.radius*RIGHT, theta)
|
||||
for theta in 2*np.pi*np.random.random(3)
|
||||
])
|
||||
for index in 0, 1, 0:
|
||||
if self.points_contain_center(points):
|
||||
break
|
||||
points[index] *= -1
|
||||
|
||||
point_mobs = self.point_mobs = VGroup(*[
|
||||
Dot().move_to(point) for point in points
|
||||
])
|
||||
point_mobs.highlight(self.point_color)
|
||||
point_labels = VGroup(*[
|
||||
TexMobject("P_%d"%(i+1))
|
||||
for i in range(len(point_mobs))
|
||||
])
|
||||
point_labels.highlight(point_mobs.get_color())
|
||||
self.point_labels_update = self.get_labels_update(point_mobs, point_labels)
|
||||
triangle = self.triangle = RegularPolygon(n = 3)
|
||||
triangle.set_fill(WHITE, opacity = self.triangle_fill_opacity)
|
||||
self.triangle_update = self.get_triangle_update(point_mobs, triangle)
|
||||
self.update_animations = [
|
||||
self.triangle_update,
|
||||
self.point_labels_update,
|
||||
]
|
||||
for anim in self.update_animations:
|
||||
anim.update(0)
|
||||
|
||||
question = TextMobject(
|
||||
"Probability that \\\\ this triangle \\\\",
|
||||
"contains the center", "?",
|
||||
arg_separator = "",
|
||||
)
|
||||
question.highlight_by_tex("center", self.center_color)
|
||||
question.scale(0.8)
|
||||
question.to_corner(UP+RIGHT)
|
||||
self.question = question
|
||||
|
||||
self.play(LaggedStart(DrawBorderThenFill, point_mobs))
|
||||
self.play(FadeIn(triangle))
|
||||
self.dither()
|
||||
self.play(LaggedStart(Write, point_labels))
|
||||
self.dither()
|
||||
self.play(Write(question))
|
||||
for x in range(self.n_initial_random_choices):
|
||||
self.change_point_mobs_randomly()
|
||||
self.dither()
|
||||
angles = self.get_point_mob_angles()
|
||||
target_angles = [5*np.pi/8, 7*np.pi/8, 0]
|
||||
self.change_point_mobs([ta - a for a, ta in zip(angles, target_angles)])
|
||||
self.dither()
|
||||
|
||||
def simplify_further(self):
|
||||
morty = Mortimer().flip()
|
||||
morty.scale(0.75)
|
||||
morty.to_edge(DOWN)
|
||||
morty.shift(3.5*LEFT)
|
||||
|
||||
bubble = SpeechBubble(
|
||||
direction = RIGHT,
|
||||
height = 3, width = 3
|
||||
)
|
||||
bubble.pin_to(morty)
|
||||
bubble.to_edge(LEFT, SMALL_BUFF)
|
||||
bubble.write("Simplify \\\\ more!")
|
||||
|
||||
self.play(FadeIn(morty))
|
||||
self.play(
|
||||
morty.change, "hooray",
|
||||
ShowCreation(bubble),
|
||||
Write(bubble.content)
|
||||
)
|
||||
self.play(Blink(morty))
|
||||
self.dither()
|
||||
self.play(
|
||||
morty.change, "happy",
|
||||
morty.fade, 1,
|
||||
*map(FadeOut, [bubble, bubble.content])
|
||||
)
|
||||
self.remove(morty)
|
||||
|
||||
def fix_two_points_in_place(self):
|
||||
push_pins = VGroup()
|
||||
for point_mob in self.point_mobs[:-1]:
|
||||
push_pin = SVGMobject(file_name = "push_pin")
|
||||
push_pin.scale_to_fit_height(0.5)
|
||||
push_pin.move_to(point_mob.get_center(), DOWN)
|
||||
line = Line(ORIGIN, UP)
|
||||
line.set_stroke(WHITE, 2)
|
||||
line.scale_to_fit_height(0.1)
|
||||
line.move_to(push_pin, UP)
|
||||
line.shift(0.3*SMALL_BUFF*(2*DOWN+LEFT))
|
||||
push_pin.add(line)
|
||||
push_pin.set_fill(LIGHT_GREY)
|
||||
push_pin.save_state()
|
||||
push_pin.shift(UP)
|
||||
push_pin.fade(1)
|
||||
push_pins.add(push_pin)
|
||||
|
||||
self.play(LaggedStart(
|
||||
ApplyMethod, push_pins,
|
||||
lambda mob : (mob.restore,)
|
||||
))
|
||||
self.add_foreground_mobjects(push_pins)
|
||||
d_thetas = 2*np.pi*np.random.random(self.n_p3_random_moves)
|
||||
for d_theta in d_thetas:
|
||||
self.change_point_mobs([0, 0, d_theta])
|
||||
self.dither()
|
||||
|
||||
self.set_variables_as_attrs(push_pins)
|
||||
|
||||
def note_special_region(self):
|
||||
point_mobs = self.point_mobs
|
||||
angles = self.get_point_mob_angles()
|
||||
|
||||
all_arcs = self.get_all_arcs()
|
||||
arc = all_arcs[-1]
|
||||
arc_lines = VGroup()
|
||||
for angle in angles[:2]:
|
||||
line = Line(LEFT, RIGHT).scale(SMALL_BUFF)
|
||||
line.shift(self.radius*RIGHT)
|
||||
line.rotate(angle + np.pi)
|
||||
line.set_stroke(arc.get_color())
|
||||
arc_lines.add(line)
|
||||
|
||||
self.play(ShowCreation(arc_lines))
|
||||
self.change_point_mobs([0, 0, angles[0]+np.pi-angles[2]])
|
||||
self.change_point_mobs(
|
||||
[0, 0, arc.angle],
|
||||
ShowCreation(arc, run_time = 2)
|
||||
)
|
||||
self.change_point_mobs([0, 0, np.pi/4 - angles[1]])
|
||||
self.change_point_mobs([0, 0, 0.99*np.pi], run_time = 4)
|
||||
self.dither()
|
||||
|
||||
self.set_variables_as_attrs(all_arcs, arc, arc_lines)
|
||||
|
||||
def draw_lines_through_center(self):
|
||||
point_mobs = self.point_mobs
|
||||
angles = self.get_point_mob_angles()
|
||||
all_arcs = self.all_arcs
|
||||
|
||||
lines = VGroup()
|
||||
for angle in angles[:2]:
|
||||
line = DashedLine(
|
||||
self.radius*RIGHT, self.radius*LEFT
|
||||
)
|
||||
line.rotate(angle)
|
||||
line.highlight(self.point_color)
|
||||
lines.add(line)
|
||||
|
||||
self.add_foreground_mobjects(self.center_dot)
|
||||
for line in lines:
|
||||
self.play(ShowCreation(line))
|
||||
self.play(FadeIn(all_arcs), Animation(point_mobs))
|
||||
self.remove(self.circle)
|
||||
self.dither()
|
||||
self.play(
|
||||
all_arcs.space_out_submobjects, 1.5,
|
||||
Animation(point_mobs),
|
||||
rate_func = there_and_back,
|
||||
run_time = 1.5,
|
||||
)
|
||||
self.dither()
|
||||
self.change_point_mobs(
|
||||
[0, 0, np.mean(angles[:2])+np.pi-angles[2]]
|
||||
)
|
||||
self.dither()
|
||||
for x in range(3):
|
||||
self.change_point_mobs([0, 0, np.pi/2])
|
||||
self.dither()
|
||||
|
||||
self.center_lines = lines
|
||||
|
||||
def ask_about_probability_p3_lands_in_this_arc(self):
|
||||
arc = self.arc
|
||||
|
||||
arrow = Vector(LEFT, color = BLUE)
|
||||
arrow.next_to(arc.get_center(), RIGHT, MED_LARGE_BUFF)
|
||||
question = TextMobject("Probability of landing \\\\ in this arc?")
|
||||
question.scale(0.8)
|
||||
question.next_to(arrow, RIGHT)
|
||||
question.shift_onto_screen()
|
||||
question.shift(SMALL_BUFF*UP)
|
||||
|
||||
answer = TexMobject(
|
||||
"{\\text{Length of arc}", "\\over",
|
||||
"\\text{Circumference}}"
|
||||
)
|
||||
answer.highlight_by_tex("arc", BLUE)
|
||||
answer.scale(0.8)
|
||||
answer.next_to(arrow, RIGHT)
|
||||
equals = TexMobject("=")
|
||||
equals.rotate(np.pi/2)
|
||||
equals.next_to(answer, UP, buff = 0.35)
|
||||
|
||||
self.play(FadeIn(question), GrowArrow(arrow))
|
||||
self.have_p3_jump_around_randomly(15)
|
||||
self.play(
|
||||
question.next_to, answer, UP, LARGE_BUFF,
|
||||
Write(equals),
|
||||
FadeIn(answer)
|
||||
)
|
||||
self.have_p3_jump_around_randomly(4)
|
||||
angles = self.get_point_mob_angles()
|
||||
self.change_point_mobs(
|
||||
[0, 0, 1.35*np.pi - angles[2]],
|
||||
run_time = 0,
|
||||
)
|
||||
self.dither()
|
||||
|
||||
question.add(equals)
|
||||
self.arc_prob_question = question
|
||||
self.arc_prob = answer
|
||||
self.arc_size_arrow = arrow
|
||||
|
||||
def various_arc_sizes_for_p1_p2_placements(self):
|
||||
arc = self.arc
|
||||
|
||||
self.triangle.save_state()
|
||||
self.play(*map(FadeOut, [
|
||||
self.push_pins, self.triangle, self.arc_lines
|
||||
]))
|
||||
self.update_animations.remove(self.triangle_update)
|
||||
self.update_animations += [
|
||||
self.get_center_lines_update(self.point_mobs, self.center_lines),
|
||||
self.get_arcs_update(self.all_arcs)
|
||||
]
|
||||
|
||||
#90 degree angle
|
||||
self.change_point_mobs_to_angles([np.pi/2, np.pi], run_time = 1)
|
||||
elbow = VGroup(
|
||||
Line(DOWN, DOWN+RIGHT),
|
||||
Line(DOWN+RIGHT, RIGHT),
|
||||
)
|
||||
elbow.scale(0.25)
|
||||
ninety_degrees = TexMobject("90^\\circ")
|
||||
ninety_degrees.next_to(elbow, DOWN+RIGHT, buff = 0)
|
||||
proportion = DecimalNumber(0.25)
|
||||
proportion.highlight(self.center_color)
|
||||
# proportion.next_to(arc.point_from_proportion(0.5), DOWN, MED_LARGE_BUFF)
|
||||
proportion.next_to(self.arc_size_arrow, DOWN)
|
||||
def proportion_update_func(alpha):
|
||||
angles = self.get_point_mob_angles()
|
||||
diff = abs(angles[1]-angles[0])/(2*np.pi)
|
||||
return min(diff, 1-diff)
|
||||
proportion_update = ChangingDecimal(proportion, proportion_update_func)
|
||||
|
||||
self.play(ShowCreation(elbow), FadeIn(ninety_degrees))
|
||||
self.dither()
|
||||
self.play(
|
||||
ApplyMethod(
|
||||
arc.rotate_in_place, np.pi/12,
|
||||
rate_func = wiggle,
|
||||
)
|
||||
)
|
||||
self.play(LaggedStart(FadeIn, proportion, run_time = 1))
|
||||
self.dither()
|
||||
|
||||
#Non right angles
|
||||
angle_pairs = [
|
||||
(0.26*np.pi, 1.24*np.pi),
|
||||
(0.73*np.pi, 0.78*np.pi),
|
||||
(0.5*np.pi, np.pi),
|
||||
]
|
||||
self.update_animations.append(proportion_update)
|
||||
for angle_pair in angle_pairs:
|
||||
self.change_point_mobs_to_angles(
|
||||
angle_pair,
|
||||
VGroup(elbow, ninety_degrees).fade, 1,
|
||||
)
|
||||
self.remove(elbow, ninety_degrees)
|
||||
self.dither()
|
||||
|
||||
self.set_variables_as_attrs(proportion, proportion_update)
|
||||
|
||||
def ask_about_average_arc_size(self):
|
||||
proportion = self.proportion
|
||||
brace = Brace(proportion, DOWN, buff = SMALL_BUFF)
|
||||
average = brace.get_text("Average?", buff = SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(average)
|
||||
)
|
||||
for x in range(6):
|
||||
self.change_point_mobs_to_angles(
|
||||
2*np.pi*np.random.random(2)
|
||||
)
|
||||
self.change_point_mobs_to_angles(
|
||||
[1.2*np.pi, 0.3*np.pi]
|
||||
)
|
||||
self.dither()
|
||||
|
||||
self.set_variables_as_attrs(brace, average)
|
||||
|
||||
def fix_p1_in_place(self):
|
||||
push_pin = self.push_pins[0]
|
||||
P1, P2, P3 = point_mobs = self.point_mobs
|
||||
|
||||
self.change_point_mobs_to_angles([0.9*np.pi])
|
||||
push_pin.move_to(P1.get_center(), DOWN)
|
||||
push_pin.save_state()
|
||||
push_pin.shift(UP)
|
||||
push_pin.fade(1)
|
||||
self.play(push_pin.restore)
|
||||
for angle in [0.89999*np.pi, -0.09999*np.pi, 0.4*np.pi]:
|
||||
self.change_point_mobs_to_angles(
|
||||
[0.9*np.pi, angle],
|
||||
run_time = 4,
|
||||
)
|
||||
self.play(FadeOut(self.average[-1]))
|
||||
|
||||
def overall_probability(self):
|
||||
point_mobs = self.point_mobs
|
||||
triangle = self.triangle
|
||||
|
||||
one_fourth = TexMobject("1/4")
|
||||
one_fourth.highlight(BLUE)
|
||||
one_fourth.next_to(self.question, DOWN)
|
||||
|
||||
self.triangle_update.update(1)
|
||||
self.play(
|
||||
FadeIn(triangle),
|
||||
Animation(point_mobs)
|
||||
)
|
||||
self.update_animations.append(self.triangle_update)
|
||||
self.have_p3_jump_around_randomly(8, dither_time = 0.25)
|
||||
self.play(ReplacementTransform(
|
||||
self.proportion.copy(), VGroup(one_fourth)
|
||||
))
|
||||
self.have_p3_jump_around_randomly(32, dither_time = 0.25)
|
||||
|
||||
#####
|
||||
|
||||
def get_labels_update(self, point_mobs, labels):
|
||||
def update_labels(labels):
|
||||
for point_mob, label in zip(point_mobs, labels):
|
||||
label.move_to(point_mob)
|
||||
vect = point_mob.get_center()
|
||||
vect /= np.linalg.norm(vect)
|
||||
label.shift(MED_LARGE_BUFF*vect)
|
||||
return labels
|
||||
return UpdateFromFunc(labels, update_labels)
|
||||
|
||||
def get_triangle_update(self, point_mobs, triangle):
|
||||
def update_triangle(triangle):
|
||||
points = [pm.get_center() for pm in point_mobs]
|
||||
triangle.set_points_as_corners(points)
|
||||
if self.points_contain_center(points):
|
||||
triangle.highlight(self.positive_triangle_color)
|
||||
else:
|
||||
triangle.highlight(self.negative_triangle_color)
|
||||
return triangle
|
||||
return UpdateFromFunc(triangle, update_triangle)
|
||||
|
||||
def get_center_lines_update(self, point_mobs, center_lines):
|
||||
def update_lines(center_lines):
|
||||
for point_mob, line in zip(point_mobs, center_lines):
|
||||
line.rotate(
|
||||
angle_of_vector(point_mob.get_center()) - \
|
||||
line.get_angle()
|
||||
)
|
||||
return center_lines
|
||||
return UpdateFromFunc(center_lines, update_lines)
|
||||
|
||||
def get_arcs_update(self, all_arcs):
|
||||
def update_arcs(arcs):
|
||||
new_arcs = self.get_all_arcs()
|
||||
Transform(arcs, new_arcs).update(1)
|
||||
return arcs
|
||||
return UpdateFromFunc(all_arcs, update_arcs)
|
||||
|
||||
def get_all_arcs(self):
|
||||
angles = self.get_point_mob_angles()
|
||||
all_arcs = VGroup()
|
||||
for da0, da1 in it.product(*[[0, np.pi]]*2):
|
||||
arc_angle = (angles[1]+da1) - (angles[0]+da0)
|
||||
arc_angle = (arc_angle+np.pi)%(2*np.pi)-np.pi
|
||||
arc = Arc(
|
||||
start_angle = angles[0]+da0,
|
||||
angle = arc_angle,
|
||||
radius = self.radius,
|
||||
stroke_width = 5,
|
||||
)
|
||||
all_arcs.add(arc)
|
||||
all_arcs.gradient_highlight(RED, MAROON_B, PINK, BLUE)
|
||||
return all_arcs
|
||||
|
||||
def points_contain_center(self, points):
|
||||
p0, p1, p2 = points
|
||||
v1 = p1 - p0
|
||||
v2 = p2 - p0
|
||||
c = -p0
|
||||
M = np.matrix([v1[:2], v2[:2]]).T
|
||||
M_inv = np.linalg.inv(M)
|
||||
coords = np.dot(M_inv, c[:2])
|
||||
return np.all(coords > 0) and (np.sum(coords.flatten()) <= 1)
|
||||
|
||||
def get_point_mob_theta_change_anim(self, point_mob, d_theta):
|
||||
curr_theta = angle_of_vector(point_mob.get_center())
|
||||
d_theta = (d_theta + np.pi)%(2*np.pi) - np.pi
|
||||
new_theta = curr_theta + d_theta
|
||||
|
||||
def update_point(point_mob, alpha):
|
||||
theta = interpolate(curr_theta, new_theta, alpha)
|
||||
point_mob.move_to(self.radius*(
|
||||
np.cos(theta)*RIGHT + np.sin(theta)*UP
|
||||
))
|
||||
return point_mob
|
||||
return UpdateFromAlphaFunc(point_mob, update_point, run_time = 2)
|
||||
|
||||
def change_point_mobs(self, d_thetas, *added_anims, **kwargs):
|
||||
anims = it.chain(
|
||||
self.update_animations,
|
||||
[
|
||||
self.get_point_mob_theta_change_anim(pm, dt)
|
||||
for pm, dt in zip(self.point_mobs, d_thetas)
|
||||
],
|
||||
added_anims
|
||||
)
|
||||
self.play(*anims, **kwargs)
|
||||
for update in self.update_animations:
|
||||
update.update(1)
|
||||
|
||||
def change_point_mobs_randomly(self, *added_anims, **kwargs):
|
||||
d_thetas = 2*np.pi*np.random.random(len(self.point_mobs))
|
||||
self.change_point_mobs(d_thetas, *added_anims, **kwargs)
|
||||
|
||||
def change_point_mobs_to_angles(self, target_angles, *added_anims, **kwargs):
|
||||
angles = self.get_point_mob_angles()
|
||||
n_added_targets = len(angles) - len(target_angles)
|
||||
target_angles = list(target_angles) + list(angles[-n_added_targets:])
|
||||
self.change_point_mobs(
|
||||
[ta-a for a, ta in zip(angles, target_angles)],
|
||||
*added_anims, **kwargs
|
||||
)
|
||||
|
||||
def get_point_mob_angles(self):
|
||||
point_mobs = self.point_mobs
|
||||
points = [pm.get_center() for pm in point_mobs]
|
||||
return np.array(map(angle_of_vector, points))
|
||||
|
||||
def have_p3_jump_around_randomly(self, n_jumps, dither_time = 0.75, run_time = 0):
|
||||
for x in range(n_jumps):
|
||||
self.change_point_mobs(
|
||||
[0, 0, 2*np.pi*random.random()],
|
||||
run_time = run_time
|
||||
)
|
||||
self.dither(dither_time)
|
||||
|
||||
class FixThreePointsOnSphere(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
class AddCenterLinesAndPlanesToSphere(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
class AverageSizeOfSphericalTriangleSection(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
class AverageSizeOfSphericalTriangleSectionSupplement(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject(
|
||||
"Average size of \\\\", "this section", "?",
|
||||
arg_separator = ""
|
||||
)
|
||||
words.highlight_by_tex("section", GREEN)
|
||||
words.scale_to_fit_width(2*SPACE_WIDTH - 1)
|
||||
words.to_edge(DOWN)
|
||||
self.play(Write(words))
|
||||
self.dither(3)
|
||||
|
||||
class TryASurfaceIntegral(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says("Can you do \\\\ a surface integral?")
|
||||
self.change_student_modes("confused", "raise_left_hand", "confused")
|
||||
self.dither()
|
||||
self.teacher_says(
|
||||
"I mean...you can \\emph{try}",
|
||||
target_mode = "sassy",
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user