中心を軸に回転

Cairo::Matrixを使い、Cairo::Context#set_sourceで読み込んだイメージを
中心を軸に回転させる。
http://cairographics.org/matrix_transform/
このページを参考にした。
ちょっと、扱い方が、やっかいだ。
回転行列に移動行列を掛ける。
逆だと、ダメだ。
テストしたプログラムはこれだ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::BLACK)
c.rectangle(0, 0, @w, @h)
c.fill
c.set_source_color(Cairo::Color::GREEN)
c.move_to(0, @h / 2)
c.line_to(@w, @h / 2)
c.stroke
(1..3).each do |i|
c.move_to(@w / 4 * i, 0)
c.line_to(@w / 4 * i, @h)
c.stroke
end
end
end

class Panel
attr_writer :matrix
attr_reader :w, :h

def initialize(x, y)
@x, @y = x, y
@w, @h = 100, 100
@image = Cairo::ImageSurface.new(@w, @h)
context = Cairo::Context.new(@image)
context.set_source_color(Cairo::Color::ORANGE)
context.rectangle(0, 0, @w, @h)
context.fill
@matrix = Cairo::Matrix.identity
end

def update(c)
c.matrix = @matrix
c.set_source(@image, @x, @y)
c.paint
end
end


class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@panel0 = Panel.new(0, 0)
@panel1 = Panel.new(@w / 4, @h / 2)
@panel2 = Panel.new(0, 0)
@panel3 = Panel.new(0, 0)
@deg = 0
end

def update
@deg += 15
@deg = 0 if @deg > 359
rd = @deg * Math::PI / 180
sin = Math.sin(rd)
cos = Math.cos(rd)
x, y = @panel1.w / 2, @panel1.h / 2
ro_mtrx = Cairo::Matrix.new(cos, sin, -sin, cos, x - cos * x + sin * y, y - sin * x - cos * y)
@panel0.matrix = ro_mtrx
@panel1.matrix = ro_mtrx
tr_mtrx = Cairo::Matrix.translate(@w / 4 * 2, @h / 2)
@panel2.matrix = tr_mtrx * ro_mtrx
tr_mtrx = Cairo::Matrix.translate(@w / 4 * 3, @h / 2)
@panel3.matrix = ro_mtrx * tr_mtrx
context = Cairo::Context.new(@image)
@bg.update(context)
@panel0.update(context)
@panel1.update(context)
@panel2.update(context)
@panel3.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 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(600, 300, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-10 22:38