mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 05:24:22 +08:00
519 lines
15 KiB
Python
519 lines
15 KiB
Python
from mobject import Mobject, Point, Mobject1D
|
|
from mobject.tex_mobject import \
|
|
TexMobject, TextMobject, Brace
|
|
from mobject.image_mobject import \
|
|
ImageMobject, MobjectFromRegion
|
|
|
|
from scene import Scene
|
|
|
|
from animation import Animation
|
|
from animation.transform import \
|
|
Transform, CounterclockwiseTransform, ApplyMethod,\
|
|
GrowFromCenter, ClockwiseTransform, ApplyPointwiseFunction, \
|
|
ShrinkToCenter
|
|
from animation.simple_animations import \
|
|
ShowCreation, ShimmerIn, FadeOut, FadeIn
|
|
from animation.meta_animations import \
|
|
DelayByOrder, TransformAnimations
|
|
from animation.playground import Vibrate
|
|
|
|
from topics.geometry import \
|
|
Line, Dot, Arrow, Grid, Square, Point
|
|
from topics.characters import \
|
|
ThoughtBubble, SpeechBubble, Mathematician
|
|
from topics.number_line import UnitInterval, NumberLine
|
|
from topics.three_dimensions import Stars
|
|
|
|
from region import region_from_polygon_vertices, Region
|
|
|
|
import displayer as disp
|
|
|
|
from hilbert.curves import \
|
|
TransformOverIncreasingOrders, FlowSnake, HilbertCurve, \
|
|
SnakeCurve, PeanoCurve
|
|
from hilbert.section1 import get_mathy_and_bubble
|
|
|
|
from scipy.spatial.distance import cdist
|
|
|
|
from helpers import *
|
|
|
|
|
|
def get_time_line():
|
|
length = 5.2*SPACE_WIDTH
|
|
year_range = 400
|
|
time_line = NumberLine(
|
|
numerical_radius = year_range/2,
|
|
unit_length_to_spatial_width = length/year_range,
|
|
tick_frequency = 10,
|
|
leftmost_tick = 1720,
|
|
number_at_center = 1870,
|
|
numbers_with_elongated_ticks = range(1700, 2100, 100)
|
|
)
|
|
time_line.sort_points(lambda p : p[0])
|
|
time_line.gradient_highlight(
|
|
PeanoCurve.DEFAULT_CONFIG["start_color"],
|
|
PeanoCurve.DEFAULT_CONFIG["end_color"]
|
|
)
|
|
time_line.add_numbers(
|
|
2020, *range(1800, 2050, 50)
|
|
)
|
|
return time_line
|
|
|
|
|
|
class SectionTwo(Scene):
|
|
def construct(self):
|
|
self.add(TextMobject("Section 2: Filling space"))
|
|
self.dither()
|
|
|
|
class HilbertCurveIsPerfect(Scene):
|
|
def construct(self):
|
|
curve = HilbertCurve(order = 6)
|
|
curve.highlight(WHITE)
|
|
colored_curve = curve.copy()
|
|
colored_curve.thin_out(3)
|
|
lion = ImageMobject("lion", invert = False)
|
|
lion.replace(curve, stretch = True)
|
|
sparce_lion = lion.copy()
|
|
sparce_lion.thin_out(100)
|
|
distance_matrix = cdist(colored_curve.points, sparce_lion.points)
|
|
closest_point_indices = np.apply_along_axis(
|
|
np.argmin, 1, distance_matrix
|
|
)
|
|
colored_curve.rgbs = sparce_lion.rgbs[closest_point_indices]
|
|
line = Line(5*LEFT, 5*RIGHT)
|
|
Mobject.align_data(line, colored_curve)
|
|
line.rgbs = colored_curve.rgbs
|
|
|
|
self.add(lion)
|
|
self.play(ShowCreation(curve, run_time = 3))
|
|
self.play(
|
|
FadeOut(lion),
|
|
Transform(curve, colored_curve),
|
|
run_time = 3
|
|
)
|
|
self.dither()
|
|
self.play(Transform(curve, line, run_time = 5))
|
|
self.dither()
|
|
|
|
|
|
class AskMathematicianFriend(Scene):
|
|
def construct(self):
|
|
mathy, bubble = get_mathy_and_bubble()
|
|
bubble.sort_points(lambda p : np.dot(p, UP+RIGHT))
|
|
|
|
self.add(mathy)
|
|
self.dither()
|
|
self.play(ApplyMethod(
|
|
mathy.blink,
|
|
rate_func = squish_rate_func(there_and_back)
|
|
))
|
|
self.dither()
|
|
self.play(ShowCreation(bubble))
|
|
self.dither()
|
|
self.play(
|
|
ApplyMethod(mathy.shift, 3*(DOWN+LEFT)),
|
|
ApplyPointwiseFunction(
|
|
lambda p : 15*p/np.linalg.norm(p),
|
|
bubble
|
|
),
|
|
run_time = 3
|
|
)
|
|
|
|
class TimeLineAboutSpaceFilling(Scene):
|
|
def construct(self):
|
|
curve = PeanoCurve(order = 5)
|
|
curve.stretch_to_fit_width(2*SPACE_WIDTH)
|
|
curve.stretch_to_fit_height(2*SPACE_HEIGHT)
|
|
curve_start = curve.copy()
|
|
curve_start.apply_over_attr_arrays(
|
|
lambda arr : arr[:200]
|
|
)
|
|
time_line = get_time_line()
|
|
time_line.shift(-time_line.number_to_point(2000))
|
|
|
|
self.add(time_line)
|
|
self.play(ApplyMethod(
|
|
time_line.shift,
|
|
-time_line.number_to_point(1900),
|
|
run_time = 3
|
|
))
|
|
brace = Brace(
|
|
Mobject(
|
|
Point(time_line.number_to_point(1865)),
|
|
Point(time_line.number_to_point(1888)),
|
|
),
|
|
UP
|
|
)
|
|
words = TextMobject("""
|
|
Cantor drives himself (and the \\\\
|
|
mathematical community at large) \\\\
|
|
crazy with research on infinity.
|
|
""")
|
|
words.next_to(brace, UP)
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
ShimmerIn(words)
|
|
)
|
|
self.dither()
|
|
self.play(
|
|
Transform(time_line, curve_start),
|
|
FadeOut(brace),
|
|
FadeOut(words)
|
|
)
|
|
self.play(ShowCreation(
|
|
curve,
|
|
run_time = 5,
|
|
rate_func = None
|
|
))
|
|
self.dither()
|
|
|
|
|
|
|
|
class NotPixelatedSpace(Scene):
|
|
def construct(self):
|
|
grid = Grid(64, 64)
|
|
space_region = Region()
|
|
space_mobject = MobjectFromRegion(space_region, DARK_GREY)
|
|
curve = PeanoCurve(order = 5).replace(space_mobject)
|
|
line = Line(5*LEFT, 5*RIGHT)
|
|
line.gradient_highlight(curve.start_color, curve.end_color)
|
|
for mob in grid, space_mobject:
|
|
mob.sort_points(np.linalg.norm)
|
|
infinitely = TextMobject("Infinitely")
|
|
detailed = TextMobject("detailed")
|
|
extending = TextMobject("extending")
|
|
detailed.next_to(infinitely, RIGHT)
|
|
extending.next_to(infinitely, RIGHT)
|
|
Mobject(extending, infinitely, detailed).center()
|
|
arrows = Mobject(*[
|
|
Arrow(2*p, 4*p)
|
|
for theta in np.arange(np.pi/6, 2*np.pi, np.pi/3)
|
|
for p in [rotate_vector(RIGHT, theta)]
|
|
])
|
|
|
|
self.add(grid)
|
|
self.dither()
|
|
self.play(Transform(grid, space_mobject, run_time = 5))
|
|
self.remove(grid)
|
|
self.highlight_region(space_region, DARK_GREY)
|
|
self.dither()
|
|
self.add(infinitely, detailed)
|
|
self.dither()
|
|
self.play(DelayByOrder(Transform(detailed, extending)))
|
|
self.play(ShowCreation(arrows))
|
|
self.dither()
|
|
self.clear()
|
|
self.highlight_region(space_region, DARK_GREY)
|
|
self.play(ShowCreation(line))
|
|
self.play(Transform(line, curve, run_time = 5))
|
|
|
|
|
|
|
|
class HistoryOfDiscover(Scene):
|
|
def construct(self):
|
|
time_line = get_time_line()
|
|
time_line.shift(-time_line.number_to_point(1900))
|
|
hilbert_curve = HilbertCurve(order = 3)
|
|
peano_curve = PeanoCurve(order = 2)
|
|
for curve in hilbert_curve, peano_curve:
|
|
curve.scale(0.5)
|
|
hilbert_curve.to_corner(DOWN+RIGHT)
|
|
peano_curve.to_corner(UP+LEFT)
|
|
squares = Mobject(*[
|
|
Square(side_length=3, color=WHITE).replace(curve)
|
|
for curve in hilbert_curve, peano_curve
|
|
])
|
|
|
|
|
|
self.add(time_line)
|
|
self.dither()
|
|
for year, curve, vect, text in [
|
|
(1890, peano_curve, UP, "Peano Curve"),
|
|
(1891, hilbert_curve, DOWN, "Hilbert Curve"),
|
|
]:
|
|
point = time_line.number_to_point(year)
|
|
point[1] = 0.2
|
|
arrow = Arrow(point+2*vect, point, buff = 0.1)
|
|
arrow.gradient_highlight(curve.start_color, curve.end_color)
|
|
year_mob = TexMobject(str(year))
|
|
year_mob.next_to(arrow, vect)
|
|
words = TextMobject(text)
|
|
words.next_to(year_mob, vect)
|
|
|
|
self.play(
|
|
ShowCreation(arrow),
|
|
ShimmerIn(year_mob),
|
|
ShimmerIn(words)
|
|
)
|
|
self.play(ShowCreation(curve))
|
|
self.dither()
|
|
self.play(ShowCreation(squares))
|
|
self.dither()
|
|
self.play(ApplyMethod(
|
|
Mobject(*self.mobjects).shift, 20*(DOWN+RIGHT)
|
|
))
|
|
|
|
|
|
|
|
class DefinitionOfCurve(Scene):
|
|
def construct(self):
|
|
start_words = TextMobject([
|
|
"``", "Space Filling", "Curve ''",
|
|
]).to_edge(TOP, buff = 0.25)
|
|
quote, space_filling, curve_quote = start_words.copy().split()
|
|
curve_quote.shift(
|
|
space_filling.get_left()-\
|
|
curve_quote.get_left()
|
|
)
|
|
space_filling = Point(space_filling.get_center())
|
|
end_words = Mobject(*[
|
|
quote, space_filling, curve_quote
|
|
]).center().to_edge(TOP, buff = 0.25)
|
|
space_filling_fractal = TextMobject("""
|
|
``Space Filling Fractal''
|
|
""").to_edge(UP)
|
|
curve = HilbertCurve(order = 2).shift(DOWN)
|
|
fine_curve = HilbertCurve(order = 8)
|
|
fine_curve.replace(curve)
|
|
dots = Mobject(*[
|
|
Dot(
|
|
curve.points[n*curve.get_num_points()/15],
|
|
color = YELLOW_C
|
|
)
|
|
for n in range(1, 15)
|
|
if n not in [4, 11]
|
|
])
|
|
|
|
start_words.shift(2*(UP+LEFT))
|
|
self.play(
|
|
ApplyMethod(start_words.shift, 2*(DOWN+RIGHT))
|
|
)
|
|
self.dither()
|
|
self.play(Transform(start_words, end_words))
|
|
self.dither()
|
|
self.play(ShowCreation(curve))
|
|
self.dither()
|
|
self.play(ShowCreation(
|
|
dots,
|
|
run_time = 3,
|
|
))
|
|
self.dither()
|
|
self.clear()
|
|
self.play(ShowCreation(fine_curve, run_time = 5))
|
|
self.dither()
|
|
self.play(ShimmerIn(space_filling_fractal))
|
|
self.dither()
|
|
|
|
|
|
class PseudoHilbertCurvesDontFillSpace(Scene):
|
|
def construct(self):
|
|
curve = HilbertCurve(order = 1)
|
|
grid = Grid(2, 2, point_thickness=1)
|
|
self.add(grid, curve)
|
|
for order in range(2, 6):
|
|
self.dither()
|
|
new_grid = Grid(2**order, 2**order, point_thickness=1)
|
|
self.play(
|
|
ShowCreation(new_grid),
|
|
Animation(curve)
|
|
)
|
|
self.remove(grid)
|
|
grid = new_grid
|
|
self.play(Transform(
|
|
curve, HilbertCurve(order = order)
|
|
))
|
|
|
|
|
|
square = Square(side_length = 6, color = WHITE)
|
|
square.corner = Mobject1D()
|
|
square.corner.add_line(3*DOWN, ORIGIN)
|
|
square.corner.add_line(ORIGIN, 3*RIGHT)
|
|
square.digest_mobject_attrs()
|
|
square.scale(2**(-5))
|
|
square.corner.highlight(
|
|
Color(rgb = curve.rgbs[curve.get_num_points()/3])
|
|
)
|
|
square.shift(
|
|
grid.get_corner(UP+LEFT)-\
|
|
square.get_corner(UP+LEFT)
|
|
)
|
|
|
|
|
|
self.dither()
|
|
self.play(
|
|
FadeOut(grid),
|
|
FadeOut(curve),
|
|
FadeIn(square)
|
|
)
|
|
self.play(
|
|
ApplyMethod(square.replace, grid)
|
|
)
|
|
self.dither()
|
|
|
|
|
|
class HilbertCurveIsLimit(Scene):
|
|
def construct(self):
|
|
mathy, bubble = get_mathy_and_bubble()
|
|
bubble.write(
|
|
"A Hilbert curve is the \\\\ limit of all these \\dots"
|
|
)
|
|
|
|
self.add(mathy, bubble)
|
|
self.play(ShimmerIn(bubble.content))
|
|
self.dither()
|
|
|
|
|
|
class DefiningCurves(Scene):
|
|
def construct(self):
|
|
words = TextMobject(
|
|
["One does not simply define the limit \\\\ \
|
|
of a sequence of","curves","\\dots"]
|
|
)
|
|
top_words = TextMobject([
|
|
"curves", "are functions"
|
|
]).to_edge(UP)
|
|
curves1 = words.split()[1]
|
|
curves2 = top_words.split()[0]
|
|
words.ingest_sub_mobjects()
|
|
number = TexMobject("0.27")
|
|
pair = TexMobject("(0.53, 0.02)")
|
|
pair.next_to(number, buff = 2)
|
|
arrow = Arrow(number, pair)
|
|
Mobject(number, arrow, pair).center().shift(UP)
|
|
number_line = UnitInterval()
|
|
number_line.stretch_to_fit_width(5)
|
|
number_line.to_edge(LEFT).shift(DOWN)
|
|
grid = Grid(4, 4).scale(0.4)
|
|
grid.next_to(number_line, buff = 2)
|
|
low_arrow = Arrow(number_line, grid)
|
|
|
|
self.play(ShimmerIn(words))
|
|
self.dither()
|
|
self.play(
|
|
FadeOut(words),
|
|
ApplyMethod(curves1.replace, curves2),
|
|
ShimmerIn(top_words.split()[1])
|
|
)
|
|
self.dither()
|
|
self.play(FadeIn(number))
|
|
self.play(ShowCreation(arrow))
|
|
self.play(FadeIn(pair))
|
|
self.dither()
|
|
self.play(ShowCreation(number_line))
|
|
self.play(ShowCreation(low_arrow))
|
|
self.play(ShowCreation(grid))
|
|
self.dither()
|
|
|
|
|
|
class PseudoHilbertCurveAsFunctionExample(Scene):
|
|
args_list = [(2,), (3,)]
|
|
|
|
# For subclasses to turn args in the above
|
|
# list into stings which can be appended to the name
|
|
@staticmethod
|
|
def args_to_string(order):
|
|
return "Order%d"%order
|
|
|
|
@staticmethod
|
|
def string_to_args(order_str):
|
|
return int(order_str)
|
|
|
|
|
|
def construct(self, order):
|
|
if order == 2:
|
|
result_tex = "(0.125, 0.75)"
|
|
elif order == 3:
|
|
result_tex = "(0.0758, 0.6875)"
|
|
|
|
phc, arg, result = TexMobject([
|
|
"\\text{PHC}_%d"%order,
|
|
"(0.3)",
|
|
"= %s"%result_tex
|
|
]).to_edge(UP).split()
|
|
function = TextMobject("Function", size = "\\normal")
|
|
function.shift(phc.get_center()+DOWN+2*LEFT)
|
|
function_arrow = Arrow(function, phc)
|
|
|
|
line = Line(5*LEFT, 5*RIGHT)
|
|
curve = HilbertCurve(order = order)
|
|
line.match_colors(curve)
|
|
grid = Grid(2**order, 2**order)
|
|
grid.fade()
|
|
for mob in curve, grid:
|
|
mob.scale(0.7)
|
|
index = int(0.3*line.get_num_points())
|
|
dot1 = Dot(line.points[index])
|
|
arrow1 = Arrow(arg, dot1, buff = 0.1)
|
|
dot2 = Dot(curve.points[index])
|
|
arrow2 = Arrow(result.get_bottom(), dot2, buff = 0.1)
|
|
|
|
self.add(phc)
|
|
self.play(
|
|
ShimmerIn(function),
|
|
ShowCreation(function_arrow)
|
|
)
|
|
self.dither()
|
|
self.remove(function_arrow, function)
|
|
self.play(ShowCreation(line))
|
|
self.dither()
|
|
self.play(
|
|
ShimmerIn(arg),
|
|
ShowCreation(arrow1),
|
|
ShowCreation(dot1)
|
|
)
|
|
self.dither()
|
|
self.remove(arrow1)
|
|
self.play(
|
|
FadeIn(grid),
|
|
Transform(line, curve),
|
|
Transform(dot1, dot2),
|
|
run_time = 2
|
|
)
|
|
self.dither()
|
|
self.play(
|
|
ShimmerIn(result),
|
|
ShowCreation(arrow2)
|
|
)
|
|
self.dither()
|
|
|
|
|
|
|
|
class ContinuityRequired(Scene):
|
|
def construct(self):
|
|
words = TextMobject([
|
|
"A function must be",
|
|
"\\emph{continuous}",
|
|
"if it is to represent a curve."
|
|
])
|
|
words.split()[1].highlight(YELLOW_C)
|
|
self.add(words)
|
|
self.dither()
|
|
|
|
|
|
|
|
|
|
class FormalDefinitionOfContinuity(Scene):
|
|
def construct(self):
|
|
self.play(ShimmerIn(TextMobject(" ".join([
|
|
"$f : A \\to B$ is continuous if: \\\\ \n\n",
|
|
"$\\forall x \\in A$,",
|
|
"$\\forall \\epsilon > 0$,",
|
|
"$\\exists \\delta > 0$ such that",
|
|
"$|f(y) - f(x)| < \\epsilon$",
|
|
"for all $y \\in A$ satisfying $|x-y|<\\delta$.",
|
|
]))))
|
|
self.dither()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|