#!ruby -Ks # -*- mode: ruby; coding: sjis -*- # Last updated: <2016/02/13 03:59:49 +0900> # # DXRubyでCatmull-Romスプライン曲線を描画してみる # # Catmull-Rom 補間 - blog.seyself.com # http://blog.seyself.com/2008/06/post_2008061020.html # # デジタル・フロンティア-Digital Frontier | DF TALK | スプライン曲線の話 # http://www.dfx.co.jp/dftalk/?p=10576 require 'dxruby' Window.caption = "Catmul-Rom Spline Curve" # Catmul-Rom補間の値を取得 # # @param p0 [Number] 値0 # @param p1 [Number] 値1 # @param p2 [Number] 値2 # @param p3 [Number] 値3 # @param t [Number] t値 (0.0 - 1.0) # @return [Number] 結果 (p1 - p2 の間で値を返す) def get_catmul_rom(p0, p1, p2, p3, t) t = t.to_f v0 = (p2 - p0).to_f * 0.5 v1 = (p3 - p1).to_f * 0.5 t2 = t * t t3 = t2 * t return ((p1 - p2) * 2 + v0 + v1) * t3 + \ ((p2 - p1) * 3 - 2 * v0 - v1) * t2 + v0 * t + p1 end # 四角(塗り潰し)を描画 def draw_dot(x, y, sz, color) Window.drawBoxFill(x - sz, y - sz, x + sz, y +sz, color) end # 四角(線)を描画 def draw_box(x, y, sz, color) x1, y1 = x - sz, y - sz x2, y2 = x + sz, y + sz Window.drawLine(x1, y1, x2, y1, color) Window.drawLine(x2, y1, x2, y2, color) Window.drawLine(x1, y1, x1, y2, color) Window.drawLine(x1, y2, x2, y2, color) end fnt = Font.new(12) # 制御点を初期化 x = 16 y = 64 dx = 120 dy = 40 p = [] 8.times do |i| p.push([x, y]) x += dx y += dy end mode = 0 Window.resize(1024, 768) # メインループ Window.loop do break if Input.keyPush?(K_ESCAPE) if Input.mousePush?(M_LBUTTON) # マウスボタンが押されたので制御点の座標を変更 p[mode] = [Input.mousePosX.to_f, Input.mousePosY.to_f] mode += 1 mode = 0 if mode >= p.length end # 制御点を描画 p.each_with_index do |c, i| x, y = c draw_dot(x, y, 3, C_RED) draw_box(x, y, 6, C_CYAN) if i == mode end # Catmul-Rom Spline を描画 (p.length - 3).times do |i| n0, n1, n2, n3 = i, i+1, i+2, i+3 x0, x1, x2, x3 = p[n0][0], p[n1][0], p[n2][0], p[n3][0] y0, y1, y2, y3 = p[n0][1], p[n1][1], p[n2][1], p[n3][1] 0.step(1.0 - 0.05, 0.05) do |t| x = get_catmul_rom(x0, x1, x2, x3, t) y = get_catmul_rom(y0, y1, y2, y3, t) draw_dot(x, y, 1, C_WHITE) end end Window.drawFont(4, 4, "Please click [#{mode}]", fnt) end