Skip to content

Commit

Permalink
Bezier curve code cleanup to conform better with the API and coding s…
Browse files Browse the repository at this point in the history
…tyle.
  • Loading branch information
wvanbergen committed Mar 19, 2011
1 parent 93bf9cd commit cf703d5
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 133 deletions.
85 changes: 31 additions & 54 deletions lib/chunky_png/canvas/drawing.rb
Expand Up @@ -34,47 +34,48 @@ def compose_pixel_unsafe(x, y, color)
# @return [Chunky:PNG::Canvas] Itself, with the curve drawn
def bezier_curve(points, stroke_color = ChunkyPNG::Color::BLACK)

points = ChunkyPNG::Vector(*points)
case points.length
when 0 || 1; return self
when 2; return line( points[0].x, points[0].y, points[1].x, points[1].y, stroke_color )
when 0, 1; return self
when 2; return line(points[0].x, points[0].y, points[1].x, points[1].y, stroke_color)
end

curvePoints = Array.new
curve_points = Array.new

t = 0
n = points.length - 1
bicof = 0
while( t <= 100 )
curP = ChunkyPNG::Point.new(0,0)

while t <= 100
cur_p = ChunkyPNG::Point.new(0,0)

#Generate a float of t.
tF = t / 100.00
# Generate a float of t.
t_f = t / 100.00

curP.x += ( ( 1 - tF )**n ) * points[0].x
curP.y += ( ( 1 - tF )**n ) * points[0].y
cur_p.x += ((1 - t_f) ** n) * points[0].x
cur_p.y += ((1 - t_f) ** n) * points[0].y

for i in 1...points.length - 1
bicof = binomial_coefficient( n , i )
bicof = binomial_coefficient(n , i)

curP.x += ( bicof * ( 1 - tF ) ** ( n - i ) ) * tF**i * points[i].x
curP.y += ( bicof * ( 1 - tF ) ** ( n - i ) ) * tF**i * points[i].y
cur_p.x += (bicof * (1 - t_f) ** (n - i)) * (t_f ** i) * points[i].x
cur_p.y += (bicof * (1 - t_f) ** (n - i)) * (t_f ** i) * points[i].y
i += 1
end

curP.x += tF**n * points[n].x
curP.y += tF**n * points[n].y
cur_p.x += (t_f ** n) * points[n].x
cur_p.y += (t_f ** n) * points[n].y

curve_points << cur_p

curvePoints.push( curP )

bicof = 0
t += 1
end
for i in 0...curvePoints.length - 1
line_xiaolin_wu( curvePoints[i].x.round, curvePoints[i].y.round, curvePoints[i+1].x.round, curvePoints[i+1].y.round, stroke_color)

curve_points.each_cons(2) do |p1, p2|
line_xiaolin_wu(p1.x.round, p1.y.round, p2.x.round, p2.y.round, stroke_color)
end

return self
end

Expand Down Expand Up @@ -297,41 +298,17 @@ def circle(x0, y0, radius, stroke_color = ChunkyPNG::Color::BLACK, fill_color =
# @param [Integer] n first parameter in coeffient (the number on top when looking at the mathematic formula)
# @param [Integer] k k-element, second parameter in coeffient (the number on the bottom when looking at the mathematic formula)
# @return [Integer] The binomial coeffcient of (n,k)
def binomial_coefficient( n, k )
if( n == k || k == 0 )
return 1
end

if( k==1 )
return n
end

if( n < k )
return -1
else

#calculate n
fact_n = 1
for i in 2..n
fact_n *= i
end
def binomial_coefficient(n, k)
return 1 if n == k || k == 0
return n if k == 1
return -1 if n < k

#calcule k
fact_k = 1
for i in 2..k
fact_k *= i
end
# calculate factorials
fact_n = (2..n).inject(1) { |carry, i| carry * i }
fact_k = (2..k).inject(1) { |carry, i| carry * i }
fact_n_sub_k = (2..(n - k)).inject(1) { |carry, i| carry * i }

#Calculate ( n - k)
fact_n_sub_k = 1
for i in 2..(n-k)
fact_n_sub_k *= i
end

return ( fact_n / (fact_k * fact_n_sub_k) )

end

fact_n / (fact_k * fact_n_sub_k)
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions lib/chunky_png/vector.rb
Expand Up @@ -64,6 +64,13 @@ def each_edge(close = true)
yield(points.last, points.first) if close
end

# Returns the point with the given indexof this vector.
# @param [Integer] index The 0-based index of the point in this vector.
# @param [ChunkyPNG::Point] The point instance.
def [](index)
points[index]
end

# Returns an enumerator that will iterate over all the edges in this vector.
# @param (see #each_edge)
# @return [Enumerator] The enumerator that iterates over the edges.
Expand Down
93 changes: 14 additions & 79 deletions spec/chunky_png/canvas/drawing_spec.rb
Expand Up @@ -122,114 +122,49 @@
end

describe '#bezier_curve' do
subject { ChunkyPNG::Canvas.new(24, 24) }
subject { ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE) }

it "should draw a bezier curve starting at the first point" do
points = Array.new
points[0] = ChunkyPNG::Point.new(3,20)
points[1] = ChunkyPNG::Point.new(10,10)
points[2] = ChunkyPNG::Point.new(20,20)
subject.bezier_curve( points )

subject[points[0].x, points[0].y].should == ChunkyPNG::Color::BLACK
subject.bezier_curve('3,20 10,10, 20,20')
subject[3, 20].should == ChunkyPNG::Color::BLACK
end

it "should draw a bezier curve ending at the last point" do
points = Array.new
points[0] = ChunkyPNG::Point.new(3,20)
points[1] = ChunkyPNG::Point.new(10,10)
points[2] = ChunkyPNG::Point.new(20,20)
subject.bezier_curve( points )

subject[points[2].x, points[2].y].should == ChunkyPNG::Color::BLACK
subject.bezier_curve('3,20 10,10, 20,20')
subject[20, 20].should == ChunkyPNG::Color::BLACK
end

it "should draw a bezier curve with a color of green" do
points = Array.new
points[0] = ChunkyPNG::Point.new(3,20)
points[1] = ChunkyPNG::Point.new(10,10)
points[2] = ChunkyPNG::Point.new(20,20)
subject.bezier_curve( points, "green" )

subject[points[0].x, points[0].y].should == ChunkyPNG::Color(:green)
subject.bezier_curve('3,20 10,10, 20,20', :green)
subject[3, 20].should == ChunkyPNG::Color(:green)
end

it "should draw a three point bezier curve" do
pnts = Array.new
canvas = ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE)
pnts[0] = ChunkyPNG::Point.new(01,23)
pnts[1] = ChunkyPNG::Point.new(12,10)
pnts[2] = ChunkyPNG::Point.new(23,23)
canvas.bezier_curve( pnts )
canvas.should == reference_canvas('bezier_three_point')
subject.bezier_curve('1,23 12,10 23,23').should == reference_canvas('bezier_three_point')
end

it "should draw a three point bezier curve flipped" do
pnts = Array.new
canvas = ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE)
pnts[0] = ChunkyPNG::Point.new(01,01)
pnts[1] = ChunkyPNG::Point.new(12,15)
pnts[2] = ChunkyPNG::Point.new(23,01)
canvas.bezier_curve( pnts )
canvas.should == reference_canvas('bezier_three_point_flipped')
subject.bezier_curve('1,1 12,15 23,1').should == reference_canvas('bezier_three_point_flipped')
end

it "should draw a four point bezier curve" do
pnts = Array.new
canvas = ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE)
pnts[0] = ChunkyPNG::Point.new(01,23)
pnts[1] = ChunkyPNG::Point.new(01,05)
pnts[2] = ChunkyPNG::Point.new(22,05)
pnts[3] = ChunkyPNG::Point.new(22,23)
canvas.bezier_curve( pnts )
canvas.should == reference_canvas('bezier_four_point')
subject.bezier_curve('1,23 1,5 22,5 22,23').should == reference_canvas('bezier_four_point')
end

it "should draw a four point bezier curve flipped" do
pnts = Array.new
canvas = ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE)
pnts[0] = ChunkyPNG::Point.new(01,01)
pnts[1] = ChunkyPNG::Point.new(01,19)
pnts[2] = ChunkyPNG::Point.new(22,19)
pnts[3] = ChunkyPNG::Point.new(22,01)
canvas.bezier_curve( pnts )
canvas.should == reference_canvas('bezier_four_point_flipped')
subject.bezier_curve('1,1 1,19 22,19 22,1').should == reference_canvas('bezier_four_point_flipped')
end

it "should draw a four point bezier curve with a shape of an s" do
pnts = Array.new
canvas = ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE)
pnts[0] = ChunkyPNG::Point.new(01,23)
pnts[1] = ChunkyPNG::Point.new(01,05)
pnts[3] = ChunkyPNG::Point.new(22,05)
pnts[2] = ChunkyPNG::Point.new(22,23)
canvas.bezier_curve( pnts )
canvas.should == reference_canvas('bezier_four_point_s')
subject.bezier_curve('1,23 1,5 22,23 22,5').should == reference_canvas('bezier_four_point_s')
end

it "should draw a five point bezier curve" do
pnts = Array.new
canvas = ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE)
pnts[0] = ChunkyPNG::Point.new(10,23)
pnts[1] = ChunkyPNG::Point.new(01,10)
pnts[2] = ChunkyPNG::Point.new(12,05)
pnts[3] = ChunkyPNG::Point.new(23,10)
pnts[4] = ChunkyPNG::Point.new(14,23)
canvas.bezier_curve( pnts )
canvas.should == reference_canvas('bezier_five_point')
subject.bezier_curve('10,23 1,10 12,5 23,10 14,23').should == reference_canvas('bezier_five_point')
end

it "should draw a six point bezier curve" do
pnts = Array.new
canvas = ChunkyPNG::Canvas.new(24, 24, ChunkyPNG::Color::WHITE)
pnts[0] = ChunkyPNG::Point.new(01,23)
pnts[1] = ChunkyPNG::Point.new(04,15)
pnts[2] = ChunkyPNG::Point.new(8,20)
pnts[3] = ChunkyPNG::Point.new(02,02)
pnts[4] = ChunkyPNG::Point.new(23,15)
pnts[5] = ChunkyPNG::Point.new(23,01)
canvas.bezier_curve( pnts )
canvas.should == reference_canvas('bezier_six_point')
subject.bezier_curve('1,23 4,15 8,20 2,2 23,15 23,1').should == reference_canvas('bezier_six_point')
end
end
end

0 comments on commit cf703d5

Please sign in to comment.