LoginSignup
4
2

More than 3 years have passed since last update.

[Ruby]フラクタル図形を作るツールを作ってみた/ドラゴン曲線,コッホ曲線

Last updated at Posted at 2020-05-06

はじめに

前回フラクタルについて書いたので,今回フラクタル図形に関する内容を書きます.
2020/5/6 @scivola 様のアドバイスより,改修

フラクタル図形

フラクタル幾何 wikipedia
フラクタル図形はフラクタル幾何とも言われるみたいですね.

ひとつの図形の中を拡大してみても,その小さな同じ図形が繰り返されているような図形のことです.

フラクタル図形のプログラミング

このようにフラクタル図形は同じ図形が繰り返されている・・・
ということは再帰ですね.
そのためプログラミングにおいてフラクタル図形の描画は,再帰を学ぶ良い題材として扱われるみたいです.

今回は,フラクタル図形の中からコッホ曲線ドラゴン曲線を実装してみようと思います.

ツールの仕様

作成したツールの仕様は以下の通りです.
コマンドラインからの引数を受け取りフラクタル図形をfractal_shape.pngとして出力します.


usage = <<"EOS"
fractal_shape.rb : フラクタル図形描画ツール
Usage:
  ruby fractal_shape.rb arg1 arg2 arg3

Description:
  ・コマンドライン引数として3つ入力してください
  ・fractal_shape.pngとして出力されます

Example:
  # 再帰回数3のコッホ曲線を1000×1000サイズで出力
  ruby fractal_shape.rb koch 1000 3   

  # 再帰回数10のドラゴン曲線を500×500サイズで出力
  ruby fractal_shape.rb dragon 500 10

Options:
  arg1:フラクタル図形の指定(コッホ曲線:'koch', ドラゴン曲線:'dragon')
  arg2:出力するpng画像のサイズ
  arg3:フラクタルのステップ数

EOS

Rubyによる実装

アルゴリズムの部分に関しては,以下の記事を参考にさせていただき,実装しました.
非常にわかりやすくまとまっており,アルゴリズムの部分は言語関係なく活用できますので是非.
再帰プログラムによるフラクタル図形の描画

入力はこんな感じで受け取ります.
引数がちゃんと3つ無い場合はUsageを表示します.

  • 引数1:コッホ曲線かドラゴン曲線か
  • 引数2:大きさ
  • 引数3:繰り返し回数

という具合で,クラスに渡します.

if __FILE__ == $0
  if ARGV.size != 3
    puts usage
    exit
  end
  id = ARGV[0]
  width = height = ARGV[1].to_i
  step = ARGV[2].to_i

  fractal_shape = FractalShape.new(width, height, step)

  if id == "koch"
    fractal_shape.koch
  elsif id == "dragon"
    fractal_shape.dragon
  end
end

まずはinitialize()で初期化を行います.
rubyで二次元描画どうするのかなあとかなり苦戦してしまいましたが
cairoというgemを使ってみることにしました.


  def initialize(width, height, step)
    @width = width
    @height = height
    @step = step
    @surface = Cairo::ImageSurface.new(width, height)
    @context = Cairo::Context.new(@surface)
    @context.set_source_rgb(1, 0, 0)
    @context.set_line_cap :round
  end

描画を行う関数です.
context.move_toからcontext.line_toにかけて形を作り
context.strokeで線分を描画します.
ここまではコッホ曲線,ドラゴン曲線ともに共通です.


  def draw_line(s, e, context)
    context.move_to(s[0], s[1])
    context.line_to(e[0], e[1])
    context.stroke
  end

コッホ曲線

まずはコッホ曲線の実装からです.
最初の部分は,コッホ曲線を描画する際に大きさ,向きをいい感じにするために適当な計算をしてます.


  def koch
    p = Vector[@width * 0.1, @height * 0.5]
    q = Vector[@width * 0.9, @height * 0.5]
    koch_algorithm(p, q, @step, @context)
    @surface.write_to_png("fractal_shape.png")
  end

コッホ曲線のアルゴリズム

コッホ曲線のアルゴリズムです.
先ほどの記事が分かり易すぎるので,私が加筆する必要がありません・・・


  def koch_algorithm(a, b, n, context)
    c = (a * 2 + b) / 3.0
    d = (a + b * 2) / 3.0

    xx = (b - a)[0]
    yy = -(b - a)[1]

    distance = Math.hypot(xx, yy) / Math.sqrt(3)

    if xx >= 0
      angle1 = Math.atan(yy.to_f / xx) + Math::PI / 6
      e = a + Vector[Math.cos(angle1), -Math.sin(angle1)] * distance
    else
      angle2 = Math.atan(yy.to_f / xx) - Math::PI / 6
      e = b + Vector[Math.cos(angle2), -Math.sin(angle2)] * distance
    end

    if n <= 0
      draw_line(a, c, context)
      draw_line(c, e, context)
      draw_line(e, d, context)
      draw_line(d, b, context)
    else
      koch_algorithm(a, c, n - 1, context)
      koch_algorithm(c, e, n - 1, context)
      koch_algorithm(e, d, n - 1, context)
      koch_algorithm(d, b, n - 1, context)
    end
  end

結果

こんな感じで相似図形が出来上がっていきます.
fractal_shape.pngfractal_shape.pngfractal_shape.pngfractal_shape.png

ドラゴン曲線

次は本命ドラゴン曲線の実装です.
こちらも同じくドラゴン曲線を描画する際に大きさをいい感じにするために適当な計算をしてます.


  def dragon
    p = Vector[@width * 0.3, @height * 0.5]
    q = Vector[@width * 0.9, @height * 0.5]
    dragon_algorithm(p, q, @step, @context)
    @surface.write_to_png("fractal_shape.png")
  end

ドラゴン曲線のアルゴリズム

ドラゴン曲線のアルゴリズムです.


  def dragon_algorithm(a, b, n, context)
    xx = (b - a)[0]
    yy = -(b - a)[1]

    c = Vector[a[0]+(xx + yy)/2, b[1]+(xx + yy)/2]

    if n <= 0
      draw_line(a, c, context)
      draw_line(b, c, context)
    else
      dragon_algorithm(a, c, n - 1, context)
      dragon_algorithm(b, c, n - 1, context)
    end
  end

結果

こんな感じで相似図形が出来上がっていきます.
fractal_shape.pngfractal_shape.pngfractal_shape.pngfractal_shape.png

そしてステップ数が10回を超えてくると・・・

fractal_shape.png

「ヘイウェイ・ドラゴン」を召喚!!

ヘイウェイ・ドラゴン(ハーター・ヘイウェイ・ドラゴンあるいはジュラシック・パーク・ドラゴンとも呼ばれる)は、NASAの物理学者のジョン・ヘイウェイ、ブルース・バンクスおよびウィリアム・ハーターによって初めて研究され、1967年、雑誌『サイエンティフィック・アメリカン(Scientific American)』のマーティン・ガードナーによるコラム「数学ゲーム(Mathematical Games」で紹介された。その性質についてはチャンドラー・デイビスとドナルド・クヌースによって初めて出版化された。マイケル・クライトンの小説『ジュラシック・パーク』の節ごとのタイトルページで使用されている。

さらに「ヘイウェイ・ドラゴン」2体を融合!
fractal_shape.png

出でよ!「ツイン・ドラゴン」!!

二つのヘイウェイ・ドラゴンを背中合わせに配置することにより、ツインドラゴン(デイビス-クヌース・ドラゴンとも呼ばれる)を作ることが出来る。

粉砕!玉砕!大喝采!

なんてこともドラゴン曲線のアルゴリズムを,位置をずらして2回実行すれば簡単にできちゃいます.

まとめ

ということで,ツイン・ドラゴンを召喚できましたフラクタル図形を描画できました!
アルゴリズムさえ変えれば他のフラクタル図形も簡単に描画できますので
是非コピペして使ってみてください.

参考文献

再帰プログラムによるフラクタル図形の描画, 石立 喬[著] ,2005 https://codezine.jp/article/detail/73

4
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2