Up to definition of problem in wcat

This commit is contained in:
Grant Sanderson
2016-10-26 17:17:07 -07:00
parent 15b8236b26
commit de75d1464b
6 changed files with 566 additions and 7 deletions

View File

@ -33,7 +33,7 @@ MED_BUFF = 0.25
LARGE_BUFF = 1
DEFAULT_MOBJECT_TO_EDGE_BUFFER = MED_BUFF
DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = SMALL_BUFF
DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_BUFF
#All in seconds

View File

@ -42,6 +42,7 @@ def play_finish_sound():
play_chord(12, 9, 5, 2)
def get_smooth_handle_points(points):
points = np.array(points)
num_handles = len(points) - 1
dim = points.shape[1]
if num_handles < 1:

View File

@ -76,12 +76,12 @@ class Scene(object):
###
def extract_mobject_family_members(self, *mobjects):
return remove_list_redundancies(list(
return list(
it.chain(*[
m.submobject_family()
for m in mobjects
])
))
)
def add(self, *mobjects_to_add):
"""
@ -237,7 +237,6 @@ class Scene(object):
animations = self.align_run_times(*animations, **kwargs)
moving_mobjects, static_mobjects = \
self.separate_moving_and_static_mobjects(*animations)
self.update_frame(static_mobjects)
static_image = self.get_frame()
for t in self.get_time_progression(animations):

View File

@ -51,11 +51,11 @@ class PiCreature(SVGMobject):
def name_parts(self):
self.mouth = self.submobjects[MOUTH_INDEX]
self.body = self.submobjects[BODY_INDEX]
self.pupils = VMobject(*[
self.pupils = VGroup(*[
self.submobjects[LEFT_PUPIL_INDEX],
self.submobjects[RIGHT_PUPIL_INDEX]
])
self.eyes = VMobject(*[
self.eyes = VGroup(*[
self.submobjects[LEFT_EYE_INDEX],
self.submobjects[RIGHT_EYE_INDEX]
])
@ -176,6 +176,28 @@ class Mathematician(PiCreature):
"color" : GREY,
}
class BabyPiCreature(PiCreature):
CONFIG = {
"scale_factor" : 0.5,
"eye_scale_factor" : 1.2,
"pupil_scale_factor" : 1.3
}
def __init__(self, *args, **kwargs):
PiCreature.__init__(self, *args, **kwargs)
self.scale(self.scale_factor)
self.shift(LEFT)
self.to_edge(DOWN, buff = LARGE_BUFF)
eyes = VGroup(self.eyes, self.pupils)
eyes_bottom = eyes.get_bottom()
eyes.scale(self.eye_scale_factor)
eyes.move_to(eyes_bottom, aligned_edge = DOWN)
looking_direction = self.get_looking_direction()
for pupil in self.pupils:
pupil.scale_in_place(self.pupil_scale_factor)
self.look(looking_direction)
class Blink(ApplyMethod):
CONFIG = {
"rate_func" : squish_rate_func(there_and_back)

View File

@ -50,7 +50,7 @@ class Circle(Arc):
class Dot(Circle): #Use 1D density, even though 2D
CONFIG = {
"radius" : 0.05,
"radius" : 0.08,
"stroke_width" : 0,
"fill_opacity" : 1.0,
"color" : WHITE

537
wcat.py Normal file
View File

@ -0,0 +1,537 @@
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 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 scene import Scene
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
class ClosedLoopScene(Scene):
CONFIG = {
"loop_anchor_points" : [
3*RIGHT,
2*RIGHT+UP,
3*RIGHT + 3*UP,
UP,
2*UP+LEFT,
2*LEFT + 2*UP,
3*LEFT,
2*LEFT+DOWN,
3*LEFT+2*DOWN,
2*DOWN+RIGHT,
LEFT+DOWN,
],
"square_vertices" : [
2*RIGHT+UP,
2*UP+LEFT,
2*LEFT+DOWN,
2*DOWN+RIGHT
],
"rect_vertices" : [
0*RIGHT + 1*UP,
-1*RIGHT + 2*UP,
-3*RIGHT + 0*UP,
-2*RIGHT + -1*UP,
],
"dot_color" : YELLOW,
"connecting_lines_color" : BLUE,
}
def setup(self):
self.dots = VGroup()
self.connecting_lines = VGroup()
self.add_loop()
def add_loop(self):
self.loop = self.get_default_loop()
self.add(self.loop)
def get_default_loop(self):
loop = VMobject()
loop.set_points_smoothly(
self.loop_anchor_points + [self.loop_anchor_points[0]]
)
return loop
def get_square(self):
return Polygon(*self.square_vertices)
def get_rect_vertex_dots(self, square = False):
if square:
vertices = self.square_vertices
else:
vertices = self.rect_vertices
dots = VGroup(*[Dot(v) for v in vertices])
dots.highlight(self.dot_color)
return dots
def add_dot(self, dot):
self.add_dots(dot)
def add_dots(self, *dots):
self.dots.add(*dots)
self.add(self.dots)
def add_rect_dots(self, square = False):
self.add_dots(*self.get_rect_vertex_dots())
def add_dots_at_alphas(self, *alphas):
self.add_dots(*[
Dot(
self.loop.point_from_proportion(alpha),
color = self.dot_color
)
for alpha in alphas
])
def add_connecting_lines(self, cyclic = False):
if cyclic:
pairs = adjascent_pairs(self.dots)
else:
n_pairs = len(list(self.dots))/2
pairs = zip(self.dots[:n_pairs], self.dots[n_pairs:])
for d1, d2 in pairs:
line = Line(
d1.get_center(), d2.get_center(),
stroke_width = 6
)
line.start_dot = d1
line.end_dot = d2
line.update_anim = UpdateFromFunc(
line,
lambda l : l.put_start_and_end_on(
l.start_dot.get_center(),
l.end_dot.get_center()
)
)
self.connecting_lines.add(line)
self.connecting_lines.highlight(self.connecting_lines_color)
self.add(self.connecting_lines, self.dots)
def get_line_anims(self):
return [
line.update_anim
for line in self.connecting_lines
] + [Animation(self.dots)]
def get_dot_alphas(self, dots = None, precision = 0.005):
if dots == None:
dots = self.dots
alphas = []
alpha_range = np.arange(0, 1, precision)
loop_points = np.array(map(self.loop.point_from_proportion, alpha_range))
for dot in dots:
vects = loop_points - dot.get_center()
norms = np.apply_along_axis(np.linalg.norm, 1, vects)
index = np.argmin(norms)
alphas.append(alpha_range[index])
return alphas
def let_dots_wonder(self, run_time = 5, random_seed = None, added_anims = []):
if random_seed is not None:
np.random.seed(random_seed)
start_alphas = self.get_dot_alphas()
alpha_rates = 0.1 + 0.1*np.random.random(len(list(self.dots)))
def generate_rate_func(start, rate):
return lambda t : (start + t*rate*run_time)%1
anims = [
MoveAlongPath(
dot,
self.loop,
rate_func = generate_rate_func(start, rate)
)
for dot, start, rate in zip(self.dots, start_alphas, alpha_rates)
]
anims += self.get_line_anims()
anims += added_anims
self.play(*anims, run_time = run_time)
def move_dots_to_alphas(self, alphas, run_time = 3):
assert(len(alphas) == len(list(self.dots)))
start_alphas = self.get_dot_alphas()
def generate_rate_func(start_alpha, alpha):
return lambda t : interpolate(start_alpha, alpha, smooth(t))
anims = [
MoveAlongPath(
dot, self.loop,
rate_func = generate_rate_func(sa, a),
run_time = run_time,
)
for dot, sa, a in zip(self.dots, start_alphas, alphas)
]
anims += self.get_line_anims()
self.play(*anims)
def transform_loop(self, target_loop, **kwargs):
alphas = self.get_dot_alphas()
dot_anims = []
for dot, alpha in zip(self.dots, alphas):
dot.generate_target()
dot.target.move_to(target_loop.point_from_proportion(alpha))
dot_anims.append(MoveToTarget(dot))
self.play(
Transform(self.loop, target_loop),
*dot_anims + self.get_line_anims(),
**kwargs
)
self.remove(self.loop)
self.loop = target_loop
self.add(self.loop)
def find_square(self):
alpha_quads = list(it.combinations(
np.arange(0, 1, 0.02) , 4
))
quads = np.array([
[
self.loop.point_from_proportion(alpha)
for alpha in quad
]
for quad in alpha_quads
])
scores = self.square_scores(quads)
index = np.argmin(scores)
return quads[index]
def square_scores(self, all_quads):
midpoint_diffs = np.apply_along_axis(
np.linalg.norm, 1,
0.5*(all_quads[:,0] + all_quads[:,2]) - 0.5*(all_quads[:,1] + all_quads[:,3])
)
vects1 = all_quads[:,0] - all_quads[:,2]
vects2 = all_quads[:,1] - all_quads[:,3]
distances1 = np.apply_along_axis(np.linalg.norm, 1, vects1)
distances2 = np.apply_along_axis(np.linalg.norm, 1, vects2)
distance_diffs = np.abs(distances1 - distances2)
midpoint_diffs /= distances1
distance_diffs /= distances2
buffed_d1s = np.repeat(distances1, 3).reshape(vects1.shape)
buffed_d2s = np.repeat(distances2, 3).reshape(vects2.shape)
unit_v1s = vects1/buffed_d1s
unit_v2s = vects2/buffed_d2s
dots = np.abs(unit_v1s[:,0]*unit_v2s[:,0] + unit_v1s[:,1]*unit_v2s[:,1] + unit_v1s[:,2]*unit_v2s[:,2])
return midpoint_diffs + distance_diffs + dots
#############################
class Introduction(TeacherStudentsScene):
def construct(self):
self.play(self.get_teacher().change_mode, "hooray")
self.random_blink()
self.teacher_says("")
for pi in self.get_students():
pi.generate_target()
pi.target.change_mode("happy")
pi.target.look_at(self.get_teacher().bubble)
self.play(*map(MoveToTarget, self.get_students()))
self.random_blink(3)
self.teacher_says(
"Here's why \\\\ I'm excited...",
pi_creature_target_mode = "hooray"
)
for pi in self.get_students():
pi.target.look_at(self.get_teacher().eyes)
self.play(*map(MoveToTarget, self.get_students()))
self.dither()
class WhenIWasAKid(TeacherStudentsScene):
def construct(self):
children = self.get_children()
speaker = self.get_speaker()
self.prepare_everyone(children, speaker)
self.transition_from_previous_scene(children, speaker)
self.students = children
self.teacher = speaker
self.run_class()
self.grow_up()
def transition_from_previous_scene(self, children, speaker):
self.play(self.get_teacher().change_mode, "hooray", run_time = 0)
self.change_student_modes(*["happy"]*3)
speaker.look_at(children)
me = children[-1]
self.play(
FadeOut(self.get_students()),
Transform(self.get_teacher(), me)
)
self.remove(self.get_teacher())
self.add(me)
self.play(*map(FadeIn, children[:-1] + [speaker]))
self.random_blink()
def run_class(self):
children = self.students
speaker = self.teacher
title = TextMobject("Topology")
title.to_edge(UP)
self.random_blink()
self.play(self.teacher.change_mode, "speaking")
self.play(Write(title))
self.random_blink()
pi1, pi2, pi3, me = children
self.play(pi1.change_mode, "raise_right_hand")
self.random_blink()
self.play(
pi2.change_mode, "confused",
pi3.change_mode, "happy",
pi2.look_at, pi3.eyes,
pi3.look_at, pi2.eyes,
)
self.random_blink()
self.play(me.change_mode, "pondering")
self.dither()
self.random_blink(2)
self.play(pi1.change_mode, "raise_left_hand")
self.dither()
self.play(pi2.change_mode, "erm")
self.random_blink()
self.student_says(
"How is this math?",
student_index = -1,
pi_creature_target_mode = "pleading",
width = 5,
height = 3,
direction = RIGHT
)
self.play(
pi1.change_mode, "pondering",
pi2.change_mode, "pondering",
pi3.change_mode, "pondering",
)
self.play(speaker.change_mode, "pondering")
self.random_blink()
def grow_up(self):
me = self.students[-1]
self.students.remove(me)
morty = Mortimer(mode = "pondering")
morty.flip()
morty.move_to(me, aligned_edge = DOWN)
morty.to_edge(LEFT)
morty.look(RIGHT)
self.play(
Transform(me, morty),
*map(FadeOut, [
self.students, self.teacher,
me.bubble, me.bubble.content
])
)
self.remove(me)
self.add(morty)
self.play(Blink(morty))
self.dither()
self.play(morty.change_mode, "hooray")
self.dither()
def prepare_everyone(self, children, speaker):
self.everyone = list(children) + [speaker]
for pi in self.everyone:
pi.bubble = None
def get_children(self):
colors = [MAROON_E, YELLOW_D, PINK, GREY_BROWN]
children = VGroup(*[
BabyPiCreature(color = color)
for color in colors
])
children.arrange_submobjects(RIGHT)
children.to_edge(DOWN, buff = LARGE_BUFF)
children.to_edge(LEFT)
return children
def get_speaker(self):
speaker = Mathematician(mode = "happy")
speaker.flip()
speaker.to_edge(DOWN, buff = LARGE_BUFF)
speaker.to_edge(RIGHT)
return speaker
def get_everyone(self):
if hasattr(self, "everyone"):
return self.everyone
else:
return TeacherStudentsScene.get_everyone(self)
class FormingTheMobiusStrip(Scene):
def construct(self):
pass
class DrawLineOnMobiusStrip(Scene):
def construct(self):
pass
class MugIntoTorus(Scene):
def construct(self):
pass
class DefineInscribedSquareProblem(ClosedLoopScene):
def construct(self):
self.draw_loop()
self.cycle_through_shapes()
self.ask_about_rectangles()
def draw_loop(self):
self.title = TextMobject("Inscribed", "square", "problem")
self.title.to_edge(UP)
#Draw loop
self.remove(self.loop)
self.play(Write(self.title))
self.dither()
self.play(ShowCreation(
self.loop,
run_time = 3,
rate_func = None
))
self.dither()
self.add_rect_dots(square = True)
self.play(ShowCreation(self.dots, run_time = 2))
self.dither()
self.add_connecting_lines(cyclic = True)
self.play(
ShowCreation(
self.connecting_lines,
submobject_mode = "all_at_once",
run_time = 2
),
Animation(self.dots)
)
self.dither(2)
def cycle_through_shapes(self):
circle = Circle(radius = 2.5, color = WHITE)
ellipse = circle.copy()
ellipse.stretch(1.5, 0)
ellipse.stretch(0.7, 1)
ellipse.rotate(-np.pi/2)
ellipse.scale_to_fit_height(4)
pi_loop = TexMobject("\\pi")[0]
pi_loop.set_fill(opacity = 0)
pi_loop.set_stroke(
color = WHITE,
width = DEFAULT_POINT_THICKNESS
)
pi_loop.scale_to_fit_height(4)
randy = Randolph()
randy.look(DOWN)
randy.scale_to_fit_width(pi_loop.get_width())
randy.move_to(pi_loop, aligned_edge = DOWN)
randy.body.set_fill(opacity = 0)
randy.mouth.set_stroke(width = 0)
self.transform_loop(circle)
self.dither()
odd_eigths = np.linspace(1./8, 7./8, 4)
self.move_dots_to_alphas(odd_eigths)
self.dither()
for nudge in 0.1, -0.1, 0:
self.move_dots_to_alphas(odd_eigths+nudge)
self.dither()
self.transform_loop(ellipse)
self.dither()
nudge = 0.055
self.move_dots_to_alphas(
odd_eigths + [nudge, -nudge, nudge, -nudge]
)
self.dither(2)
self.transform_loop(pi_loop)
self.let_dots_wonder()
randy_anims = [
FadeIn(randy),
Animation(randy),
Blink(randy),
Animation(randy),
Blink(randy, rate_func = smooth)
]
for anim in randy_anims:
self.let_dots_wonder(
run_time = 1,
random_seed = 0,
added_anims = [anim]
)
self.remove(randy)
self.transform_loop(self.get_default_loop())
def ask_about_rectangles(self):
morty = Mortimer()
morty.next_to(ORIGIN, DOWN)
morty.to_edge(RIGHT)
new_title = TextMobject("Inscribed", "rectangle", "problem")
new_title.highlight_by_tex("rectangle", YELLOW)
new_title.to_edge(UP)
rect_dots = self.get_rect_vertex_dots()
rect_alphas = self.get_dot_alphas(rect_dots)
self.play(FadeIn(morty))
self.play(morty.change_mode, "speaking")
self.play(Transform(self.title, new_title))
self.move_dots_to_alphas(rect_alphas)
self.dither()
self.play(morty.change_mode, "hooray")
self.play(Blink(morty))
self.dither()
self.play(FadeOut(self.connecting_lines))
self.connecting_lines = VGroup()
self.play(morty.change_mode, "plain")
dot_pairs = [
VGroup(self.dots[i], self.dots[j])
for i, j in (0, 2), (1, 3)
]
pair_colors = MAROON_B, PURPLE_C
diag_lines = [
Line(d1.get_center(), d2.get_center(), color = c)
for (d1, d2), c in zip(dot_pairs, pair_colors)
]
for pair, line in zip(dot_pairs, diag_lines):
self.play(
FadeIn(line),
pair.highlight, line.get_color(),
)