Main Menu
  • Welcome to The RPG Maker Resource Kit.

Problem with drawing circles

Started by modern algebra, February 18, 2008, 07:26:59 PM

0 Members and 1 Guest are viewing this topic.

modern algebra

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?