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