mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Beginning fractal dimension project
This commit is contained in:
parent
1454216006
commit
209264e90c
5 changed files with 208 additions and 21 deletions
|
@ -25,6 +25,118 @@ from mobject.svg_mobject import *
|
|||
from mobject.tex_mobject import *
|
||||
|
||||
|
||||
class Test(Scene):
|
||||
class KochTest(Scene):
|
||||
def construct(self):
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -17,9 +17,6 @@ class VMobject(Mobject):
|
|||
"considered_smooth" : True,
|
||||
"propogate_style_to_family" : False,
|
||||
}
|
||||
def __init__(self, *args, **kwargs):
|
||||
Mobject.__init__(self, *args, **kwargs)
|
||||
VMobject.init_colors(self)
|
||||
|
||||
## Colors
|
||||
def init_colors(self):
|
||||
|
|
|
@ -29,7 +29,9 @@ class PiCreature(SVGMobject):
|
|||
CONFIG = {
|
||||
"color" : BLUE_E,
|
||||
"stroke_width" : 0,
|
||||
"stroke_color" : BLACK,
|
||||
"fill_opacity" : 1.0,
|
||||
"propogate_style_to_family" : True,
|
||||
"initial_scale_factor" : 0.01,
|
||||
"corner_scale_factor" : 0.75,
|
||||
"flip_at_start" : False,
|
||||
|
@ -44,7 +46,6 @@ class PiCreature(SVGMobject):
|
|||
)
|
||||
digest_config(self, kwargs, locals())
|
||||
SVGMobject.__init__(self, file_name = svg_file, **kwargs)
|
||||
self.init_colors()
|
||||
if self.flip_at_start:
|
||||
self.flip()
|
||||
if self.start_corner is not None:
|
||||
|
@ -66,7 +67,7 @@ class PiCreature(SVGMobject):
|
|||
self.parts_named = True
|
||||
|
||||
def init_colors(self):
|
||||
self.set_stroke(color = BLACK, width = self.stroke_width)
|
||||
SVGMobject.init_colors(self)
|
||||
if not self.parts_named:
|
||||
self.name_parts()
|
||||
self.mouth.set_fill(BLACK, opacity = 1)
|
||||
|
|
|
@ -3,7 +3,7 @@ from mobject.vectorized_mobject import VMobject, VGroup, VectorizedPoint
|
|||
from scene import Scene
|
||||
from animation.transform import Transform
|
||||
from animation.simple_animations import ShowCreation
|
||||
from topics.geometry import Line
|
||||
from topics.geometry import Line, Polygon, RegularPolygon
|
||||
|
||||
from helpers import *
|
||||
|
||||
|
@ -15,15 +15,88 @@ def rotate(points, angle = np.pi, axis = OUT):
|
|||
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):
|
||||
CONFIG = {
|
||||
"radius" : 3,
|
||||
"order" : 5,
|
||||
"colors" : [RED, GREEN],
|
||||
"monochromatic" : False,
|
||||
"stroke_width" : 2,
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
points = self.get_anchor_points()
|
||||
if self.monochromatic:
|
||||
self.set_points_as_corners(points)
|
||||
else:
|
||||
for triplet in zip(points, points[1:], points[2:]):
|
||||
corner = VMobject()
|
||||
corner.set_points_as_corners(triplet)
|
||||
|
@ -244,11 +317,10 @@ class FlowSnake(LindenmayerCurve):
|
|||
LindenmayerCurve.__init__(self, **kwargs)
|
||||
self.rotate(-self.order*np.pi/9)
|
||||
|
||||
class Sierpinski(LindenmayerCurve):
|
||||
class SierpinskiCurve(LindenmayerCurve):
|
||||
CONFIG = {
|
||||
"start_color" : RED,
|
||||
"end_color" : WHITE,
|
||||
"axiom" : "A",
|
||||
"colors" : [RED, WHITE],
|
||||
"axiom" : "B",
|
||||
"rule" : {
|
||||
"A" : "+B-A-B+",
|
||||
"B" : "-A+B+A-",
|
||||
|
@ -259,10 +331,9 @@ class Sierpinski(LindenmayerCurve):
|
|||
"angle" : -np.pi/3,
|
||||
}
|
||||
|
||||
class KochCurve(LindenmayerCurve):
|
||||
class KochSnowFlake(LindenmayerCurve):
|
||||
CONFIG = {
|
||||
"start_color" : BLUE_D,
|
||||
"end_color" : WHITE,
|
||||
"colors" : [BLUE_D, WHITE],
|
||||
"axiom" : "A--A--A--",
|
||||
"rule" : {
|
||||
"A" : "A+A--A+A"
|
||||
|
@ -278,6 +349,12 @@ class KochCurve(LindenmayerCurve):
|
|||
self.scale_factor = 2*(1+np.cos(self.angle))
|
||||
LindenmayerCurve.__init__(self, **kwargs)
|
||||
|
||||
class KochCurve(KochSnowFlake):
|
||||
CONFIG = {
|
||||
"axiom" : "A--"
|
||||
}
|
||||
|
||||
|
||||
|
||||
class StellarCurve(LindenmayerCurve):
|
||||
CONFIG = {
|
||||
|
|
|
@ -267,14 +267,14 @@ class Polygon(VMobject):
|
|||
def get_vertices(self):
|
||||
return self.get_anchors_and_handles()[0]
|
||||
|
||||
class RegularPolygon(VMobject):
|
||||
class RegularPolygon(Polygon):
|
||||
CONFIG = {
|
||||
"start_angle" : 0
|
||||
}
|
||||
def __init__(self, n = 3, **kwargs):
|
||||
digest_config(self, kwargs, locals())
|
||||
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)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue