The RPG Maker Resource Kit

RMRK RPG Maker Creation => RPG Maker General => General Scripting => Topic started by: modern algebra on February 18, 2008, 07:26:59 PM

Title: Problem with drawing circles
Post by: modern algebra on February 18, 2008, 07:26:59 PM
Okay, so I needed to be able to draw circles on a bitmap easily and so I wrote the following script:


#==============================================================================
# ** Ellipse
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#  Stores an ellipse object.
#==============================================================================

class Ellipse
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # * Public Instance Variables
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  attr_reader   :a # The width of the oval
  attr_reader   :b # The Height of the oval
  attr_reader   :x # the top left x position
  attr_reader   :y # the top left y position
  attr_reader   :h # The x position of the origin
  attr_reader   :k # The y position of the origin
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # * Object Initialization
  #     x : the top left x position
  #     y : the top left y position
  #     a : the width of oval from origin to the side
  #     b : the height of oval from origin. If nil, then a is radius of circle
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  def initialize (x, y, a, b = nil)
    @x = x
    @y = y
    @a = a
    @b = b.nil? ? a : b
    @h = x + a
    @k = y + @b
  end
end

#==============================================================================
# ** Bitmap
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#  Summary of changes:
#     Methods added - outline_rect, outline_ellipse, fill_ellipse
#==============================================================================

class Bitmap
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # * Outline Ellipse
  #    ellipse : the ellipse being drawn
  #    width   : the width of the bar
  #    colour  : the colour of the outline
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  def outline_ellipse (ellipse, width = 1, colour = Color.new (255, 255, 255))
    # For neatness, define local variables a and b to the ellipse variables
    a, b = ellipse.a, ellipse.b
    # Use Ramanujan's approximation of the Circumference of an ellipse
    circumference = Math::PI*(3*(a + b) - Math.sqrt((3*a + b)*(a + 3*b)))
    radian_modifier = (2*Math::PI) / circumference
    for i in 0...circumference
      t = (radian_modifier*i) % (2*Math::PI)
      # Expressed parametrically:
      #   x = h + acos(t), y = k + bsin(t) : where t ranges from 0 to 2pi
      x = (ellipse.h + (a*Math.cos(t))).floor
      y = (ellipse.k + (b*Math.sin(t))).floor
      set_pixel (x, y, colour)
    end
    # Thicken the line
    if width > 1
      ellipse = Ellipse.new (ellipse.x + 1, ellipse.y + 1, ellipse.a - 1, ellipse.b - 1)
      outline_ellipse (ellipse, width - 1, colour)
    end
  end
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # * Fill Ellipse
  #    ellipse : the ellipse being drawn
  #    colour  : the colour of the outline
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  def fill_ellipse (ellipse, colour)
    # For neatness, define local variables a and b to the ellipse variables
    a, b = ellipse.a, ellipse.b
    # Use Ramanujan's approximation of the Circumference of an ellipse
    circumference = Math::PI*(3*(a + b) - Math.sqrt((3*a + b)*(a + 3*b)))
    radian_modifier = (2*Math::PI) / circumference
    for i in 0...(circumference / 2)
      t = (radian_modifier*i) % (2*Math::PI)
      # Expressed parametrically:
      #   x = h + acos(t), y = k + bsin(t) : where t ranges from 0 to 2pi
      x = ellipse.h + (a*Math.cos(t))
      y = ellipse.k - (b*Math.sin(t))
      fill_rect (x, y, 1, 2*(ellipse.k - y), colour)
    end
  end
end


Anyway, the outline_ellipse method does not work properly when you increase the width, and I am wondering if anybody has any ideas on how to fix it. It's possible to just fill_ellipse twice and that will work fine, but part of the point of the method is to not overwrite what is already in the area over which you are drawing the ellipse.

Any suggestions?