2017-01-13 17:00:47 -08:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
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 *
|
|
|
|
|
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
class Britain(SVGMobject):
|
|
|
|
CONFIG = {
|
|
|
|
"file_name" : "Britain.svg",
|
|
|
|
"stroke_width" : 1,
|
|
|
|
"stroke_color" : WHITE,
|
|
|
|
"fill_opacity" : 0,
|
|
|
|
"height" : 5,
|
|
|
|
"mark_paths_closed" : True,
|
|
|
|
}
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
SVGMobject.__init__(self, **kwargs)
|
|
|
|
self.scale_to_fit_height(self.height)
|
|
|
|
self.center()
|
|
|
|
|
|
|
|
|
2017-01-16 11:43:59 -08:00
|
|
|
class KochTest(Scene):
|
2017-01-13 17:00:47 -08:00
|
|
|
def construct(self):
|
2017-01-16 11:43:59 -08:00
|
|
|
koch = KochCurve(order = 5, stroke_width = 2)
|
|
|
|
|
|
|
|
self.play(ShowCreation(koch, run_time = 3))
|
|
|
|
self.play(
|
|
|
|
koch.scale, 3, koch.get_left(),
|
|
|
|
koch.set_stroke, None, 4
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
class SierpinskiTest(Scene):
|
|
|
|
def construct(self):
|
|
|
|
sierp = Sierpinski(
|
|
|
|
order = 5,
|
|
|
|
)
|
|
|
|
|
|
|
|
self.play(FadeIn(
|
|
|
|
sierp,
|
|
|
|
run_time = 5,
|
|
|
|
submobject_mode = "lagged_start",
|
|
|
|
))
|
|
|
|
self.dither()
|
|
|
|
# self.play(sierp.scale, 2, sierp.get_top())
|
|
|
|
# self.dither(3)
|
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
class FractalCreation(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"fractal_class" : PentagonalFractal,
|
|
|
|
"max_order" : 6,
|
|
|
|
"path_arc" : np.pi/6,
|
|
|
|
"submobject_mode" : "lagged_start"
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
fractal = self.fractal_class(order = 0)
|
|
|
|
self.play(FadeIn(fractal))
|
|
|
|
for order in range(1, self.max_order+1):
|
|
|
|
new_fractal = self.fractal_class(order = order)
|
|
|
|
self.play(Transform(
|
|
|
|
fractal, new_fractal,
|
|
|
|
path_arc = self.path_arc,
|
|
|
|
submobject_mode = self.submobject_mode,
|
|
|
|
run_time = 2
|
|
|
|
))
|
|
|
|
self.dither()
|
|
|
|
self.dither()
|
|
|
|
|
2017-01-16 11:43:59 -08:00
|
|
|
###################################
|
|
|
|
|
|
|
|
|
|
|
|
class ZoomInOnFractal(PiCreatureScene):
|
|
|
|
CONFIG = {
|
|
|
|
"fractal_order" : 6,
|
2017-01-16 13:26:46 -08:00
|
|
|
"num_zooms" : 5,
|
|
|
|
"fractal_class" : DiamondFractal,
|
2017-01-16 11:43:59 -08:00
|
|
|
"index_to_replace" : 0,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
morty = self.pi_creature
|
|
|
|
|
2017-01-16 13:26:46 -08:00
|
|
|
fractal = self.fractal_class(order = self.fractal_order)
|
2017-01-16 11:43:59 -08:00
|
|
|
fractal.show()
|
2017-01-16 13:26:46 -08:00
|
|
|
|
|
|
|
fractal = self.introduce_fractal()
|
|
|
|
self.change_mode("thinking")
|
|
|
|
self.blink()
|
|
|
|
self.zoom_in(fractal)
|
|
|
|
|
|
|
|
|
|
|
|
def introduce_fractal(self):
|
|
|
|
fractal = self.fractal_class(order = 0)
|
|
|
|
self.play(FadeIn(fractal))
|
|
|
|
for order in range(1, self.fractal_order+1):
|
|
|
|
new_fractal = self.fractal_class(order = order)
|
|
|
|
self.play(
|
|
|
|
Transform(fractal, new_fractal, run_time = 2),
|
|
|
|
self.pi_creature.change_mode, "hooray"
|
|
|
|
)
|
|
|
|
return fractal
|
|
|
|
|
|
|
|
def zoom_in(self, fractal):
|
|
|
|
grower = fractal[self.index_to_replace]
|
|
|
|
grower_target = fractal.copy()
|
|
|
|
|
|
|
|
for x in range(self.num_zooms):
|
|
|
|
self.tweak_fractal_subpart(grower_target)
|
|
|
|
grower_family = grower.family_members_with_points()
|
|
|
|
everything = VGroup(*[
|
|
|
|
submob
|
|
|
|
for submob in fractal.family_members_with_points()
|
|
|
|
if not submob.is_off_screen()
|
|
|
|
if submob not in grower_family
|
|
|
|
])
|
|
|
|
everything.generate_target()
|
|
|
|
everything.target.shift(
|
|
|
|
grower_target.get_center()-grower.get_center()
|
|
|
|
)
|
|
|
|
everything.target.scale(
|
|
|
|
grower_target.get_height()/grower.get_height()
|
|
|
|
)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
Transform(grower, grower_target),
|
|
|
|
MoveToTarget(everything),
|
|
|
|
self.pi_creature.change_mode, "thinking",
|
|
|
|
run_time = 2
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
grower_target = grower.copy()
|
|
|
|
grower = grower[self.index_to_replace]
|
|
|
|
|
|
|
|
|
|
|
|
def tweak_fractal_subpart(self, subpart):
|
|
|
|
subpart.rotate_in_place(np.pi/4)
|
|
|
|
|
|
|
|
class WhatAreFractals(TeacherStudentsScene):
|
|
|
|
def construct(self):
|
|
|
|
self.student_says(
|
2017-01-17 17:14:32 -08:00
|
|
|
"But what \\emph{is} a fractal?",
|
2017-01-16 13:26:46 -08:00
|
|
|
student_index = 2,
|
|
|
|
width = 6
|
2017-01-16 11:43:59 -08:00
|
|
|
)
|
2017-01-16 13:26:46 -08:00
|
|
|
self.change_student_modes("thinking", "pondering", None)
|
2017-01-16 11:43:59 -08:00
|
|
|
self.dither()
|
2017-01-16 13:26:46 -08:00
|
|
|
|
|
|
|
name = TextMobject("Benoit Mandelbrot")
|
|
|
|
name.to_corner(UP+LEFT)
|
|
|
|
# picture = Rectangle(height = 4, width = 3)
|
|
|
|
picture = ImageMobject("Mandelbrot")
|
|
|
|
picture.scale_to_fit_height(4)
|
|
|
|
picture.next_to(name, DOWN)
|
2017-01-16 11:43:59 -08:00
|
|
|
self.play(
|
2017-01-16 13:26:46 -08:00
|
|
|
Write(name, run_time = 2),
|
|
|
|
FadeIn(picture),
|
|
|
|
*[
|
|
|
|
ApplyMethod(pi.look_at, name)
|
|
|
|
for pi in self.get_everyone()
|
|
|
|
]
|
2017-01-16 11:43:59 -08:00
|
|
|
)
|
2017-01-16 13:26:46 -08:00
|
|
|
self.dither(2)
|
|
|
|
question = TextMobject("Aren't they", "self-similar", "shapes?")
|
|
|
|
question.highlight_by_tex("self-similar", YELLOW)
|
|
|
|
self.student_says(question)
|
|
|
|
self.play(self.get_teacher().change_mode, "happy")
|
|
|
|
self.dither(2)
|
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
class IntroduceVonKochCurve(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"order" : 5,
|
|
|
|
"stroke_width" : 3,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
snowflake = self.get_snowflake()
|
|
|
|
name = TextMobject("Von Koch Snowflake")
|
|
|
|
name.to_edge(UP)
|
2017-01-16 13:26:46 -08:00
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
self.play(ShowCreation(snowflake, run_time = 3))
|
|
|
|
self.play(Write(name, run_time = 2))
|
|
|
|
curve = self.isolate_one_curve(snowflake)
|
|
|
|
self.dither()
|
|
|
|
self.zoom_in_on(curve)
|
|
|
|
|
|
|
|
def get_snowflake(self):
|
|
|
|
triangle = RegularPolygon(n = 3, start_angle = np.pi/2)
|
|
|
|
triangle.scale_to_fit_height(4)
|
|
|
|
curves = VGroup(*[
|
|
|
|
KochCurve(
|
|
|
|
order = self.order,
|
|
|
|
stroke_width = self.stroke_width
|
|
|
|
)
|
|
|
|
for x in range(3)
|
|
|
|
])
|
|
|
|
for index, curve in enumerate(curves):
|
|
|
|
width = curve.get_width()
|
|
|
|
curve.move_to(
|
|
|
|
(np.sqrt(3)/6)*width*UP, DOWN
|
|
|
|
)
|
|
|
|
curve.rotate(-index*2*np.pi/3)
|
|
|
|
curves.gradient_highlight(BLUE, WHITE, BLUE)
|
2017-01-16 13:26:46 -08:00
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
return curves
|
2017-01-16 13:26:46 -08:00
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
def isolate_one_curve(self, snowflake):
|
|
|
|
self.play(*[
|
|
|
|
ApplyMethod(curve.shift, curve.get_center()/2)
|
|
|
|
for curve in snowflake
|
|
|
|
])
|
|
|
|
self.dither()
|
|
|
|
self.play(
|
|
|
|
snowflake.scale, 2.1,
|
|
|
|
snowflake.next_to, UP, DOWN
|
|
|
|
)
|
|
|
|
self.remove(*snowflake[1:])
|
|
|
|
return snowflake[0]
|
|
|
|
|
|
|
|
def zoom_in_on(self, curve):
|
|
|
|
larger_curve = KochCurve(order = self.order+1)
|
|
|
|
larger_curve.replace(curve)
|
|
|
|
larger_curve.scale(3, about_point = curve.get_corner(DOWN+LEFT))
|
|
|
|
larger_curve.gradient_highlight(
|
|
|
|
curve[0].get_color(),
|
|
|
|
curve[-1].get_color(),
|
|
|
|
)
|
2017-01-16 13:26:46 -08:00
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
self.play(Transform(curve, larger_curve, run_time = 2))
|
|
|
|
n_parts = len(curve.split())
|
|
|
|
sub_portion = VGroup(*curve[:n_parts/4])
|
|
|
|
self.play(
|
|
|
|
sub_portion.highlight, YELLOW,
|
|
|
|
rate_func = there_and_back
|
|
|
|
)
|
|
|
|
self.dither()
|
2017-01-16 11:43:59 -08:00
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
class IntroduceSierpinskiTriangle(PiCreatureScene):
|
|
|
|
CONFIG = {
|
|
|
|
"order" : 7,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
sierp = Sierpinski(order = self.order)
|
|
|
|
sierp.save_state()
|
2017-01-16 11:43:59 -08:00
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
self.play(FadeIn(
|
|
|
|
sierp,
|
|
|
|
run_time = 2,
|
|
|
|
submobject_mode = "lagged_start"
|
|
|
|
))
|
|
|
|
self.dither()
|
|
|
|
self.play(
|
|
|
|
self.pi_creature.change_mode, "pondering",
|
|
|
|
*[
|
|
|
|
ApplyMethod(submob.shift, submob.get_center())
|
|
|
|
for submob in sierp
|
|
|
|
]
|
|
|
|
)
|
|
|
|
self.dither()
|
|
|
|
for submob in sierp:
|
|
|
|
self.play(sierp.shift, -submob.get_center())
|
|
|
|
self.dither()
|
|
|
|
self.play(sierp.restore)
|
|
|
|
self.change_mode("happy")
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
class SelfSimilarFractalsAsSubset(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"fractal_width" : 1.5
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
self.add_self_similar_fractals()
|
|
|
|
self.add_general_fractals()
|
|
|
|
|
|
|
|
def add_self_similar_fractals(self):
|
|
|
|
fractals = VGroup(
|
|
|
|
DiamondFractal(order = 5),
|
|
|
|
KochSnowFlake(order = 3),
|
|
|
|
Sierpinski(order = 5),
|
|
|
|
)
|
|
|
|
for submob in fractals:
|
|
|
|
submob.scale_to_fit_width(self.fractal_width)
|
|
|
|
fractals.arrange_submobjects(RIGHT)
|
|
|
|
fractals[-1].next_to(VGroup(*fractals[:-1]), DOWN)
|
|
|
|
|
|
|
|
title = TextMobject("Self-similar fractals")
|
|
|
|
title.next_to(fractals, UP)
|
|
|
|
|
|
|
|
small_rect = Rectangle()
|
|
|
|
small_rect.replace(VGroup(fractals, title), stretch = True)
|
|
|
|
small_rect.scale_in_place(1.2)
|
|
|
|
self.small_rect = small_rect
|
|
|
|
|
|
|
|
group = VGroup(fractals, title, small_rect)
|
|
|
|
group.to_corner(UP+LEFT, buff = 2*MED_BUFF)
|
2017-01-16 11:43:59 -08:00
|
|
|
|
2017-01-17 17:14:32 -08:00
|
|
|
self.play(
|
|
|
|
Write(title),
|
|
|
|
ShowCreation(fractals),
|
|
|
|
run_time = 3
|
|
|
|
)
|
|
|
|
self.play(ShowCreation(small_rect))
|
|
|
|
self.dither()
|
|
|
|
|
|
|
|
def add_general_fractals(self):
|
|
|
|
big_rectangle = Rectangle(
|
|
|
|
width = 2*SPACE_WIDTH - 2*MED_BUFF,
|
|
|
|
height = 2*SPACE_HEIGHT - 2*MED_BUFF,
|
|
|
|
)
|
|
|
|
title = TextMobject("Fractals")
|
|
|
|
title.scale(1.5)
|
|
|
|
title.next_to(ORIGIN, RIGHT, buff = LARGE_BUFF)
|
|
|
|
title.to_edge(UP, buff = 2*MED_BUFF)
|
|
|
|
|
|
|
|
britain = Britain()
|
|
|
|
britain.next_to(self.small_rect, RIGHT)
|
|
|
|
britain.shift(2*DOWN)
|
|
|
|
|
|
|
|
randy = Randolph().flip().scale(1.4)
|
|
|
|
randy.next_to(britain, buff = SMALL_BUFF)
|
|
|
|
randy.generate_target()
|
|
|
|
randy.target.change_mode("pleading")
|
|
|
|
fractalify(randy.target, order = 2)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(big_rectangle),
|
|
|
|
Write(title),
|
|
|
|
)
|
|
|
|
self.play(ShowCreation(britain), run_time = 5)
|
|
|
|
self.play(
|
|
|
|
britain.set_stroke, BLACK, 0,
|
|
|
|
britain.set_fill, BLUE, 1,
|
|
|
|
)
|
|
|
|
self.play(FadeIn(randy))
|
|
|
|
self.play(MoveToTarget(randy, run_time = 2))
|
|
|
|
self.dither(2)
|
|
|
|
|
|
|
|
class ConstrastSmoothAndFractal(Scene):
|
|
|
|
def construct(self):
|
|
|
|
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
|
|
|
smooth = TextMobject("Smooth")
|
|
|
|
smooth.shift(SPACE_WIDTH*LEFT/2)
|
|
|
|
fractal = TextMobject("Fractal")
|
|
|
|
fractal.shift(SPACE_WIDTH*RIGHT/2)
|
|
|
|
VGroup(smooth, fractal).to_edge(UP)
|
|
|
|
self.add(v_line, smooth, fractal)
|
|
|
|
|
|
|
|
britain = Britain()
|
|
|
|
anchors = britain.get_anchors()
|
|
|
|
smooth_britain =
|
2017-01-16 11:43:59 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|