読者です 読者をやめる 読者になる 読者になる

GTK+ で落書き 6(Ruby)

Gem 'oekaki' で落書きです。
oekaki | RubyGems.org | your community gem host
GTK+でお絵かきしてみた(Ruby) - Camera Obscura


スターを描いてみました。

 

require 'oekaki'

Oekaki.app do
  draw do
    color(0, 0, 0)
    rectangle(true, 0, 0, 300, 300)
    
    color(0xdc00, 0xdc00, 0xdc00)     #gainsboro
    arc(true, 0, 0, 300, 300, 0, 64 * 360) 
    color(0x6b00, 0x8e00, 0x2300)     #olivedrab
    star(true, 150, 150, 150, 0)
  end
end

メソッド Tool#star(fill, x1, y1, x2, y2, color = nil) を新たに書きました。fill は ture で塗りつぶし、false で輪郭のみ描画します。(x1, y1) はスターの中心、(x2, y2) は(とがった)頂点のひとつの座標です。


こんなのも。

 

require 'oekaki'

Oekaki.app width: 400, height: 400 do
  draw do
    color(0, 0, 0)
    rectangle(true, 0, 0, 400, 400)
    
    color(0, 65535, 0)
    po = Vector[0, 50]
    θ = PI / 15
    a = Matrix[[cos(θ), -sin(θ)], [sin(θ), cos(θ)]]
    for y in 0..3
      for x in 0..3
        x1 = x * 100 + 50
        y1 = y * 100 + 50
        star(false, x1, y1, x1 + po[0], y1 - po[1])
        po = a * po
      end
    end
  end
end

Gem の内部で require 'matrix', include Math をしているので、それらのクラスとモジュールがそのまま使えます。
 
 
Gem 'oekaki' に加えたコードはだいたいこんな感じです。

require 'matrix'
include Math

module Oekaki
  class Tool
    def star(fill, x1, y1, x2, y2, color = nil)
      set_color(color)
      Star.new(fill, x1, y1, x2, y2, @color).draw
    end
  end

  class Star < Tool
    def initialize(fill, x1, y1, x2, y2, color)
      @fill = fill
      @o = []; @a = []; @b = []
      @o[0], @o[1] = x1, y1
      @a[0] = Vector[x2 - x1, y1 - y2]
      θ = PI / 5
      rt1 = Matrix[[cos(θ), -sin(θ)], [sin(θ), cos(θ)]]
      rt2 = rt1 * rt1
      1.upto(4) {|i| @a[i] = rt2 * @a[i - 1]}
      t = cos(2 * θ) / cos(θ)
      @b[0] = rt1 * @a[0] * t
      1.upto(4) {|i| @b[i] = rt2 * @b[i - 1]}
      super()
      @color = color
    end
    
    def draw_triangle(n)
      ar = [@a[n].to_w(@o), @b[n].to_w(@o), @b[(n - 1) % 5].to_w(@o)]
      polygon(@fill, ar)
    end
    private :draw_triangle
    
    def draw
      if @fill
        5.times {|i| draw_triangle(i)}
        ar = []
        5.times {|i| ar << @b[i].to_w(@o)}
        polygon(@fill, ar)
      else
        ar = []
        5.times {|i| ar << @a[i].to_w(@o); ar << @b[i].to_w(@o)}
        polygon(@fill, ar)
      end
    end
  end
end

class Vector
  def to_w(o)
    v = self
    [o[0] + v[0], o[1] - v[1]]
  end
end

スターのそれぞれの頂点は、頂点ベクトルに回転行列(変数 rt2)を順に掛けて求めています。Ruby では標準添付ライブラリの 'matrix' で行列やベクトルの計算が簡単に行なえます。

一番苦心したのがじつは色の取り扱いです。Tool#star メソッドの中で Starクラスのインスタンスを新たに作っているので、Tool#color を Tool#star に対して使うとき、Starクラスは Toolクラスを継承しているものの、Toolクラスのインスタンス変数の内容が Star.new で上書きされてしまいます。なので、少しトリッキーなことをしています。


「Gem 'oekaki'」タグを作りました。