Sierpiński triangle


また,フラクタルへの関心が強まっている.今回はその中でもシェルピンスキーの三角形というものを学んだので試したい.

import matplotlib.pyplot as plt
import numpy as np
import imageio
from matplotlib.patches import Polygon
from io import BytesIO
from PIL import Image

def remove_center(vertices):
    """
    三角形 vertices(3点のリスト)が与えられたとき,
    各辺の中点を結んだ中央の三角形(穴)の頂点リストを返す.
    """
    a, b, c = vertices
    mid_ab = ((a[0] + b[0]) / 2, (a[1] + b[1]) / 2)
    mid_bc = ((b[0] + c[0]) / 2, (b[1] + c[1]) / 2)
    mid_ca = ((c[0] + a[0]) / 2, (c[1] + a[1]) / 2)
    return [mid_ab, mid_bc, mid_ca]

def save_frame(fig):
    """
    現在の matplotlib の描画状態を PNG 画像としてバッファに保存し,
    numpy 配列に変換して返す.
    """
    buf = BytesIO()
    fig.savefig(buf, format='png', bbox_inches='tight')
    buf.seek(0)
    img = Image.open(buf)
    frame = np.array(img)
    buf.close()
    return frame

def simulate_removal(initial_triangle, depth):
    """
    初期の塗りつぶされた三角形から始め,
    各段階で各三角形の中央部分(穴)を白で塗りつぶす
    くり抜き操作を行いながらフレームを記録する.

    Parameters:
      initial_triangle: 三角形の頂点リスト(例: [(0,0), (1,0), (0.5, np.sqrt(3)/2)])
      depth: くり抜きを何段階行うか

    Returns:
      フレーム画像(numpy 配列)のリスト
    """
    frames = []
    
    # 描画の初期設定
    fig, ax = plt.subplots(figsize=(6, 6))
    ax.set_aspect('equal')
    ax.axis('off')
    ax.set_xlim(-0.05, 1.05)
    ax.set_ylim(-0.05, np.sqrt(3)/2 + 0.05)
    
    # 初期の塗りつぶされた大三角形(色はお好みで)
    initial_patch = Polygon(initial_triangle, facecolor='blue', edgecolor='black', linewidth=1.5)
    ax.add_patch(initial_patch)
    frames.append(save_frame(fig))
    
    # くり抜き処理の対象となる三角形リスト(最初は大三角形)
    current_triangles = [initial_triangle]
    
    # depth 回の処理
    for d in range(depth):
        new_triangles = []
        # 各三角形に対して中央部分を削除(白塗り)し,
        # 次の段階で処理する残りの三角形を求める
        for tri in current_triangles:
            # 中央部分(穴)の頂点リスト
            hole = remove_center(tri)
            # 中央部分を背景色(ここでは白)で塗りつぶす
            hole_patch = Polygon(hole, facecolor='white', edgecolor='white')
            ax.add_patch(hole_patch)
            frames.append(save_frame(fig))
            
            # 元の三角形の各頂点と辺の中点から,
            # 次の段階で処理する3つの小三角形を作成する
            a, b, c = tri
            mid_ab = ((a[0] + b[0]) / 2, (a[1] + b[1]) / 2)
            mid_bc = ((b[0] + c[0]) / 2, (b[1] + c[1]) / 2)
            mid_ca = ((c[0] + a[0]) / 2, (c[1] + a[1]) / 2)
            
            t1 = [a, mid_ab, mid_ca]
            t2 = [b, mid_bc, mid_ab]
            t3 = [c, mid_ca, mid_bc]
            new_triangles.extend([t1, t2, t3])
        current_triangles = new_triangles
        
    return frames

def main():
    # くり抜きの深さ(大きくすると細かい穴が増えます)
    depth = 5
    # 初期の正三角形の頂点(底辺は横,高さは np.sqrt(3)/2)
    initial_triangle = [(0, 0), (1, 0), (0.5, np.sqrt(3) / 2)]
    
    frames = simulate_removal(initial_triangle, depth)
    # GIF アニメーションとして保存(duration はフレーム間の時間[秒])
    imageio.mimsave('sierpinski_removal.gif', frames, duration=0.2)
    print("sierpinski_removal.gif を作成しました。")

if __name__ == '__main__':
    main()


参考文献

  • Fractal Foundation. (2009). Fractal Pack 1: Educators’ guide. Fractals are SMART: Science, math & art! Retrieved from http://www.FractalFoundation.org

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です