Cairo::Matrixを使ってみる

二次元図形の座標変換について調べてみた。
http://ldt.kobe-shinwa.ac.jp/masa/classes/2005fmm/chapter3.html
ここだ。
最初ruby のMatrixクラスを使って座標変換をしようとしたが、
座標変換が理解できるようになったら
Cairo::Matrixで、変換したほうが、手っ取り早い事に気づいた。
それで、これ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w,@h = w, h
@color = Cairo::Color::BLACK
end

def update(c)
c.set_source_color(@color)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Core
def initialize(x,y)
@x, @y = x, y
@r = 5
@color = Cairo::Color::ORANGE
end

def update(c)
c.set_source_color(@color)
c.circle(@x, @y, @r)
c.fill
end
end

class Diagram
attr_accessor :matrix

def initialize(x,y)
@x,@y = x,y
@r = 50
@color = Cairo::Color::GREEN
@line_width = 5
angle_size = 4
step = 360 / angle_size
@vector = []
0.step(359, step) do |dg|
rd= dg * Math::PI / 180
@vector << [@r * Math::cos(rd), @r * Math::sin(rd)]
end
@matrix = Cairo::Matrix.identity
end

def update(c)
c.set_source_color(@color)
c.set_line_width(@line_width)
flag =true
@vector.each do |x0,y0|
x, y = @matrix.transform_point(x0, y0)
if flag
c.move_to(x + @x, y + @y)
else
c.line_to(x + @x, y + @y)
end
flag = false
end
c.close_path
c.stroke
end
end

class Phase
def initialize(w,h)
@image = Cairo::ImageSurface.new(w, h)
@bg = BackGround.new(w, h)
bx = 0
@core = []
@dia = []
4.times do |i|
bx += 100
@core << Core.new(bx, 150)
@dia << Diagram.new(bx, 150)
end
@deg = 0
@angle = 15
end

def update
@deg += @angle
@deg = 0 if @deg > 359
rd = @deg * Math::PI / 180
# 回転
@dia[1].matrix = Cairo::Matrix.rotate(rd)
# せん断
@dia[2].matrix = Cairo::Matrix.new( Math.sin(rd), 1, 1, Math.cos(rd), 0, 0)
# 行列の積 Cairo::Matrix#multiplyと同じ
@dia[3].matrix = @dia[1].matrix * @dia[2].matrix
context = Cairo::Context.new(@image)
@bg.update(context)
@core.each {|obj| obj.update(context)}
@dia.each {|obj| obj.update(context)}
@image
end
end

class Game
def initialize(screen)
@screen = screen
@phase = Phase.new(@screen.w, @screen.h)
end

def update
image = @phase.update
suface = SDL::Surface.new_from(image.data, image.width, image.height, 32, image.stride, 0, 0, 0, 0)
@screen.put(suface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(100)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(500, 300, SDL::Screen.info.bpp, SDL::SWSURFACE)
Game.new(@screen).run
[PR]
by gaziya | 2011-05-09 19:10