LoginSignup
17
14

More than 5 years have passed since last update.

「プログラムでシダを描画する」を Ruby で描画する

Last updated at Posted at 2014-05-28

巷ではシダを生やすのが流行っているようですが、
意外にも Ruby での投稿がなかったようなのでやってみました。

shida.rb
require "RMagick"
require "open3"

class ShidaGenerator
  include Magick

  N = 20
  DEFAULT_WIDTH  = 500
  DEFAULT_HEIGHT = 500
  FILE_NAME = "shida.jpg"

  W1x = -> (x, y) { 0.836 * x + 0.044 * y }
  W1y = -> (x, y) { -0.044 * x + 0.836 * y + 0.169 }
  W2x = -> (x, y) { -0.141 * x + 0.302 * y }
  W2y = -> (x, y) { 0.302 * x + 0.141 * y + 0.127 }
  W3x = -> (x, y) { 0.141 * x - 0.302 * y }
  W3y = -> (x, y) { 0.302 * x + 0.141 * y + 0.169 }
  W4x = -> (x, y) { 0 }
  W4y = -> (x, y) { 0.175337 * y }

  def initialize(width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT)
    @width = width
    @height = height
  end

  def self.show(width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT)
    self.new(width, height).show
  end

  def generate
    image = Magick::Image.new(@width, @height)

    f = -> (k, x, y) do
      if 0 < k
        f.(k - 1, W1x.(x, y), W1y.(x, y))
        f.(k - 1, W2x.(x, y), W2y.(x, y)) if Random.rand < 0.3
        f.(k - 1, W3x.(x, y), W3y.(x, y)) if Random.rand < 0.3
        f.(k - 1, W4x.(x, y), W4y.(x, y)) if Random.rand < 0.3
      else
        xx = (x * 490 + @width * 0.5).to_i
        yy = (@height - y * 490).to_i
        image.store_pixels(xx, yy, 1, 1, [green_pixel])
      end
    end

    -> (k, x, y) { f.(k, x, y) }.(N, 0, 0)

    image
  end

  def show
    self.generate.write(image_path)
    system("open -a Preview #{image_path}") if open_command_exists?
  end

  private

  def green_pixel
    @pixel ||= Magick::Pixel.new(0, 128 * 256, 0)
  end

  def image_path
    current_dir = File.expand_path(File.dirname(__FILE__))
    File.join(current_dir, FILE_NAME)
  end

  def open_command_exists?
    Open3.capture3("which open").first.empty?.!
  end
end

exit unless __FILE__ == $0

ShidaGenerator.show

当初は ShidaGenerator#render メソッドを再帰的に呼んで描画処理を行っていたのですが、
インスタンスメソッドを再帰的に呼ぶのが嫌だったので、メソッド内で lambda を再帰的に呼ぶことで実現しました。

それと、本当は tk を使って GUI で表示したかったんですが、何時間か試しても実現できませんでした…。
そのため妥協案として JPEG 画像を生成して Mac の場合はそれをプレビューで表示するようにしました。

結果

shida.jpg

元ネタ

参考

17
14
0

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
17
14