Final inscribed rectangle animations

This commit is contained in:
Grant Sanderson 2024-12-26 09:53:52 -07:00
parent 8f54648b19
commit 00edbe600b
3 changed files with 254 additions and 18 deletions

View file

@ -96,7 +96,7 @@ class StateThePuzzle(LoopScene):
loop = get_example_loop(4)
loop.set_height(7)
loop.move_to(2 * RIGHT)
curve_words = Text("Closed\nContinus\nCurve", alignment="LEFT", font_size=72)
curve_words = Text("Closed\nContinuous\nCurve", alignment="LEFT", font_size=72)
curve_words.to_edge(LEFT)
self.play(
@ -162,14 +162,17 @@ class StateThePuzzle(LoopScene):
self.wait()
# Ambiently animate to various different loops
def true_find_square(loop_func, trg_angle=90 * DEG, cost_tol=1e-2, max_tries=10):
def true_find_square(loop_func, trg_angle=90 * DEG, cost_tol=1e-2, max_tries=8):
ic = np.arange(0, 1, 0.25)
min_params = ic
min_cost = np.inf
for x in range(max_tries):
params, cost = find_rectangle(loop_func, target_angle=trg_angle, n_refinements=3, return_cost=True)
if cost < cost_tol:
break
if cost < min_cost:
min_params = params
min_cost = cost
ic = np.random.random(4)
return params
return min_params
new_loops = [
get_example_loop(1),
@ -188,15 +191,19 @@ class StateThePuzzle(LoopScene):
dots.resume_updating()
self.add(dots, polygon)
for new_loop in new_loops:
self.remove(dots, polygon)
self.play(
Transform(loop, new_loop),
UpdateFromFunc(
quad_tracker,
lambda m: m.set_value(true_find_square(loop_func))
),
run_time=5
# UpdateFromFunc(
# quad_tracker,
# lambda m: m.set_value(true_find_square(loop_func))
# ),
run_time=1
)
self.wait()
self.add(dots, polygon)
for _ in range(5):
quad_tracker.set_value(find_rectangle(loop_func, np.random.random(4), target_angle=90 * DEG))
self.wait(0.5)
# Change question to rectangle
square_word = question["square"]
@ -427,17 +434,18 @@ class ShowTheSurface(LoopScene):
# Pair of points
uv_tracker = ValueTracker([0, 0.5])
dots = self.get_movable_pair(uv_tracker, loop_func, radius=0.05)
dots = self.get_movable_pair(uv_tracker, loop_func, radius=0.075)
connecting_line = self.get_connecting_line(dots)
midpoint_dot = self.get_midpoint_dot(dots)
self.add(uv_tracker)
self.add(dots)
self.add(connecting_line)
self.play(
UpdateFromFunc(uv_tracker, lambda m: m.set_value(np.random.random(2))),
)
self.add(dots)
self.add(dots, connecting_line)
self.play(uv_tracker.animate.set_value([0.8, 0.5]), run_time=3)
# Add coordinates
@ -2033,6 +2041,63 @@ class MapTheStripOntoTheSurface(ShowTheSurface):
)
class AmbientRectangleSearch(ShowTheSurface):
def construct(self):
# Setup loop
frame = self.frame
axes, plane = self.get_axes_and_plane()
self.add(plane)
loop = get_example_loop(2)
loop.insert_n_curves(50)
loop.set_height(5)
loop.set_stroke(WHITE, 3)
loop.set_fill(opacity=0)
loop_func = get_quick_loop_func(loop)
self.add(loop)
# Dots
abcd_tracker = ValueTracker(np.random.random(4))
dots = self.get_movable_quad(abcd_tracker, loop_func, radius=0.1)
polygon = self.get_dot_polygon(dots)
polygon.set_stroke(YELLOW, 2)
self.add(dots, polygon)
# Various rectangles
for _ in range(20):
rect_params = find_rectangle(
loop_func,
initial_condition=np.random.random(4),
target_angle=np.random.uniform(0, 90 * DEG),
)
self.play(abcd_tracker.animate.set_value(rect_params), run_time=2)
self.wait()
class GenericLoopPair(ShowTheSurface):
def construct(self):
loop = Circle(radius=2.5)
loop.set_stroke(WHITE, 3)
loop.set_fill(opacity=0)
loop_func = get_quick_loop_func(loop)
self.add(loop)
uv_tracker = ValueTracker([0, 0.5])
# self.set_uv_tracker_in_motion(uv_tracker, velocity=(0.1 * PI / 2, -0.1))
dots = self.get_movable_pair(uv_tracker, loop_func, radius=0.075, colors=[YELLOW, YELLOW])
connecting_line = self.get_connecting_line(dots)
connecting_line.set_stroke(YELLOW)
pair_group = Group(dots, connecting_line)
self.add(uv_tracker, pair_group)
# Wait
for _ in range(20):
self.play(uv_tracker.animate.set_value(np.random.random(2)), run_time=2)
self.wait(0.5)
class SudaneseBand(InteractiveScene):
def construct(self):
# Tranform mobius to Sudanese
@ -2044,7 +2109,10 @@ class SudaneseBand(InteractiveScene):
sudanese_band.set_height(6)
frame.reorient(28, 75, 0, ORIGIN, 8)
self.add(strip)
# self.add(strip)
self.add(sudanese_band)
frame.add_ambient_rotation(6 * DEG)
self.wait(60)
self.play(frame.animate.increment_theta(180 * DEG), run_time=12)
self.play(
frame.animate.reorient(99, 102, 0),
@ -2448,7 +2516,6 @@ class PuzzleOverMobiusDiagram(ConstructKleinBottle):
)
class ShowAngleInformation(ShowTheSurface):
def construct(self):
# Setup (fairly heavily copied from above)

View file

@ -167,6 +167,28 @@ class WhatIsTopology(InteractiveScene):
self.wait()
class ThreeShapes(InteractiveScene):
def construct(self):
# Test
v_lines = Line(DOWN, UP).replicate(2)
v_lines.set_height(FRAME_HEIGHT)
v_lines.arrange(RIGHT, buff=FRAME_WIDTH / 3)
v_lines.set_stroke(WHITE, 3)
titles = VGroup(
Text("Möbius Strip"),
Text("Torus"),
Text("Klein Bottle"),
)
for title, x in zip(titles, [-1, 0, 1]):
title.scale(60 / 48)
title.set_x(x * FRAME_WIDTH / 3)
title.to_edge(UP)
self.add(v_lines)
self.add(titles)
class ThisIsTheSame(InteractiveScene):
def construct(self):
# Test
@ -264,6 +286,36 @@ class AskAboutProvingCollision(InteractiveScene):
self.wait()
class GraphOfBellCurve(InteractiveScene):
def construct(self):
# Test
axes = ThreeDAxes((-3, 3), (-3, 3), (0, 1))
axes.set_depth(2, stretch=True)
surface = axes.get_graph(lambda x, y: np.exp(-x**2 - y**2))
surface.set_opacity(0.7)
surface.always_sort_to_camera(self.camera)
mesh = SurfaceMesh(surface, resolution=(21, 21))
mesh.set_stroke(WHITE, 0.5, 0.5)
self.frame.reorient(42, 67, 0, (0.42, 0.43, 0.1), 6.03)
self.frame.add_ambient_rotation(3 * DEG)
self.add(axes)
self.add(surface, mesh)
self.wait(30)
class GraphLabel(InteractiveScene):
def construct(self):
group = VGroup(
Text("Graph of"),
Tex(R"f(x, y) = e^{-x^2 - y^2}"),
)
group.arrange(DOWN)
group.to_edge(UP)
self.play(Write(group))
self.wait()
class ChekhovsGun(InteractiveScene):
def construct(self):
# Add image
@ -519,7 +571,7 @@ class AskAboutUnsolved(InteractiveScene):
def construct(self):
randy = Randolph()
randy.to_corner(DL)
self.play(randy.says("What about the\nunsolvd problem?", "maybe"))
self.play(randy.says("What about the\nunsolved problem?", "maybe"))
self.play(Blink(randy))
self.wait(2)
@ -602,7 +654,7 @@ class GreeneLobbTheorem(InteractiveScene):
Theorem by Greene and Lobb (2020):
Every smooth closed curve contains
inscribed rectangles of all possible
aspect ratio.
aspect ratios.
""", t2s={"smooth": ITALIC}, alignment="LEFT")
text.to_corner(UL)
@ -640,3 +692,121 @@ class SmoothImplication(InteractiveScene):
FadeIn(tangent, 0.5 * DOWN),
)
self.wait()
class ProblemSolvingToRecreation(InteractiveScene):
def construct(self):
# Test
words = VGroup(
Text("Solving\nproblems"),
Text("Helpful\nconstructs"),
Text("Recreational\nmath"),
)
words.arrange(RIGHT, buff=2.5)
words.set_y(-1.5)
mind_bending = Text("(Sometimes Mind-bending)", font_size=24)
mind_bending.next_to(words[1], DOWN)
arrows = VGroup(
Arrow(w1, w2, thickness=4, buff=0.45)
for w1, w2 in zip(words, words[1:])
)
arrows.space_out_submobjects(1.1)
self.play(FadeIn(words[0], lag_ratio=0.1))
self.wait()
self.play(
FadeIn(words[1], lag_ratio=0.1),
GrowArrow(arrows[0]),
)
self.wait()
self.play(FadeIn(mind_bending, 0.25 * DOWN))
self.wait()
# Move mind-bending
mb = mind_bending["Mind-bending"]
helpful = words[1]["Helpful"]
self.play(
mb.animate.scale(2).move_to(helpful),
FadeOut(helpful, 0.25 * UP),
FadeOut(mind_bending["(Sometimes"][0]),
FadeOut(mind_bending[")"][0]),
)
self.play(
FadeIn(words[2], lag_ratio=0.1),
GrowArrow(arrows[1]),
)
self.wait()
self.play(
words[0].animate.set_opacity(0.1),
arrows[0].animate.set_opacity(0.1),
)
self.wait()
class WriteTopologicalSpace(InteractiveScene):
def construct(self):
# Test
text = Text("Topological Space", font_size=72)
text.to_edge(UP)
self.play(Write(text))
self.wait()
class AskAboutTopology(TeacherStudentsScene):
def construct(self):
morty = self.teacher
stds = self.students
self.play(
stds[0].says("What is a\ntopological space?", "raise_left_hand"),
stds[1].change("pondering", stds[0].eyes),
stds[2].change("pondering", stds[0].eyes),
morty.change("tease"),
)
self.wait(2)
self.play(
stds[1].animate.look_at(stds[2].eyes),
stds[2].says("What is\ntopology?", "maybe", look_at=morty.eyes, bubble_direction=LEFT)
)
self.wait()
self.play(morty.change("guilty"))
self.play(stds[0].change('confused'))
self.play(morty.change("hesitant"))
self.wait(4)
class PlaylistMention(InteractiveScene):
def construct(self):
# Test
rects = ScreenRectangle().replicate(8)
rects.set_fill(GREY_E, 1)
rects.set_stroke(WHITE, 1)
group = Group()
for x, rect in zip(np.linspace(1, 0, len(rects)), rects):
rect.shift(x * 0.75 * UR)
group.add(rect)
group.add(Point())
thumbnail = ImageMobject("https://img.youtube.com/vi/OkmNXy7er84/maxresdefault.jpg")
thumbnail.replace(rects[-1])
group.add(thumbnail)
group.set_height(2)
group.to_edge(UP, buff=1.0)
words = Text("More neat proofs\nand puzzle solutions")
words.next_to(group, DOWN, buff=2.5)
arrow = Arrow(words, group)
self.play(
FadeIn(group, UP),
Write(words),
GrowArrow(arrow)
)
self.wait()
self.play(FadeOut(words), FadeOut(arrow))
class EndScreen(PatreonEndScreen):
title_text = ""

View file

@ -53,7 +53,6 @@ def get_full_surface(band_func, x_range):
bound.apply_depth_test()
meshes.set_stroke(WHITE, 0.5, 0.5)
return Group(surface, m1, m2, bound)
return Group(surface, bound)
def get_sudanese_band(circle_on_xy_plane=False):