Ruby/SDLで計算幾何(1)GeoBaseを作る

アルゴリズムC第二巻amazon:4764902567のお勉強を、Rubyで始めてみます。

とっかかりのアイデアid:technohippyさんの過去日記 http://d.hatena.ne.jp/technohippy/20070719#1184868435 から頂きます。ありがとうございます。

ベースのクラスを作成します。ほぼid:technohippyさんのコピーですが、多角形Polygonに関してのみ追加しています。

class GeoBase
  attr_accessor :screen
  
  class Point
    attr_accessor :x, :y
    def initialize(x, y); @x, @y = x, y end
    def to_s; "(#{x}, #{y})" end
    def inspect; to_s end
    def ==(p1); x == p1.x and y == p1.y; end
  end
  
  class Line
    attr_accessor :p1, :p2
    def initialize(p1, p2); @p1, @p2 = p1, p2 end
    def to_s; "[#{p1.to_s}, #{p2.to_s}]" end
    def inspect; to_s end
    def ==(l1); p1 == l1.p1 and p2 == l1.p2; end
  end
  
 # 多角形
  class Polygon
    attr_accessor :vertices
    def initialize(vertices)
      @vertices = vertices.push vertices[0], vertices[1]
    end
    def to_s; "#{vertices}" end
    def inspect; to_s end
    def ==(poly1); vertices == poly1.vertices; end
  end

  def default_color; [255, 255, 255] end
  
  def point(x, y)
    Point.new x, y
  end
  alias p point
  
  def line(x1, y1, x2=nil, y2=nil)
    if x2
      x1 = p x1, y1
      y1 = p x2, y2
    end
    Line.new x1, y1
  end
  alias l line
  
  # 多角形を点の座標、または配列で作成
  def polygon(x1, *arg)
    if arg
      if arg.size % 2 == 0
        raise ArgumentError, 'num of coodinates is odd.'
      else
        arg.unshift x1
        vertices = []
        (0..(arg.size/2)).each do |i|
          vertices << p(arg[i], arg[i+1])
        end
      end
    else
      vertices = x1
    end
    Polygon.new vertices  
  end
  alias poly polygon
  
  def draw_point(p1)
    @screen.drawCircle p1.x, p1.y, 3, default_color, true
  end

  def draw_line(x1, y1=nil, x2=nil, y2=nil)
    if x2
      x1 = l x1, y1, x2, y2
    elsif y1
      x1 = l x1, y1
    end
    @screen.drawLine x1.p1.x, x1.p1.y, x1.p2.x, x1.p2.y, default_color
  end
  
 # 多角形を描画
  def draw_polygon(poly1)
    poly1.vertices.inject do |s,n| 
      draw l(s, n); n
    end
  end
  
  def draw(*targets)
    targets.each do |target|
      case target
      when Point
        draw_point target
      when Line
        draw_line target
      when Polygon
        draw_polygon target
      end
    end
  end
  
  def start
    raise 'subclass responsibility'
  end

  def update
    @screen.updateRect 0, 0, 0, 0
  end
  
  def self.wait
    loop do
      while event = SDL::Event2.poll
        case event
        when SDL::Event2::Quit, SDL::Event2::KeyDown
          exit
        end
      end
    end
  end
  
  def self.start
    SDL.init SDL::INIT_VIDEO
    geo = self.new
    geo.screen = SDL.setVideoMode 640, 480, 16, SDL::SWSURFACE
    geo.start
    geo.update
    wait
  end
end

次回は、二つの直線が交差するかどうかを判定するメソッドを作成します。

module関数にするか、Lineクラスのmethodにするか、まだ決めていません。