mirror of
https://github.com/SleepingInsomniac/pixelfaucet
synced 2025-02-02 20:45:54 +01:00
Add bezier paths
This commit is contained in:
parent
2cf7bf3df9
commit
ab9176c00d
4 changed files with 184 additions and 0 deletions
90
examples/cubic_bezier.cr
Normal file
90
examples/cubic_bezier.cr
Normal file
|
@ -0,0 +1,90 @@
|
|||
require "../src/game"
|
||||
require "../src/bezier"
|
||||
|
||||
module PF
|
||||
class CubicBezier < PF::Game
|
||||
@curve : BezierCubic(Float64)
|
||||
|
||||
@hover_point : Vector2(Float64)*? = nil
|
||||
@selected_point : Vector2(Float64)*? = nil
|
||||
|
||||
@mouse_pos : Vector2(Int32) = Vector[0, 0]
|
||||
|
||||
def initialize(*args, **kwargs)
|
||||
super
|
||||
@curve = BezierCubic.new(
|
||||
Vector[width * 0.25, height * 0.75],
|
||||
Vector[width * 0.33, height * 0.5],
|
||||
Vector[width * 0.66, height * 0.5],
|
||||
Vector[width * 0.75, height * 0.75]
|
||||
)
|
||||
|
||||
@controller = PF::Controller(Keys).new({
|
||||
Keys::KEY_1 => "p1",
|
||||
Keys::KEY_2 => "p2",
|
||||
Keys::KEY_3 => "p3",
|
||||
Keys::KEY_4 => "p4",
|
||||
|
||||
Keys::UP => "up",
|
||||
Keys::LEFT => "left",
|
||||
Keys::DOWN => "down",
|
||||
Keys::RIGHT => "right",
|
||||
})
|
||||
end
|
||||
|
||||
def update(dt, event)
|
||||
@controller.map_event(event)
|
||||
|
||||
case event
|
||||
when SDL::Event::MouseButton
|
||||
if event.pressed? && event.button == 1
|
||||
@selected_point = @hover_point
|
||||
end
|
||||
|
||||
if event.released? && event.button == 1
|
||||
@selected_point = nil
|
||||
end
|
||||
when SDL::Event::MouseMotion
|
||||
@mouse_pos = Vector[event.x, event.y] // scale
|
||||
|
||||
unless point = @selected_point
|
||||
@hover_point = @curve.points.find { |p| @mouse_pos.distance(p.value) < 4 }
|
||||
else
|
||||
point.value.x = @mouse_pos.x.to_f
|
||||
point.value.y = @mouse_pos.y.to_f
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def draw
|
||||
clear
|
||||
|
||||
draw_line(@curve.p0, @curve.p1, Pixel.new(100, 100, 100))
|
||||
draw_line(@curve.p3, @curve.p2, Pixel.new(100, 100, 100))
|
||||
|
||||
point = @curve.p0
|
||||
0.upto(100) do |x|
|
||||
t = x / 100
|
||||
next_point = @curve.at(t)
|
||||
draw_line(point.to_i, next_point.to_i, Pixel.white)
|
||||
point = next_point
|
||||
end
|
||||
|
||||
fill_circle(@curve.p0.to_i, 1, Pixel.blue)
|
||||
fill_circle(@curve.p1.to_i, 1, Pixel.blue)
|
||||
fill_circle(@curve.p2.to_i, 1, Pixel.blue)
|
||||
fill_circle(@curve.p3.to_i, 1, Pixel.blue)
|
||||
|
||||
draw_string("P1", @curve.p0.to_i, Pixel.white)
|
||||
draw_string("P2", @curve.p1.to_i, Pixel.white)
|
||||
draw_string("P3", @curve.p2.to_i, Pixel.white)
|
||||
draw_string("P4", @curve.p3.to_i, Pixel.white)
|
||||
|
||||
if point = @hover_point
|
||||
draw_circle(point.value.to_i, 5, Pixel.yellow)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
engine = PF::CubicBezier.new(500, 500, 2).run!
|
1
src/bezier.cr
Normal file
1
src/bezier.cr
Normal file
|
@ -0,0 +1 @@
|
|||
require "./bezier/*"
|
48
src/bezier/cubic.cr
Normal file
48
src/bezier/cubic.cr
Normal file
|
@ -0,0 +1,48 @@
|
|||
require "../bezier"
|
||||
|
||||
module PF
|
||||
struct BezierCubic(T)
|
||||
def self.point(t : Float64, p0 : Number, p1 : Number, p2 : Number, p3 : Number)
|
||||
(1 - t) ** 3 * p0 + 3 * (1 - t) ** 2 * t * p1 + 3 * (1 - t) * t ** 2 * p2 + t ** 3 * p3
|
||||
end
|
||||
|
||||
property p0 : Vector2(T)
|
||||
property p1 : Vector2(T)
|
||||
property p2 : Vector2(T)
|
||||
property p3 : Vector2(T)
|
||||
|
||||
def initialize(@p0 : Vector2(T), @p1 : Vector2(T), @p2 : Vector2(T), @p3 : Vector2(T))
|
||||
end
|
||||
|
||||
def [](index : Int)
|
||||
points[index]
|
||||
end
|
||||
|
||||
def points
|
||||
{pointerof(@p0), pointerof(@p1), pointerof(@p2), pointerof(@p3)}
|
||||
end
|
||||
|
||||
# Get the point at percentage *t* of the curve
|
||||
def at(t : Float64)
|
||||
Vector[
|
||||
BezierCubic.point(t, @p0.x, @p1.x, @p2.x, @p3.x),
|
||||
BezierCubic.point(t, @p0.y, @p1.y, @p2.y, @p3.y),
|
||||
]
|
||||
end
|
||||
|
||||
# Get the length of the curve by calculating the length of line segments
|
||||
def length(steps : UInt32 = 10)
|
||||
_length = 0.0
|
||||
seg_p0 = Vector[@p0.x, @p0.y]
|
||||
seg_p1 = uninitialized Vector2(T)
|
||||
|
||||
0.upto(steps) do |n|
|
||||
t = n / steps
|
||||
seg_p1 = at(t)
|
||||
_length += seg_p0.distance(seg_p1)
|
||||
seg_p0 = seg_p1
|
||||
end
|
||||
_length
|
||||
end
|
||||
end
|
||||
end
|
45
src/bezier/quad.cr
Normal file
45
src/bezier/quad.cr
Normal file
|
@ -0,0 +1,45 @@
|
|||
module PF
|
||||
struct BezierQuad(T)
|
||||
def self.point(t : Float64, p0 : Number, p1 : Number, p2 : Number)
|
||||
(1 - t) ** 2 * p0 + 2 * (1 - t) * t * p1 + t ** 2 * p2
|
||||
end
|
||||
|
||||
property p0 : Vector2(T)
|
||||
property p1 : Vector2(T)
|
||||
property p2 : Vector2(T)
|
||||
|
||||
def initialize(@p0 : Vector2(T), @p1 : Vector2(T), @p2 : Vector2(T))
|
||||
end
|
||||
|
||||
def [](index : Int)
|
||||
points[index]
|
||||
end
|
||||
|
||||
def points
|
||||
{pointerof(@p0), pointerof(@p1), pointerof(@p2)}
|
||||
end
|
||||
|
||||
# Get the point at percentage *t* of the curve
|
||||
def at(t : Float64)
|
||||
Vector[
|
||||
BezierQuad.point(t, @p0.x, @p1.x, @p2.x),
|
||||
BezierQuad.point(t, @p0.y, @p1.y, @p2.y),
|
||||
]
|
||||
end
|
||||
|
||||
# Get the length of the curve by calculating the length of line segments
|
||||
def length(steps : UInt32 = 10)
|
||||
_length = 0.0
|
||||
seg_p0 = Vector[@p0.x, @p0.y]
|
||||
seg_p1 = uninitialized Vector2(T)
|
||||
|
||||
0.upto(steps) do |n|
|
||||
t = n / steps
|
||||
seg_p1 = at(t)
|
||||
_length += seg_p0.distance(seg_p1)
|
||||
seg_p0 = seg_p1
|
||||
end
|
||||
_length
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue