lib/chunky_png/canvas/drawing.rb



module ChunkyPNG
  class Canvas
    
    module Drawing
      
      # Sets a point on the canvas by composing a pixel with its background color.
      def point(x, y, color)
        self[x, y] = ChunkyPNG::Color.compose(color, self[x, y])
      end
      
      # Draws an anti-aliased line using Xiaolin Wu's algorithm.
      #
      def line_xiaolin_wu(x0, y0, x1, y1, color)
        y0, y1, x0, x1 = y1, y0, x1, x0 if y0 > y1
        dx = x1 - x0
        sx = dx < 0 ? -1 : 1
        dx *= sx
        dy = y1 - y0
        
        if dy == 0 # vertical line
          Range.new(*[x0,x1].sort).each do |x|
            point(x, y0, color)
          end
        elsif dx == 0 # horizontal line
          (y0..y1).each do |y|
            point(x0, y, color)
          end
        elsif dx == dy # diagonal
          x0.step(x1, sx) do |x|
            point(x, y0, color)
            y0 += 1
          end
          
        elsif dy > dx  # vertical displacement
          point(x0, y0, color)
          e_acc = 0          
          e = ((dx << 16) / dy.to_f).round
          (y0...y1-1).each do |i|
            e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xffff
            x0 = x0 + sx if (e_acc <= e_acc_temp)
            w = 0xff - (e_acc >> 8)
            point(x0, y0, ChunkyPNG::Color.fade(color, w)) if include?(x0, y0)
            y0 = y0 + 1
            point(x0 + sx, y0, ChunkyPNG::Color.fade(color, 0xff - w)) if include?(x0 + sx, y0)
          end
          point(x1, y1, color)
          
        else # horizontal displacement
          point(x0, y0, color)
          e_acc = 0
          e = (dy << 16) / dx
          (dx - 1).downto(0) do |i|
            e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xffff
            y0 += 1 if (e_acc <= e_acc_temp)
            w = 0xff - (e_acc >> 8)
            point(x0, y0, ChunkyPNG::Color.fade(color, w)) if include?(x0, y0)
            x0 += sx
            point(x0, y0 + 1, ChunkyPNG::Color.fade(color, 0xff - w)) if include?(x0, y0 + 1)
          end
          point(x1, y1, color)
        end
      end
      
      alias :line :line_xiaolin_wu
      
    end
  end
end