lib/chunky_png/canvas/drawing.rb in chunky_png-1.0.1 vs lib/chunky_png/canvas/drawing.rb in chunky_png-1.1.0

- old
+ new

@@ -27,19 +27,70 @@ # @return [Integer] The composed color. def compose_pixel_unsafe(x, y, color) set_pixel(x, y, ChunkyPNG::Color.compose(color, get_pixel(x, y))) end + # Draws a Bezier curve + # @param [Array, Point] A collection of control points + # @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) + end + + curve_points = Array.new + + t = 0 + n = points.length - 1 + bicof = 0 + + while t <= 100 + cur_p = ChunkyPNG::Point.new(0,0) + + # Generate a float of t. + t_f = t / 100.00 + + 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) + + 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 + + cur_p.x += (t_f ** n) * points[n].x + cur_p.y += (t_f ** n) * points[n].y + + curve_points << cur_p + + bicof = 0 + t += 1 + end + + 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 + + # Draws an anti-aliased line using Xiaolin Wu's algorithm. # # @param [Integer] x0 The x-coordinate of the first control point. # @param [Integer] y0 The y-coordinate of the first control point. # @param [Integer] x1 The x-coordinate of the second control point. # @param [Integer] y1 The y-coordinate of the second control point. # @param [Integer] stroke_color The color to use for this line. # @param [true, false] inclusive Whether to draw the last pixel. - # Set to false when drawing multiplelines in a path. + # Set to false when drawing multiple lines in a path. # @return [ChunkyPNG::Canvas] Itself, with the line drawn. def line_xiaolin_wu(x0, y0, x1, y1, stroke_color, inclusive = true) stroke_color = ChunkyPNG::Color.parse(stroke_color) @@ -236,9 +287,29 @@ line(x0 - length, y0 + y, x0 + length, y0 + y, fill_color) if length > 0 && y > 0 end end return self + end + + private + + # Calculates the binomial coefficient for n over k. + # + # @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) + return 1 if n == k || k == 0 + return n if k == 1 + return -1 if n < k + + # 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 } + + fact_n / (fact_k * fact_n_sub_k) end end end end