mscene.fractalΒΆ

from manim import *


class KochCurve(VMobject):
    def __init__(
        self,
        level=0,
        length=config.frame_width * 3 / 4,
        point=ORIGIN,
        group=True,
        **kwargs
    ):
        super().__init__(**kwargs)

        self.level = 0 if level < 0 else level
        self.length = length
        self.kwargs = kwargs
        self._koch_curve(self.level, self.length, point, group=group)

    def _koch_curve(self, level, length, point, group=True):
        l = length / (3**level)
        points = [LEFT * l / 2, RIGHT * l / 2]
        self.set_points_as_corners(points)
        vmob = self.copy()
        for _ in range(level):
            new_vmob = VGroup()
            for i in (0, PI / 3, -PI / 3, 0):
                new_vmob.add(vmob.copy().rotate(i))
            new_vmob.arrange(RIGHT, buff=0, aligned_edge=DOWN)
            vmob.become(new_vmob)
        vmob.move_to(point)
        if group:
            points = vmob.get_all_points()
            self.set_points(points)
        else:
            self.become(vmob)

    def new_level(self, level=None, length=None, point=None, **kwargs):
        level = self.level if level is None else level
        length = self.length if length is None else length
        point = self.get_center() if point is None else point
        self.kwargs.update(kwargs)
        kwargs = self.kwargs
        self.__init__(level, length, point, **kwargs)

    def next_level(self, **kwargs):
        level = self.level + 1
        self.new_level(level, **kwargs)

    def prev_level(self, **kwargs):
        level = self.level - 1
        self.new_level(level, **kwargs)


class KochSnowflake(KochCurve):
    def __init__(
        self,
        level=0,
        length=config.frame_width / 3,
        point=ORIGIN,
        invert=False,
        fill_opacity=1,
        stroke_width=0,
        color=BLUE,
        **kwargs
    ):
        kwargs.update(
            {
                "fill_opacity": fill_opacity,
                "stroke_width": stroke_width,
                "color": color,
            }
        )

        super().__init__(**kwargs)

        self.level = 0 if level < 0 else level
        self.length = length
        kwargs.update({"invert": invert})
        self.kwargs = kwargs
        self._koch_snowflake(self.level, self.length, point, invert)

    def _koch_snowflake(self, level, length, point, invert):

        self._koch_curve(level, length, point, group=True)

        if invert:
            self.rotate(PI).reverse_direction()
            kc2 = self.copy().rotate(PI, about_point=self.get_top())
        else:
            kc2 = self.copy().rotate(PI, about_point=self.get_bottom())

        kc1 = self.copy().rotate(-PI / 3, about_point=self.get_end())
        kc3 = self.copy().rotate(PI / 3, about_point=self.get_start())
        ks = VGroup(kc1, kc2, kc3).move_to(point)

        points = ks.get_all_points()

        self.sides = ks.set_style(fill_opacity=0, stroke_width=4)

        self.set_points_as_corners(points)