Beginning fractal dimension project

This commit is contained in:
Grant Sanderson 2017-01-16 11:43:59 -08:00
parent 1454216006
commit 209264e90c
5 changed files with 208 additions and 21 deletions

View file

@ -25,6 +25,118 @@ from mobject.svg_mobject import *
from mobject.tex_mobject import * from mobject.tex_mobject import *
class Test(Scene): class KochTest(Scene):
def construct(self): def construct(self):
pass 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)
###################################
class ZoomInOnFractal(PiCreatureScene):
CONFIG = {
"fractal_order" : 6,
"num_zooms" : 4,
"fractal_class" : Sierpinski,
"index_to_replace" : 0,
}
def construct(self):
morty = self.pi_creature
fractal = self.get_zoomable_fractal()
fractal.show()
self.play(
ShowCreation(
fractal,
run_time = 4,
rate_func = rush_from
),
morty.change_mode, "hooray",
)
self.dither()
self.play(
ApplyMethod(
fractal.scale, 2**self.num_zooms,
self.zoom_in_about_point,
run_time = 8
),
morty.change_mode, "thinking",
morty.look_at, fractal.get_corner(self.zoom_in_about_point),
)
self.play(Blink(morty))
self.dither()
def get_zoomable_fractal(self):
fractal = self.fractal_class(order = self.fractal_order)
to_be_tweaked = fractal
for x in range(self.num_zooms):
new_corner = self.fractal_class(order = self.fractal_order)
new_corner.replace(to_be_tweaked[self.index_to_replace])
self.tweak_subpart(new_corner)
to_be_tweaked.submobjects[self.index_to_replace] = new_corner
to_be_tweaked = new_corner
self.zoom_in_about_point = to_be_tweaked.get_center()
return fractal
def tweak_subpart(self, subpart):
pass
class ZoomInOnDiamondFractal(ZoomInOnFractal):
CONFIG = {
"fractal_order" : 5,
"fractal_class" : DiamondFractal,
}
def construct(self):
high_res_fractal = self.fractal_class(order = self.fractal_order)
low_res_fractal = self.fractal_class(order = self.fractal_order-1)
high_res_fractal.scale(3, high_res_fractal.get_top())
self.add(low_res_fractal)
self.dither()
self.play(Transform(low_res_fractal, high_res_fractal))
self.dither(3)

View file

@ -17,9 +17,6 @@ class VMobject(Mobject):
"considered_smooth" : True, "considered_smooth" : True,
"propogate_style_to_family" : False, "propogate_style_to_family" : False,
} }
def __init__(self, *args, **kwargs):
Mobject.__init__(self, *args, **kwargs)
VMobject.init_colors(self)
## Colors ## Colors
def init_colors(self): def init_colors(self):

View file

@ -29,7 +29,9 @@ class PiCreature(SVGMobject):
CONFIG = { CONFIG = {
"color" : BLUE_E, "color" : BLUE_E,
"stroke_width" : 0, "stroke_width" : 0,
"stroke_color" : BLACK,
"fill_opacity" : 1.0, "fill_opacity" : 1.0,
"propogate_style_to_family" : True,
"initial_scale_factor" : 0.01, "initial_scale_factor" : 0.01,
"corner_scale_factor" : 0.75, "corner_scale_factor" : 0.75,
"flip_at_start" : False, "flip_at_start" : False,
@ -44,7 +46,6 @@ class PiCreature(SVGMobject):
) )
digest_config(self, kwargs, locals()) digest_config(self, kwargs, locals())
SVGMobject.__init__(self, file_name = svg_file, **kwargs) SVGMobject.__init__(self, file_name = svg_file, **kwargs)
self.init_colors()
if self.flip_at_start: if self.flip_at_start:
self.flip() self.flip()
if self.start_corner is not None: if self.start_corner is not None:
@ -66,7 +67,7 @@ class PiCreature(SVGMobject):
self.parts_named = True self.parts_named = True
def init_colors(self): def init_colors(self):
self.set_stroke(color = BLACK, width = self.stroke_width) SVGMobject.init_colors(self)
if not self.parts_named: if not self.parts_named:
self.name_parts() self.name_parts()
self.mouth.set_fill(BLACK, opacity = 1) self.mouth.set_fill(BLACK, opacity = 1)

View file

@ -3,7 +3,7 @@ from mobject.vectorized_mobject import VMobject, VGroup, VectorizedPoint
from scene import Scene from scene import Scene
from animation.transform import Transform from animation.transform import Transform
from animation.simple_animations import ShowCreation from animation.simple_animations import ShowCreation
from topics.geometry import Line from topics.geometry import Line, Polygon, RegularPolygon
from helpers import * from helpers import *
@ -15,19 +15,92 @@ def rotate(points, angle = np.pi, axis = OUT):
return points return points
class SelfSimilarFractal(VMobject):
CONFIG = {
"order" : 5,
"num_subparts" : 3,
"height" : 4,
"colors" : [RED, WHITE],
"stroke_width" : 1,
"fill_opacity" : 1,
"propogate_style_to_family" : True,
}
def init_colors(self):
VMobject.init_colors(self)
self.gradient_highlight(*self.colors)
def generate_points(self):
self.submobjects = self.get_order_n_self(self.order).submobjects
def get_order_n_self(self, order):
if order == 0:
result = self.get_seed_shape()
else:
subparts = [
self.get_order_n_self(order - 1)
for x in range(self.num_subparts)
]
self.arrange_subparts(*subparts)
result = VGroup(*subparts)
result.scale_to_fit_height(self.height)
result.center()
return result
def get_seed_shape(self):
raise Exception("Not implemented")
def arrange_subparts(self, *subparts):
raise Exception("Not implemented")
class Sierpinski(SelfSimilarFractal):
def get_seed_shape(self):
return Polygon(
RIGHT, np.sqrt(3)*UP, LEFT,
)
def arrange_subparts(self, *subparts):
tri1, tri2, tri3 = subparts
tri1.move_to(tri2.get_corner(DOWN+LEFT), UP)
tri3.move_to(tri2.get_corner(DOWN+RIGHT), UP)
class DiamondFractal(SelfSimilarFractal):
CONFIG = {
"num_subparts" : 4,
"height" : 6,
}
def get_seed_shape(self):
return RegularPolygon(n = 4)
def arrange_subparts(self, *subparts):
# VGroup(*subparts).rotate(np.pi/4)
for part, vect in zip(subparts, compass_directions(start_vect = UP+RIGHT)):
part.next_to(ORIGIN, vect, buff = 0)
VGroup(*subparts).rotate(np.pi/4)
######## Space filling curves ############
class SpaceFillingCurve(VMobject): class SpaceFillingCurve(VMobject):
CONFIG = { CONFIG = {
"radius" : 3, "radius" : 3,
"order" : 5, "order" : 5,
"colors" : [RED, GREEN], "colors" : [RED, GREEN],
"monochromatic" : False,
"stroke_width" : 2,
} }
def generate_points(self): def generate_points(self):
points = self.get_anchor_points() points = self.get_anchor_points()
for triplet in zip(points, points[1:], points[2:]): if self.monochromatic:
corner = VMobject() self.set_points_as_corners(points)
corner.set_points_as_corners(triplet) else:
self.add(corner) for triplet in zip(points, points[1:], points[2:]):
corner = VMobject()
corner.set_points_as_corners(triplet)
self.add(corner)
self.gradient_highlight(*self.colors) self.gradient_highlight(*self.colors)
def get_anchor_points(self): def get_anchor_points(self):
@ -244,11 +317,10 @@ class FlowSnake(LindenmayerCurve):
LindenmayerCurve.__init__(self, **kwargs) LindenmayerCurve.__init__(self, **kwargs)
self.rotate(-self.order*np.pi/9) self.rotate(-self.order*np.pi/9)
class Sierpinski(LindenmayerCurve): class SierpinskiCurve(LindenmayerCurve):
CONFIG = { CONFIG = {
"start_color" : RED, "colors" : [RED, WHITE],
"end_color" : WHITE, "axiom" : "B",
"axiom" : "A",
"rule" : { "rule" : {
"A" : "+B-A-B+", "A" : "+B-A-B+",
"B" : "-A+B+A-", "B" : "-A+B+A-",
@ -259,10 +331,9 @@ class Sierpinski(LindenmayerCurve):
"angle" : -np.pi/3, "angle" : -np.pi/3,
} }
class KochCurve(LindenmayerCurve): class KochSnowFlake(LindenmayerCurve):
CONFIG = { CONFIG = {
"start_color" : BLUE_D, "colors" : [BLUE_D, WHITE],
"end_color" : WHITE,
"axiom" : "A--A--A--", "axiom" : "A--A--A--",
"rule" : { "rule" : {
"A" : "A+A--A+A" "A" : "A+A--A+A"
@ -278,6 +349,12 @@ class KochCurve(LindenmayerCurve):
self.scale_factor = 2*(1+np.cos(self.angle)) self.scale_factor = 2*(1+np.cos(self.angle))
LindenmayerCurve.__init__(self, **kwargs) LindenmayerCurve.__init__(self, **kwargs)
class KochCurve(KochSnowFlake):
CONFIG = {
"axiom" : "A--"
}
class StellarCurve(LindenmayerCurve): class StellarCurve(LindenmayerCurve):
CONFIG = { CONFIG = {

View file

@ -267,14 +267,14 @@ class Polygon(VMobject):
def get_vertices(self): def get_vertices(self):
return self.get_anchors_and_handles()[0] return self.get_anchors_and_handles()[0]
class RegularPolygon(VMobject): class RegularPolygon(Polygon):
CONFIG = { CONFIG = {
"start_angle" : 0 "start_angle" : 0
} }
def __init__(self, n = 3, **kwargs): def __init__(self, n = 3, **kwargs):
digest_config(self, kwargs, locals()) digest_config(self, kwargs, locals())
start_vect = rotate_vector(RIGHT, self.start_angle) start_vect = rotate_vector(RIGHT, self.start_angle)
vertices = compass_directions(n, start_angle) vertices = compass_directions(n, start_vect)
Polygon.__init__(self, *vertices, **kwargs) Polygon.__init__(self, *vertices, **kwargs)