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?