#!ruby -Ks # -*- mode: ruby; encoding: sjis -*- # Last updated: <2014/06/05 16:31:06 +0900> require 'dxruby' # 4点を指定して射影変換描画 class ProjTrans attr_accessor :images attr_accessor :src_w attr_accessor :src_h attr_accessor :divx, :divy attr_accessor :mdivx, :mdivy attr_accessor :src_pos attr_accessor :src_idx # コンストラクタ # # @param [Object] img Imageオブジェクト # @param [Number] divx x方向の分割数 # @param [Number] divy y方向の分割数 # def initialize(img, divx = 8, divy = 8) self.divx = divx self.divy = divy self.src_w, self.src_h = img.width, img.height self.images = img.sliceTiles(divx, divy) # 画像を分割 # 頂点列を登録 self.src_pos = [] w, h = 0, 0 bx, by = 0, 0 i = 0 (0..self.divy).each do |iy| bx = 0 (0..self.divx).each do |ix| if ix < self.divx and iy < self.divy i = iy * self.divx + ix w = self.images[i].width h = self.images[i].height end puts "#{i} : (#{bx}, #{by})" if false # 元画像のサイズで座標値を割っておく self.src_pos.push([bx.to_f / self.src_w, by.to_f / self.src_h]) bx += w i += 1 end by += h end # 頂点番号を登録 self.src_idx = [] self.divy.times do |iy| self.divx.times do |ix| addy = self.divx + 1 i = ix + iy * addy self.src_idx.push([i, i + 1, i + 1 + addy, i + addy]) end end if false self.src_idx.each_with_index {|a, i| puts "#{i} : #{a}" } end end # 描画 # # @param [Number] x1 点1のx座標 # @param [Number] y1 点1のy座標 # @param [Number] x2 点2のx座標 # @param [Number] y2 点2のy座標 # @param [Number] x3 点3のx座標 # @param [Number] y3 点3のy座標 # @param [Number] x4 点4のx座標 # @param [Number] y4 点4のy座標 # @param [Number] alpha アルファ値 0-255 # @param [Number] z 描画深度 # @param [Number] blend 合成種類 # @param [Number] mdivx drawMorphに与えるx方向の分割数 # @param [Number] mdivy drawMorphに与えるy方向の分割数 # def draw(x1, y1, x2, y2, x3, y3, x4, y4, alpha = 255, z = 0, blend = :alpha, mdivx = 2, mdivy = 2) # a から h までの、8つの係数を求める sa, sb, sc, sd, se, sf, sg, sh = get_system(x1.to_f, y1.to_f, x2.to_f, y2.to_f, x3.to_f, y3.to_f, x4.to_f, y4.to_f) # 射影変換 d = [] self.src_pos.each do |x, y| m = (x * sg + y * sh + 1) u = (x * sa + y * sb + sc) / m v = (x * sd + y * se + sf) / m d.push([u, v]) end self.src_idx.each_with_index do |a, i| i0, i1, i2, i3 = a Window.drawMorph(d[i0][0], d[i0][1], d[i1][0], d[i1][1], d[i2][0], d[i2][1], d[i3][0], d[i3][1], self.images[i], :dividex => mdivx, :dividey => mdivy, :alpha => alpha, :z => z, :blend => blend) end end # 8つの係数を求める # # @note 変換式に与える座標値を元画像のサイズで割らないとこの係数は使えない # # @param [Number] x0 点1のx座標 # @param [Number] y0 点1のy座標 # @param [Number] x1 点2のx座標 # @param [Number] y1 点2のy座標 # @param [Number] x2 点3のx座標 # @param [Number] y2 点3のy座標 # @param [Number] x3 点4のx座標 # @param [Number] y3 点4のy座標 # @return [Array] 8つの係数を配列で返す # def get_system(x0, y0, x1, y1, x2, y2, x3, y3) sx = (x0 - x1) + (x2 - x3) sy = (y0 - y1) + (y2 - y3) dx1 = x1 - x2 dx2 = x3 - x2 dy1 = y1 - y2 dy2 = y3 - y2 z = (dx1 * dy2) - (dy1 * dx2) g = ((sx * dy2) - (sy * dx2))/z h = ((sy * dx1) - (sx * dy1))/z return [ x1 - x0 + g * x1, x3 - x0 + h * x3, x0, y1 - y0 + g * y1, y3 - y0 + h * y3, y0, g, h ] end end if $0 == __FILE__ # ---------------------------------------- # 動作確認 img = Image.load("lena.png") prt = ProjTrans.new(img) if false # ---------------------------------------- # 簡単な使い方の例 Window.loop do break if Input.keyPush?(K_ESCAPE) alpha = 255 z = 0 blend = :alpha divx = 2 divy = 2 # 左上の点から時計回りに4点を指定 prt.draw(160, 100, 320, 20, 600, 460, 100, 300, alpha, z, blend, divx, divy) end else # ---------------------------------------- # 動作確認 font = Font.new(14) step = 0 pos = [] poly_pos = [] morph_enable = false mdiv = 1 Window.loop do break if Input.keyPush?(K_ESCAPE) if Input.mousePush?(M_LBUTTON) # マウスの左ボタンが押されたので座標を記録 pos = [] if step == 0 pos.push([Input.mousePosX, Input.mousePosY]) step += 1 if step >= 4 # 4点が入力された step = 0 poly_pos = pos.dup end end # zキーが押されたら drawMorph で描画するかどうかを切替 morph_enable = !morph_enable if Input.keyPush?(K_Z) # 上下キーで分割数を変更 (1から64まで。128にすると落ちる…) mdiv *= 2 if (Input.keyPush?(K_UP) and mdiv < 64) mdiv /= 2 if (Input.keyPush?(K_DOWN) and mdiv >= 2) if poly_pos.size == 4 # 4点が決まってるので、画像を変形して描画 x1, y1 = poly_pos[0] x2, y2 = poly_pos[1] x3, y3 = poly_pos[2] x4, y4 = poly_pos[3] unless morph_enable # 射影変換で描画する場合 prt.draw(x1, y1, x2, y2, x3, y3, x4, y4, 255, 0, :alpha, mdiv, mdiv) else # drawMorphで描画する場合 Window.drawMorph(x1, y1, x2, y2, x3, y3, x4, y4, img, :dividex => mdiv, :dividey => mdiv) end end # 指定済みの頂点位置を描画 d = 5 pos.each do |p| x, y = p Window.drawLine(x - d, y, x + d, y, C_GREEN) Window.drawLine(x, y - d, x, y + d, C_GREEN) end i = step + 1 y = 2 msg = [ "#{Window.real_fps.to_i} FPS CPU: #{Window.getLoad.to_i} %", "zキー : drawMorph 描画との切替 [#{(morph_enable)? "drawMorph" : "射影変換"}]", "↑↓キー : drawMorph 分割数 [#{mdiv}]", "時計回りで、4回、マウスクリックしてください (#{step+1}/4)" ].each_with_index do |s, iy| Window.drawFont(4, 2 + iy * (font.size + 8), s, font) end end end end