Up to folding the unit square in wcat

This commit is contained in:
Grant Sanderson
2016-10-30 12:39:32 -07:00
parent cdde0ea0a7
commit 96d99ee40b
3 changed files with 586 additions and 6 deletions

View File

@ -157,16 +157,21 @@ class ShimmerIn(DelayByOrder):
class Rotate(ApplyMethod):
CONFIG = {
"in_place" : False,
"about_point" : None,
}
def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs):
if "path_arc" not in kwargs:
kwargs["path_arc"] = angle
digest_config(self, kwargs, locals())
target = mobject.copy()
if self.in_place:
method = mobject.rotate_in_place
else:
method = mobject.rotate
ApplyMethod.__init__(self, method, angle, axis, **kwargs)
self.about_point = mobject.get_center()
target.rotate(
angle,
axis = axis,
about_point = self.about_point,
)
Transform.__init__(self, mobject, target, **kwargs)
class ApplyPointwiseFunction(ApplyMethod):

View File

@ -123,15 +123,19 @@ class Mobject(object):
mob.points *= scale_factor
return self
def rotate(self, angle, axis = OUT, axes = []):
def rotate(self, angle, axis = OUT, axes = [], about_point = None):
if len(axes) == 0:
axes = [axis]
if about_point is not None:
self.shift(-about_point)
rot_matrix = np.identity(self.dim)
for axis in axes:
rot_matrix = np.dot(rot_matrix, rotation_matrix(angle, axis))
t_rot_matrix = np.transpose(rot_matrix)
for mob in self.family_members_with_points():
mob.points = np.dot(mob.points, t_rot_matrix)
if about_point is not None:
self.shift(about_point)
return self
def stretch(self, factor, dim):

573
wcat.py
View File

@ -1025,8 +1025,558 @@ class DeformToInterval(ClosedLoopScene):
)
self.dither()
class RepresentPairInUnitSquare(Scene):
class RepresentPairInUnitSquare(ClosedLoopScene):
def construct(self):
interval = UnitInterval(color = WHITE)
interval.shift(2.5*DOWN)
interval.shift(LEFT)
numbers = interval.get_number_mobjects(0, 1)
line = Line(interval.get_left(), interval.get_right())
line.insert_n_anchor_points(self.loop.get_num_anchor_points())
line.make_smooth()
vert_interval = interval.copy()
square = Square()
square.scale_to_fit_width(interval.get_width())
square.set_stroke(width = 0)
square.set_fill(color = BLUE, opacity = 0.3)
square.move_to(
interval.get_left(),
aligned_edge = DOWN+LEFT
)
right_words = VGroup(*[
TextMobject("Pair of\\\\ loop points"),
TexMobject("\\Downarrow"),
TextMobject("Point in \\\\ unit square")
])
right_words.arrange_submobjects(DOWN)
right_words.to_edge(RIGHT)
dot_coords = (0.3, 0.7)
self.loop.scale(0.7)
self.loop.to_edge(UP)
self.add_dots_at_alphas(*dot_coords)
self.dots.gradient_highlight(GREEN, RED)
self.play(
Write(self.dots),
Write(right_words[0])
)
self.dither()
self.transform_loop(line)
self.play(
ShowCreation(interval),
Write(numbers),
Animation(self.dots)
)
self.dither()
self.play(*[
Rotate(mob, np.pi/2, about_point = interval.get_left())
for mob in vert_interval, self.dots[1]
])
#Find interior point
point = self.dots[0].get_center()[0]*RIGHT
point += self.dots[1].get_center()[1]*UP
inner_dot = Dot(point, color = YELLOW)
dashed_lines = VGroup(*[
DashedLine(dot, inner_dot, color = dot.get_color())
for dot in self.dots
])
self.play(ShowCreation(dashed_lines))
self.play(ShowCreation(inner_dot))
self.play(
FadeIn(square),
Animation(self.dots),
*map(Write, right_words[1:])
)
self.dither()
#Shift point in square
movers = list(dashed_lines)+list(self.dots)+[inner_dot]
for mob in movers:
mob.generate_target()
shift_vals = [
RIGHT+DOWN,
LEFT+DOWN,
LEFT+2*UP,
3*DOWN,
2*RIGHT+UP,
RIGHT+UP,
3*LEFT+3*DOWN
]
for shift_val in shift_vals:
inner_dot.target.shift(shift_val)
self.dots[0].target.shift(shift_val[0]*RIGHT)
self.dots[1].target.shift(shift_val[1]*UP)
for line, dot in zip(dashed_lines, self.dots):
line.target.put_start_and_end_on(
dot.target.get_center(),
inner_dot.target.get_center()
)
self.play(*map(MoveToTarget, movers))
self.dither()
self.play(*map(FadeOut, [dashed_lines, self.dots]))
class EdgesOfSquare(Scene):
def construct(self):
square = self.add_square()
x_edges, y_edges = self.get_edges(square)
label_groups = self.get_coordinate_labels(square)
arrow_groups = self.get_arrows(x_edges, y_edges)
for edge in list(x_edges) + list(y_edges):
self.play(ShowCreation(edge))
self.dither()
for label_group in label_groups:
for label in label_group[:3]:
self.play(FadeIn(label))
self.dither()
self.play(Write(VGroup(*label_group[3:])))
self.dither()
self.play(FadeOut(VGroup(*label_groups)))
for arrows in arrow_groups:
self.play(ShowCreation(arrows, run_time = 2))
self.dither()
self.play(*[
ApplyMethod(
n.next_to,
square.get_corner(vect+LEFT),
LEFT,
MED_BUFF,
path_arc = np.pi/2
)
for n, vect in zip(self.numbers, [DOWN, UP])
])
self.dither()
def add_square(self):
interval = UnitInterval(color = WHITE)
interval.shift(2.5*DOWN)
bottom_left = interval.get_left()
for tick in interval.tick_marks:
height = tick.get_height()
tick.scale_in_place(0.5)
tick.shift(height*DOWN/4.)
self.numbers = interval.get_number_mobjects(0, 1)
vert_interval = interval.copy()
vert_interval.rotate(np.pi, axis = UP+RIGHT, about_point = bottom_left)
square = Square()
square.scale_to_fit_width(interval.get_width())
square.set_stroke(width = 0)
square.set_fill(color = BLUE, opacity = 0.3)
square.move_to(
bottom_left,
aligned_edge = DOWN+LEFT
)
self.add(interval, self.numbers, vert_interval, square)
return square
def get_edges(self, square):
y_edges = VGroup(*[
Line(
square.get_corner(vect+LEFT),
square.get_corner(vect+RIGHT),
)
for vect in DOWN, UP
])
y_edges.highlight(BLUE)
x_edges = VGroup(*[
Line(
square.get_corner(vect+DOWN),
square.get_corner(vect+UP),
)
for vect in LEFT, RIGHT
])
x_edges.highlight(MAROON_B)
return x_edges, y_edges
def get_coordinate_labels(self, square):
alpha_range = np.arange(0, 1.1, 0.1)
dot_groups = [
VGroup(*[
Dot(interpolate(
square.get_corner(DOWN+vect),
square.get_corner(UP+vect),
alpha
))
for alpha in alpha_range
])
for vect in LEFT, RIGHT
]
for group in dot_groups:
group.gradient_highlight(YELLOW, PURPLE_B)
label_groups = [
VGroup(*[
TexMobject("(%s, %s)"%(a, b)).scale(0.7)
for b in alpha_range
])
for a in 0, 1
]
for dot_group, label_group in zip(dot_groups, label_groups):
for dot, label in zip(dot_group, label_group):
label[1].highlight(MAROON_B)
label.next_to(dot, RIGHT*np.sign(dot.get_center()[0]))
label.add(dot)
return label_groups
def get_arrows(self, x_edges, y_edges):
alpha_range = np.linspace(0, 1, 4)
return [
VGroup(*[
VGroup(*[
Arrow(
edge.point_from_proportion(a1),
edge.point_from_proportion(a2),
buff = 0
)
for a1, a2 in zip(alpha_range, alpha_range[1:])
])
for edge in edges
]).highlight(edges.get_color())
for edges in x_edges, y_edges
]
class EndpointsGluedTogether(ClosedLoopScene):
def construct(self):
interval = UnitInterval(color = WHITE)
interval.shift(2*DOWN)
numbers = interval.get_number_mobjects(0, 1)
line = Line(interval.get_left(), interval.get_right())
line.insert_n_anchor_points(self.loop.get_num_anchor_points())
line.make_smooth()
self.loop.scale(0.7)
self.loop.to_edge(UP)
original_loop = self.loop
self.remove(original_loop)
self.loop = line
dots = VGroup(*[
Dot(line.get_critical_point(vect))
for vect in LEFT, RIGHT
])
dots.highlight(BLUE)
self.add(interval, dots)
self.play(dots.rotate_in_place, np.pi/20, rate_func = wiggle)
self.dither()
self.transform_loop(
original_loop,
added_anims = [
ApplyMethod(dot.move_to, original_loop.points[0])
for dot in dots
],
run_time = 3
)
self.dither()
class WrapUpToTorus(Scene):
def construct(self):
pass
class WhatAboutUnordered(TeacherStudentsScene):
def construct(self):
self.student_says(
"What about \\\\ unordered pairs?"
)
self.play(self.get_teacher().change_mode, "pondering")
self.random_blink(2)
class TrivialPairCollision(ClosedLoopScene):
def construct(self):
self.loop.to_edge(RIGHT)
self.add_dots_at_alphas(0.35, 0.55)
self.dots.gradient_highlight(BLUE, YELLOW)
a, b = self.dots
a_label = TexMobject("a").next_to(a, RIGHT)
a_label.highlight(a.get_color())
b_label = TexMobject("b").next_to(b, LEFT)
b_label.highlight(b.get_color())
line = Line(
a.get_corner(DOWN+LEFT),
b.get_corner(UP+RIGHT),
color = MAROON_B
)
midpoint = Dot(self.dots.get_center(), color = RED)
randy = Randolph(mode = "pondering")
randy.next_to(self.loop, LEFT, aligned_edge = DOWN)
randy.look_at(b)
self.add(randy)
for label in a_label, b_label:
self.play(
Write(label, run_time = 1),
randy.look_at, label
)
self.play(Blink(randy))
self.dither()
swappers = [a, b, a_label, b_label]
for mob in swappers:
mob.save_state()
self.play(
a.move_to, b,
b.move_to, a,
a_label.next_to, b, LEFT,
b_label.next_to, a, RIGHT,
randy.look_at, a,
path_arc = np.pi
)
self.play(ShowCreation(midpoint))
self.play(ShowCreation(line), Animation(midpoint))
self.play(randy.change_mode, "erm", randy.look_at, b)
self.play(
randy.look_at, a,
*[m.restore for m in swappers],
path_arc = -np.pi
)
self.play(Blink(randy))
self.dither()
class FoldUnitSquare(EdgesOfSquare):
def construct(self):
self.add_triangles()
self.add_arrows()
self.show_points_to_glue()
self.perform_fold()
self.show_singleton_pairs()
self.ask_about_gluing()
self.clarify_edge_gluing()
def add_triangles(self):
square = self.add_square()
triangles = VGroup(*[
Polygon(*[square.get_corner(vect) for vect in vects])
for vects in [
(DOWN+LEFT, UP+RIGHT, UP+LEFT),
(DOWN+LEFT, UP+RIGHT, DOWN+RIGHT),
]
])
triangles.set_stroke(width = 0)
triangles.set_fill(
color = square.get_color(),
opacity = square.get_fill_opacity()
)
self.remove(square)
self.square = square
self.add(triangles)
self.triangles = triangles
def add_arrows(self):
start_arrows = VGroup()
end_arrows = VGroup()
colors = MAROON_B, BLUE
for a in 0, 1:
for color in colors:
b_range = np.linspace(0, 1, 4)
for b1, b2 in zip(b_range, b_range[1:]):
arrow = Arrow(
self.get_point_from_coords(a, b1),
self.get_point_from_coords(a, b2),
buff = 0,
color = color
)
if color is BLUE:
arrow.rotate(
-np.pi/2,
about_point = self.square.get_center()
)
if (a is 0):
start_arrows.add(arrow)
else:
end_arrows.add(arrow)
self.add(start_arrows, end_arrows)
self.start_arrows = start_arrows
self.end_arrows = VGroup(*list(end_arrows[3:])+list(end_arrows[:3])).copy()
self.end_arrows.highlight(
color_gradient([MAROON_B, BLUE], 3)[1]
)
def show_points_to_glue(self):
colors = YELLOW, MAROON_B, PINK
pairs = [(0.2, 0.3), (0.5, 0.7), (0.25, 0.6)]
unit = self.square.get_width()
start_dots = VGroup()
end_dots = VGroup()
for (x, y), color in zip(pairs, colors):
old_x_line, old_y_line = None, None
for (a, b) in (x, y), (y, x):
point = self.get_point_from_coords(a, b)
dot = Dot(point)
dot.highlight(color)
if color == colors[-1]:
s = "(x, y)" if a < b else "(y, x)"
label = TexMobject(s)
else:
label = TexMobject("(%.01f, %.01f)"%(a, b))
vect = UP+RIGHT if a < b else DOWN+RIGHT
label.next_to(dot, vect, buff = SMALL_BUFF)
self.play(*map(FadeIn, [dot, label]))
x_line = Line(point+a*unit*LEFT, point)
y_line = Line(point+b*unit*DOWN, point)
x_line.highlight(GREEN)
y_line.highlight(RED)
if old_x_line is None:
self.play(ShowCreation(x_line), Animation(dot))
self.play(ShowCreation(y_line), Animation(dot))
old_x_line, old_y_line = y_line, x_line
else:
self.play(Transform(old_x_line, x_line), Animation(dot))
self.play(Transform(old_y_line, y_line), Animation(dot))
self.remove(old_x_line, old_y_line)
self.add(x_line, y_line, dot)
self.dither(2)
self.play(FadeOut(label))
if a < b:
start_dots.add(dot)
else:
end_dots.add(dot)
self.play(*map(FadeOut, [x_line, y_line]))
self.start_dots, self.end_dots = start_dots, end_dots
def perform_fold(self):
diag_line = DashedLine(
self.square.get_corner(DOWN+LEFT),
self.square.get_corner(UP+RIGHT),
color = RED
)
self.play(ShowCreation(diag_line))
self.dither()
self.play(
Transform(*self.triangles),
Transform(self.start_dots, self.end_dots),
Transform(self.start_arrows, self.end_arrows),
)
self.dither()
self.diag_line = diag_line
def show_singleton_pairs(self):
xs = [0.7, 0.4, 0.5]
old_label = None
old_dot = None
for x in xs:
point = self.get_point_from_coords(x, x)
dot = Dot(point)
if x is xs[-1]:
label = TexMobject("(x, x)")
else:
label = TexMobject("(%.1f, %.1f)"%(x, x))
label.next_to(dot, UP+LEFT, buff = SMALL_BUFF)
VGroup(dot, label).highlight(RED)
if old_label is None:
self.play(
ShowCreation(dot),
Write(label)
)
old_label = label
old_dot = dot
else:
self.play(
Transform(old_dot, dot),
Transform(old_label, label),
)
self.dither()
#Some strange bug necesitating this
self.remove(old_label)
self.add(label)
def ask_about_gluing(self):
keepers = VGroup(
self.triangles[0],
self.start_arrows,
self.diag_line
).copy()
faders = VGroup(*self.get_mobjects())
randy = Randolph()
randy.next_to(ORIGIN, DOWN)
bubble = randy.get_bubble(height = 4, width = 6)
bubble.write("How do you \\\\ glue those arrows?")
self.play(
FadeOut(faders),
Animation(keepers)
)
self.play(
keepers.scale, 0.6,
keepers.shift, 4*RIGHT + UP,
FadeIn(randy)
)
self.play(
randy.change_mode, "pondering",
randy.look_at, keepers,
ShowCreation(bubble),
Write(bubble.content)
)
self.play(Blink(randy))
self.dither()
self.randy = randy
def clarify_edge_gluing(self):
dots = VGroup(*[
Dot(self.get_point_from_coords(*coords), radius = 0.1)
for coords in [
(0.1, 0),
(1, 0.1),
(0.9, 0),
(1, 0.9),
]
])
dots.scale(0.6)
dots.shift(4*RIGHT + UP)
for dot in dots[:2]:
dot.highlight(YELLOW)
self.play(
ShowCreation(dot),
self.randy.look_at, dot
)
self.dither()
for dot in dots[2:]:
dot.highlight(MAROON_B)
self.play(
ShowCreation(dot),
self.randy.look_at, dot
)
self.play(Blink(self.randy))
self.dither()
def get_point_from_coords(self, x, y):
left, right, bottom, top = [
self.triangles.get_edge_center(vect)
for vect in LEFT, RIGHT, DOWN, UP
]
x_point = interpolate(left, right, x)
y_point = interpolate(bottom, top, y)
return x_point[0]*RIGHT + y_point[1]*UP
class PrepareForMobiusStrip(Scene):
def construct(self):
self.add_triangles()
self.perform_cut()
self.rearrange_pieces()
def add_triangles(self):
tri1, tri2 = triangles = VGroup(
Polygon(
DOWN+LEFT,
ORIGIN,
DOWN+RIGHT
),
Polygon(
DOWN+LEFT,
UP+LEFT,
UP+RIGHT
),
)
def perform_cut(self):
pass
def rearrange_pieces(self):
pass
@ -1039,3 +1589,24 @@ class RepresentPairInUnitSquare(Scene):