自習開始

ちょっと興味がわいたので、amazon:476490277X擬似コードで書かれてるアルゴリズムを実際にRubyでちまちまと組んでいこうかなと。

まずは、ベースのクラスを作っとく。

require 'sdl'

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
    
    # 「計算幾何学入門 幾何アルゴリズムとその応用」p.27
    def left?(p)
      0 < (p1.x-p.x)*(p2.y-p.y)+(p2.x-p.x)*(p.y-p1.y)
    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 draw_point(p1)
    @screen.drawFilledCircle p1.x, p1.y, 3, default_color
  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
  alias l line
  
  def draw(*targets)
    targets.each do |target|
      case target
      when Point
        draw_point target
      when Line
        draw_line 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

今後は上のクラスを継承してstartメソッドだけ上書きすれば大丈夫。
例えばこんな感じ。

class GeoBaseTest < GeoBase
  def start
    draw p(10, 10)
    draw l(100, 100, 400, 200)
    draw p(100, 80), l(80, 80, 200, 400)
  end
end

GeoBaseTest.start