Fractals Geometry#

Sierpinski Triangle 3D#

Sierpinski Triangle

@tree
def iterate_sierpinski(instances: Instances, cone: Mesh):
    """Iterate Sierp."""
    instances = cone.Instances.on_points(instances, scale=0.5)
    return instances, cone

@tree
def sierpinski_fractal(scale: Float = (2, 0.1, 10)):
    cone = MeshCone(vertices=3, depth=1.5).mesh
    instances, cone = iterate_sierpinski(cone, cone)
    instances.node.label = f"Iterate 1"

    for i in range(5):
        instances, cone = iterate_sierpinski(instances, cone)
        instances.node.label = f"Iterate {i+2}"

    return instances.scale_elements(scale=scale)

Menger Sponge#

Menger Sponge

@tree
def iterate_menger(instances: Instances, points: Points, scale: Float = (1 / 3, 0, 1 / 3)):
    return instances.on_points(points, scale=scale)

@tree
def menger_init_points():
    points = MeshCube(1, 3, 3, 3).mesh.to_points()
    return points[points.position.length > 0.5].select()

@tree
def menger_sponge():
    cube = MeshCube(1.5).mesh
    points = menger_init_points()
    instances = iterate_menger(cube, points)

    for i in range(2):
        instances = iterate_menger(points=points, instances=instances)

    return instances

Pythagoras Tree#

pythagoras_tree

from pynodes import *
from pynodes.math import *

# Calculate the center and radius of the tangent circle of a right triangle. v3 is the right Angle point
@tree
def inscribed_circle(v1: Vector, v2: Vector, v3: Vector):
    """Inscribed Circle of Right Triangle"""

    with frame("Length of side"):
        c = v1.distance(v2)
        a = v2.distance(v3)
        b = v3.distance(v1)

    with frame("Perimeter"):
        l = c + a + b

    with frame("Radius: a + b = c + 2r"):
        r = (a + b - c) / 2

    with frame("Center of circle"):
        x = (a * v1.x + b * v2.x + c * v3.x) / l
        y = (a * v1.y + b * v2.y + c * v3.y) / l

    return CombineXYZ(x, y)("Center"), r("Radius") # Rename the ouput socket
    # return CombineXYZ(x, y), r # this is also OK


@tree
def iterate_pythagoras(v1: Vector, v2: Vector, angle: Float = (pi / 6, 0, pi / 2), sphere: Mesh = None):

    with frame("Length of side"):
        length = v1.distance(v2)

    with frame("Square"):
        v3 = v2.rotate("Z_AXIS", center=v1, angle=pi / 2)
        v4 = v1.rotate("Z_AXIS", center=v2, angle=-pi / 2)

    with frame("Right Angle point"):
        v5 = v4.rotate("Z_AXIS", center=v3, angle=angle)
        v5 = v3.mix(v5, cos(angle))

    with frame("Cube"):
        rect = Quadrangle(v1, v2, v4, v3)
        cube = rect.filled_ngons.extrude(length).mesh

    with frame("Cylinder"):
        line = v1.mix(v2).line_to(v3.mix(v4))
        cylinder = line.to_mesh(CurveCircle(length / 2), True)

    with frame("Sphere"):
        center, radius = inscribed_circle(v3, v4, v5)
        # sphere = MeshIcoSphere(radius, 1).mesh.transform(center)
        sphere_transformed = sphere.Mesh.transform(center, scale=radius)

    mesh = cube.switch(True, cylinder.join(sphere_transformed))

    return mesh("Mesh"), v3('v1'), v5('v2'), v4('v3'), angle("Angle"), sphere


def iterate_n(v1, v2, angle, sphere, curves: list, n=3):
    if n == 0:
        return
    mesh, v1, v2, v3, angle, sphere = iterate_pythagoras(v1, v2, angle, sphere)
    curves.append(mesh)
    iterate_n(v1, v2, angle, sphere, curves, n - 1)
    iterate_n(v2, v3, angle, sphere, curves, n - 1)


@tree
def pythagoras_tree(
    v1: Vector = (-1, 0, 0),
    v2: Vector = (1, 0, 0),
    angle: Float = (pi / 6, 0, pi / 2),
    animate: Boolean = True,
):
    curves = []

    sphere = MeshIcoSphere(subdivisions=3).mesh

    iterate_n(v1, v2, angle.switch(animate, sin(SceneTime().seconds).map_range(-1, 1, 0, pi / 4)), sphere, curves, 6)

    return join(*curves)

Quadratic Koch 3D#

quadratic_koch_3d

from pynodes import *


@tree
def iterate(points: Points, instance: Instances):

    normal = points.capture_vector_on_faces(points.normal)

    points = points.Mesh.to_points("FACES")

    return instance.on_points(points, rotation=normal.align_euler_to_vector("Z"), scale=1 / 3)


@tree
def quadratic_koch_3d():

    mesh = MeshGrid(3, 3, 4, 4).mesh

    base_mesh = mesh[4].extrude_faces().mesh

    iterated_mesh = iterate(base_mesh, base_mesh)
    iterated_mesh.node.label = "Iterate 1"

    iterated_mesh = iterate(iterated_mesh, base_mesh)
    iterated_mesh.node.label = "Iterate 2"

    iterated_mesh = iterate(iterated_mesh, base_mesh)
    iterated_mesh.node.label = "Iterate 3"

    return iterated_mesh