2021年7月7日水曜日

ヒルベルト曲線を(Pythonで)描く

以前,JavaScriptでヒルベルト曲線を描くプログラムを紹介した.今回は,Pythonのタートルグラフィクスライブラリを使って同様のヒルベルト曲線を描くプログラムである.

ヒルベルト曲線に限らずフラクタルは再帰の考え方で描くことができるが,まさに下記の関数がそれを表している.こんなに簡単に表現することができるのは素晴らしい.NumPyを利用して行列演算をたんなる掛け算として表すことができる点も,単純化に寄与している要因である.

def hilbert(n, m):

  if n > 1:

    for m_ in tm: hilbert(n-1, m * m_)

  else:

    for q in [ m * p_ for p_ in p ]: draw_line_to(q)

なお,一時的に用意している「m_」や「p_」といった変数は,とくに名前を付ける必要はないのでアンダースコア1文字で次のように表現することも許されているらしい.しかし,ここまでやるのは少しやり過ぎな気もする.

def hilbert(n, m):

  if n > 1:

    for _ in tm: hilbert(n-1, m * _)

  else:

    for q in [ m * _ for _ in p ]: draw_line_to(q)

タートルグラフィクスなので,これだけのプログラムでアニメーション動作する.動画を用意した.ずっと眺めていても飽きないゾ?

プログラムの全体は以下のとおりである.

#!/usr/bin/env python


from turtle import *

import numpy as np


SIZE = 300

MARGIN = 50

penup_flag = True


settings = [ { 'color': x[0], 'width': x[1] } for x in [

  ['forestgreen', 5], ['navy', 4], ['purple', 3], ['brown', 2],

  ['red', 2], ['orange', 1], ['yellowgreeen', 1] ] ]


tm = [ np.matrix(x) for x in [

  [ [0.0, -0.5, -0.5], [-0.5, 0.0,  0.5], [0.0, 0.0, 1.0] ],

  [ [0.5,  0.0, -0.5], [ 0.0, 0.5, -0.5], [0.0, 0.0, 1.0] ],

  [ [0.5,  0.0,  0.5], [ 0.0, 0.5, -0.5], [0.0, 0.0, 1.0] ],

  [ [0.0,  0.5,  0.5], [ 0.5, 0.0,  0.5], [0.0, 0.0, 1.0] ] ] ]


e = np.eye(3)


p = [ np.matrix(x).T for x in [

      [-0.5,  0.5, 1.0], [-0.5, -0.5, 1.0],

      [ 0.5, -0.5, 1.0], [ 0.5,  0.5, 1.0] ] ]


def draw_line_to(x):

  goto(x[0,0]*SIZE, x[1,0]*SIZE)

  global penup_flag

  if penup_flag:

    pendown()

    penup_flag = False


def reset():

  penup()

  global penup_flag

  penup_flag = True


def hilbert(n, m):

  if n > 1:

    for m_ in tm: hilbert(n-1, m * m_)

  else:

    for q in [ m * p_ for p_ in p ]: draw_line_to(q)


setup(width = 2*SIZE+MARGIN, height = 2*SIZE+MARGIN)


for i in range(len(settings)):

  reset()

  color(settings[i]['color'], 'white')

  width(settings[i]['width'])

  hilbert(i+1, e)


onkey(exit, 'q')

listen()

mainloop()

0 件のコメント:

コメントを投稿