From 09479bdc456943198cebf4548008d265b2c6a382 Mon Sep 17 00:00:00 2001 From: Alex Clink Date: Thu, 24 Feb 2022 00:02:40 -0500 Subject: [PATCH] Add extremities finding for cubic bezier --- examples/cubic_bezier.cr | 12 ++++++++++++ src/bezier/cubic.cr | 37 +++++++++++++++++++++++++++++++++++++ src/sprite/draw_curve.cr | 4 ++-- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/examples/cubic_bezier.cr b/examples/cubic_bezier.cr index 5b0971b..9e50c1c 100644 --- a/examples/cubic_bezier.cr +++ b/examples/cubic_bezier.cr @@ -8,6 +8,8 @@ module PF CTL_COLOR = Pixel.new(0x505050FF) CURVE_COLOR = Pixel.new(0x0077FFFF) SEL_COLOR = Pixel.new(0xFFFF00FF) + EXT_X_COLOR = Pixel.new(0xFF00FFFF) + EXT_Y_COLOR = Pixel.new(0x00FF00FF) @curve : Bezier::Cubic(Float64) @@ -57,6 +59,16 @@ module PF draw_string("Length: " + @curve.length.round(2).to_s, 5, 5, FONT_COLOR) draw_curve(@curve, CURVE_COLOR) + ext_x, ext_y = @curve.extremeties + + ext_x.each do |point| + draw_circle(point.to_i, 3, EXT_X_COLOR) + end + + ext_y.each do |point| + draw_circle(point.to_i, 3, EXT_Y_COLOR) + end + fill_circle(@curve.p0.to_i, 2, POINT_COLOR) fill_circle(@curve.p1.to_i, 2, POINT_COLOR) fill_circle(@curve.p2.to_i, 2, POINT_COLOR) diff --git a/src/bezier/cubic.cr b/src/bezier/cubic.cr index 7774d81..34494a7 100644 --- a/src/bezier/cubic.cr +++ b/src/bezier/cubic.cr @@ -17,6 +17,32 @@ module PF 6 * (1 - t) * (p2 - 2 * p1 + p0) + 6 * t * (p3 - 2 * p2 + p1) end + def self.extremeties(p0 : Number, p1 : Number, p2 : Number, p3 : Number) + a = 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0 + b = 6 * p0 - 12 * p1 + 6 * p2 + c = 3 * p1 - 3 * p0 + + disc = b * b - 4 * a * c + + return Tuple.new unless disc >= 0 + + t1 = (-b + Math.sqrt(disc)) / (2 * a) + t2 = (-b - Math.sqrt(disc)) / (2 * a) + + accept_1 = t1 >= 0 && t1 <= 1 + accept_2 = t2 >= 0 && t2 <= 1 + + if accept_1 && accept_2 + {t1, t2} + elsif accept_1 + {t1} + elsif accept_2 + {t2} + else + {0.5} + end + end + property p0 : Vector2(T) property p1 : Vector2(T) property p2 : Vector2(T) @@ -52,6 +78,17 @@ module PF T.new(-self.class.derivative(t, @p0.x, @p1.x, @p2.x, @p3.x)), ].normalized end + + # Get the points at the extremeties of this curve + def extremeties + txs = self.class.extremeties(@p0.x, @p1.x, @p2.x, @p3.x) + tys = self.class.extremeties(@p0.y, @p1.y, @p2.y, @p3.y) + + txs = txs.map { |t| at(t) } + tys = tys.map { |t| at(t) } + + {txs, tys} + end end end end diff --git a/src/sprite/draw_curve.cr b/src/sprite/draw_curve.cr index 17cde36..f2b8b81 100644 --- a/src/sprite/draw_curve.cr +++ b/src/sprite/draw_curve.cr @@ -1,6 +1,6 @@ module PF class Sprite - def draw_curve(curve : Bezier::Cubic, samples : Int = 100, pixel : Pixel = Pixel.new) + def draw_curve(curve : Bezier::Cubic | Bezier::Quad, samples : Int = 100, pixel : Pixel = Pixel.new) point = curve.p0 0.upto(samples) do |x| t = x / samples @@ -10,7 +10,7 @@ module PF end end - def draw_curve(curve : Bezier::Cubic, pixel : Pixel) + def draw_curve(curve : Bezier::Cubic | Bezier::Quad, pixel : Pixel) draw_curve(curve, pixel: pixel) end end