Skip to content

Instantly share code, notes, and snippets.

@mirichi

mirichi/bezier.rb Secret

Created Jan 1, 2017
Embed
What would you like to do?
ベジェ曲線体験ツール
require 'dxruby'
# 3次ベジェ曲線をImageオブジェクトに描画する
class BezierDrawer
attr_reader :image
KAPPA90 = 0.5522847493
TESS_TOL = 0.25 / 1.0
def initialize
@points = []
@image = Image.new(640,480)
end
def tesselate_bezier(x1, y1, x2, y2, x3, y3, x4, y4, level)
return if level > 10
dx = x4 - x1
dy = y4 - y1
d2 = ((x2 - x4) * dy - (y2 - y4) * dx).abs
d3 = ((x3 - x4) * dy - (y3 - y4) * dx).abs
if (d2 + d3) * (d2 + d3) < TESS_TOL * (dx * dx + dy * dy)
@points << [x4, y4]
return
end
x12 = (x1 + x2) * 0.5
y12 = (y1 + y2) * 0.5
x23 = (x2 + x3) * 0.5
y23 = (y2 + y3) * 0.5
x34 = (x3 + x4) * 0.5
y34 = (y3 + y4) * 0.5
x123 = (x12 + x23) * 0.5
y123 = (y12 + y23) * 0.5
x234 = (x23 + x34) * 0.5
y234 = (y23 + y34) * 0.5
x1234 = (x123 + x234) * 0.5
y1234 = (y123 + y234) * 0.5
tesselate_bezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1)
tesselate_bezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1)
end
def draw_bezier(x1, y1, x2, y2, x3, y3, x4, y4)
tesselate_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0)
@image.line(x1, y1, @points[0][0], @points[0][1], C_WHITE)
@points.each_cons(2) do |p1, p2|
@image.line(p1[0], p1[1], p2[0], p2[1], C_WHITE)
end
end
end
class Slider
attr_reader :pos
def initialize
@pos = 0.5
@btn = Sprite.new(@pos * 629, 430, Image.new(10, 40, C_YELLOW))
@mouse = Sprite.new(0, 0)
@mouse.collision = [0, 0]
@drag = false
@dx = 0
end
def update
if Input.mouse_push?(M_LBUTTON)
@mouse.x, @mouse.y = Input.mouse_x, Input.mouse_y
if @mouse === @btn
@drag = true
@dx = Input.mouse_x - @pos * 629
end
elsif !Input.mouse_down?(M_LBUTTON)
@drag = false
end
if @drag
@pos = (Input.mouse_x - @dx) / 629
@pos = 0.0 if @pos < 0.0
@pos = 1.0 if @pos > 1.0
@btn.x = @pos * 629
end
end
def draw
Window.draw_line(0, 450, 639, 450, C_YELLOW)
@btn.draw
end
end
class Handle < Sprite
def initialize(x, y, image)
super
@mouse = Sprite.new(0, 0)
@mouse.collision = [0, 0]
@drag = false
@dx = 0
@dy = 0
end
def update
if Input.mouse_push?(M_LBUTTON)
@mouse.x, @mouse.y = Input.mouse_x, Input.mouse_y
if @mouse === self
@drag = true
@dx = Input.mouse_x - self.x
@dy = Input.mouse_y - self.y
end
elsif !Input.mouse_down?(M_LBUTTON)
@drag = false
end
if @drag
self.x, self.y = Input.mouse_x - @dx, Input.mouse_y - @dy
end
end
end
Anchor = Handle
x1, y1, x2, y2, x3, y3, x4, y4 = 50, 240, 300, 10, 150, 400, 600, 240
bd = BezierDrawer.new
bd.draw_bezier(x1, y1, x2, y2, x3, y3, x4, y4)
slider = Slider.new
anchor1 = Anchor.new(x1-2, y1-2, Image.new(5, 5, C_BLUE))
handle1 = Handle.new(x2-2, y2-2, Image.new(5, 5, C_GREEN))
handle2 = Handle.new(x3-2, y3-2, Image.new(5, 5, C_GREEN))
anchor2 = Anchor.new(x4-2, y4-2, Image.new(5, 5, C_BLUE))
Window.loop do
anchor1.update
handle2.update
handle1.update
anchor2.update
x1, y1 = anchor1.x+2, anchor1.y+2
x2, y2 = handle1.x+2, handle1.y+2
x3, y3 = handle2.x+2, handle2.y+2
x4, y4 = anchor2.x+2, anchor2.y+2
# ベジェ曲線ひきなおし
bd = BezierDrawer.new
bd.draw_bezier(x1, y1, x2, y2, x3, y3, x4, y4)
Window.draw(0, 0, bd.image)
# 制御線
Window.draw_line(x1, y1, x2, y2, C_YELLOW)
Window.draw_line(x2, y2, x3, y3, C_YELLOW)
Window.draw_line(x3, y3, x4, y4, C_YELLOW)
pos = slider.pos
ipos = 1 - pos
x12 = x1 * ipos + x2 * pos
y12 = y1 * ipos + y2 * pos
x23 = x2 * ipos + x3 * pos
y23 = y2 * ipos + y3 * pos
x34 = x3 * ipos + x4 * pos
y34 = y3 * ipos + y4 * pos
Window.draw_line(x12, y12, x23, y23, C_CYAN)
Window.draw_line(x23, y23, x34, y34, C_CYAN)
Window.draw_box_fill(x12-2, y12-2, x12+2, y12+2, C_YELLOW)
Window.draw_box_fill(x23-2, y23-2, x23+2, y23+2, C_YELLOW)
Window.draw_box_fill(x34-2, y34-2, x34+2, y34+2, C_YELLOW)
x123 = x12 * ipos + x23 * pos
y123 = y12 * ipos + y23 * pos
x234 = x23 * ipos + x34 * pos
y234 = y23 * ipos + y34 * pos
Window.draw_line(x123, y123, x234, y234, C_MAGENTA)
Window.draw_box_fill(x123-2, y123-2, x123+2, y123+2, C_CYAN)
Window.draw_box_fill(x234-2, y234-2, x234+2, y234+2, C_CYAN)
x1234 = x123 * ipos + x234 * pos
y1234 = y123 * ipos + y234 * pos
Window.draw_box_fill(x1234-2, y1234-2, x1234+2, y1234+2, C_MAGENTA)
# アンカー
anchor1.draw
anchor2.draw
# ハンドル
handle1.draw
handle2.draw
# スライダー
slider.update
slider.draw
break if Input.key_push?(K_ESCAPE)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment