Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > [QUIZ] Circle Drawing (#166)

Reply
Thread Tools

[QUIZ] Circle Drawing (#166)

 
 
Matthew Moss
Guest
Posts: n/a
 
      06-13-2008
[Note: parts of this message were removed to make it a legal post.]

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/>.
3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Circle Drawing (#166)

This week we're going to keep it simple... very simple.

Given a radius, draw an ASCII circle.

For example:

ruby circle.rb 7

Should produce a circle of radius 7:

#####
## ##
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
## ##
#####


Note that most fonts do not have a square aspect ratio, which is why the
above output may look like an oval, despite my calculations for a circle. It
is acceptable if your code produces similar output.


However, _for extra credit_ you may support an additional argument that
specifies the aspect ratio (height divided by width).

ruby circle.rb 7 1.4

This should draw a circle of radius 7 with aspect ratio of 1.4. If done
correctly, your output will actually look like a circle (assuming 1.4 is an
accurate measure of the actual aspect ratio).



--
Matthew Moss <(E-Mail Removed)>

 
Reply With Quote
 
 
 
 
Clifford Heath
Guest
Posts: n/a
 
      06-13-2008
Matthew Moss wrote:
> However, _for extra credit_ ...


What about bonus points for using only *integer* arithmetic and no transcendentals?
I wrote C code for that which is hiding somewhere
 
Reply With Quote
 
 
 
 
ThoML
Guest
Posts: n/a
 
      06-14-2008
Hi,

> For example:
>
> ruby circle.rb 7
>
> Should produce a circle of radius 7


I'm not sure if this is intentional but the circle is 15 characters
high. Of course, the line has to be counted in too.
Nevertheless ...

Regards,
Thomas.
 
Reply With Quote
 
Robert Dober
Guest
Posts: n/a
 
      06-14-2008
On Sat, Jun 14, 2008 at 8:09 AM, ThoML <(E-Mail Removed)> wrote:
> Hi,
>
>> For example:
>>
>> ruby circle.rb 7
>>
>> Should produce a circle of radius 7

>
> I'm not sure if this is intentional but the circle is 15 characters
> high. Of course, the line has to be counted in too.
> Nevertheless ...
>
> Regards,
> Thomas.
>
>

2*7 = 15, simple LOL.

I finally decided against it because of simplicity, but I believe that
it is more beautyful to add a "middle" line, especially for small r's.

Robert


--
http://ruby-smalltalk.blogspot.com/

---
As simple as possible, but not simpler.
Albert Einstein

 
Reply With Quote
 
Eric Mahurin
Guest
Posts: n/a
 
      06-14-2008
[Note: parts of this message were removed to make it a legal post.]

On 6/14/08, ThoML <(E-Mail Removed)> wrote:
>
> Hi,
>
>
> > For example:
> >
> > ruby circle.rb 7
> >
> > Should produce a circle of radius 7

>
>
> I'm not sure if this is intentional but the circle is 15 characters
> high. Of course, the line has to be counted in too.
> Nevertheless ...
>
> Regards,
> Thomas.
>
>

Depends on where you are measuring the radius:

outside: 7.5
inside: 6.5 (white space is 13 characters high)
center: 7 (center of bottom to center of top is 14)

 
Reply With Quote
 
Matthew Moss
Guest
Posts: n/a
 
      06-14-2008
> > > For example:
>
> > > =A0 =A0 ruby circle.rb 7

>
> > > Should produce a circle of radius 7

>
> > I'm not sure if this is intentional but the circle is 15 characters
> > high. Of course, the line has to be counted in too.
> > Nevertheless ...

>
> > Regards,
> > Thomas.

>
> Depends on where you are measuring the radius:
>
> outside: 7.5
> inside: 6.5 (white space is 13 characters high)
> center: 7 (center of bottom to center of top is 14)


It was quite intentional that my circle of radius 7 took up 15 rows of
characters. This is a common issue when dealing with computer
graphics: how do you measure distance on a field of discrete elements?

In computer graphics, this is often not a big deal when drawing 3d
objects, especially if you have blurring, other post-processing, or
anti-aliasing going on. It is much more important when you are trying
to render a HUD or UI elements, for example, that you want pixel-
perfect to the artwork provided. Many graphics cards have a setting
you can enable/disable to offset coordinates by half a pixel...
Putting it into the correct mode and setting your texturing unit to
point sampling mode (as opposed to tri-/bi-linear sampling) will give
you pixel-perfect results.

So, in the case as I presented it, I was measuring from the center of
the character cell, which is 15 rows high *if measured from the top
edge of the top row to the bottom edge of the bottom row*. But as Eric
pointed out, it's only 14 if you measure from character cell center's.

 
Reply With Quote
 
Andrea Fazzi
Guest
Posts: n/a
 
      06-15-2008
Matthew Moss ha scritto:
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> The three rules of Ruby Quiz 2:
>
> 1. Please do not post any solutions or spoiler discussion for this
> quiz until 48 hours have passed from the time on this message.
>
> 2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
> permanent, new website is in the works for Ruby Quiz 2. Until then,
> please visit the temporary website at
>
> <http://splatbang.com/rubyquiz/>.
> 3. Enjoy!
>
> Suggestion: A [QUIZ] in the subject of emails about the problem
> helps everyone on Ruby Talk follow the discussion. Please reply to
> the original quiz message, if you can.
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> ## Circle Drawing (#166)
>
> This week we're going to keep it simple... very simple.
>
> Given a radius, draw an ASCII circle.
>
> For example:
>
> ruby circle.rb 7
>
> Should produce a circle of radius 7:
>
> #####
> ## ##
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> ## ##
> #####
>
>
> Note that most fonts do not have a square aspect ratio, which is why the
> above output may look like an oval, despite my calculations for a circle. It
> is acceptable if your code produces similar output.
>
>
> However, _for extra credit_ you may support an additional argument that
> specifies the aspect ratio (height divided by width).
>
> ruby circle.rb 7 1.4
>
> This should draw a circle of radius 7 with aspect ratio of 1.4. If done
> correctly, your output will actually look like a circle (assuming 1.4 is an
> accurate measure of the actual aspect ratio).
>
>
>
>

Here my solution. It is available on pastie:

http://pastie.org/215379
http://pastie.org/215380 (specs)

and it is also attached below:

#
# Solution to Ruby Quiz #166 - Circle Drawing
#
# Usage:
#
# Circle.new(5).to_s
#
# or:
#
# Circle.new(5, 2).to_s
#
#
# or:
#
# Circle.new(5, 2, 'x').to_s
#

# Objects of class Circle draw circles on stdout. The aspect ratio
# correction is actually made drawing an ellipse with semimajor axis
# (a) equals to the given circle radius and semiminor axis (b) equals
# to a / aspect_ratio.
#
# Circle class is responsible to
#
# * initialize a Circle object with the given radius, aspect ratio
# and drawing char
#
# * initialize a canvas
#
# * draw the circle on its internal canvas
#
# * convert the canvas to string for output on stdout
#
class Circle

# cx, cy are the coordinates of the circle's center.
attr_reader :cx, :cy

attr_reader :radius

# w, h are width and height of the canvas
attr_reader :w, :h

# canvas is a linear array that is initially filled with spaces
attr_reader :canvas

#
# Initialize a Circle object passing a value for radius, aspect
# ratio and drawing character.
#
def initialize(radius, aspect_ratio = 1.0, char = '#')

@radius = radius.to_i
@aspect_ratio = aspect_ratio.to_f
@char = char

fail "Error: radius must be > 0" if @radius <= 0
fail "Error: aspect ratio must be > 0" if @aspect_ratio <= 0

# a is the semimajor axis of the ellipse and is equal to the given
# radius
@a = @radius

# b is the semiminor axis of the ellipse and is calculated from a
# and the given aspect ratio
@b = (@a / @aspect_ratio).ceil

# calculate the size of the canvas
@w, @h = (@a + 1) * 2, (@b + 1) * 2

# center coordinates correspond to the size of semiaxis.
@cx, @cy = @a, @b

# initialize the canvas with spaces
@canvas = Array.new(@w * @h, ' ')

# draw ellipse on canvas
draw_ellipse(@a, @b)
end

#
# Print circle on stdout.
#
def to_s
result = ""
(0..@h - 1).each do |line|
result << @canvas[line * @w..line * @w + @w - 1].to_s << "\n"
end
result
end

private

#
# Draw the given character on canvas to the given coordinates.
#
def point(x, y)
@canvas[y * @w + x] = @char
end

#
# Translates and mirrors point (x, y) in the quadrants taking
# advantage of the simmetries in the ellipse. Thus, for a given
# point (x, y) the method plot three other points in the remaining
# quadrants.
#
def plot_four_points(x, y)
point(@cx + x, @cy + y)
point(@cx - x, @cy + y)
point(@cx + x, @cy - y)
point(@cx - x, @cy - y)
end

#
# Draw an ellipse on canvas. This method implements a Bresenham
# based algorithm by John Kennedy
# (http://homepage.smc.edu/kennedy_john/BELIPSE.PDF)
#
# The method calculates two set of points in the first quadrant. The
# first set starts on the positive x axis and wraps in a
# counterclockwise direction until the tangent line slope is equal
# to -1. The second set starts on the positive y axis and wraps in
# a clockwise direction until the tangent line slope is equal to -1.
#
def draw_ellipse(a, b)
a_square = 2 * a**2
b_square = 2 * b**2

draw_first_set(a, b, a_square, b_square)
draw_second_set(a, b, a_square, b_square)
end

#
# The method increments y and decides when to decrement x testing
# the sign of a function. In this case, the decision function is
# (2*ellipse_error+x_change) and its value is calculated
# iteratively.
#
def draw_first_set(a, b, a_square, b_square)

x, y = a, 0
x_change, y_change = b**2 * (1 - 2 * a), a**2
stopping_x, stopping_y = b_square * a, 0
ellipse_error = 0

while(stopping_x >= stopping_y) do
plot_four_points(x, y)
y += 1
stopping_y += a_square
ellipse_error += y_change
y_change += a_square
if (2 * ellipse_error + x_change) > 0
x -= 1
stopping_x -= b_square
ellipse_error += x_change
x_change += b_square
end
end

end

#
# The method increments x and decides when to decrement y testing
# the sign of a function. In this case, the decision function is
# (2*ellipse_error+y_change) and its value is calculated
# iteratively.
#
def draw_second_set(a, b, a_square, b_square)

x, y = 0, b
x_change, y_change = b**2, a**2 * (1 - 2 * b)
stopping_x, stopping_y = 0, a_square * b
ellipse_error = 0

while stopping_x <= stopping_y do
plot_four_points(x, y)
x += 1
stopping_x += b_square
ellipse_error += x_change
x_change += b_square
if (2 * ellipse_error + y_change) > 0
y -= 1
stopping_y -= a_square
ellipse_error += y_change
y_change += a_square
end
end

end

end

# Usage:
#
# ruby circle.rb 7 #=> print out a circle of radius 7
#
# ruby circle.rb 7 1.8 #=> print out a circle of radius 7 and aspect
ratio 1.8
#
# ruby circle.rb 7 1.8 x #=> print out a circle of radius 7 and aspect
ratio 1.8
# using the ascii char 'x'
#

print Circle.new(ARGV[0], ARGV[1] || 1.0, ARGV[2] || '#').to_s if $0 ==
__FILE__

 
Reply With Quote
 
Martin Boese
Guest
Posts: n/a
 
      06-15-2008
Here's my solution, it creates a buffer to draw into, once done it puts it on
the screen:

----- circle.rb -----
class Circle
def initialize(rad, asp)
@rad, @asp = rad, asp # radius, horizontal aspect ratio
@height = rad*2+1 # hight/width of the pictures
@width = (@height*asp).round
@buf = Array.new(@height, ' ').map { |e| Array.new(@width, ' ') }
end
def draw
(0..Math:I*2).step(1/(@rad*@asp*2)) do |deg|
@buf[((@height/2) + (Math::sin(deg)*@rad)).round] \
[((@width/2) + (Math::cos(deg)*@rad*@asp)).round] = '#'
end
@buf.map { |l| l.join + "\n"}.join
end
end
puts Circle.new((ARGV[0] || 7).to_i, (ARGV[1] || 1).to_f).draw
----- end circle.rb -----


On Friday 13 June 2008 14:47:38 Matthew Moss wrote:
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> The three rules of Ruby Quiz 2:
>
> 1. Please do not post any solutions or spoiler discussion for this
> quiz until 48 hours have passed from the time on this message.
>
> 2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
> permanent, new website is in the works for Ruby Quiz 2. Until then,
> please visit the temporary website at
>
> <http://splatbang.com/rubyquiz/>.
> 3. Enjoy!
>
> Suggestion: A [QUIZ] in the subject of emails about the problem
> helps everyone on Ruby Talk follow the discussion. Please reply to
> the original quiz message, if you can.
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> ## Circle Drawing (#166)
>
> This week we're going to keep it simple... very simple.
>
> Given a radius, draw an ASCII circle.
>
> For example:
>
> ruby circle.rb 7
>
> Should produce a circle of radius 7:
>
> #####
> ## ##
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> # #
> ## ##
> #####
>
>
> Note that most fonts do not have a square aspect ratio, which is why the
> above output may look like an oval, despite my calculations for a circle.
> It is acceptable if your code produces similar output.
>
>
> However, _for extra credit_ you may support an additional argument that
> specifies the aspect ratio (height divided by width).
>
> ruby circle.rb 7 1.4
>
> This should draw a circle of radius 7 with aspect ratio of 1.4. If done
> correctly, your output will actually look like a circle (assuming 1.4 is an
> accurate measure of the actual aspect ratio).




 
Reply With Quote
 
ThoML
Guest
Posts: n/a
 
      06-15-2008
My solution makes circles with r=7 14 characters wide. This may be
incorrect. It's rather simple though.

Regards,
Thomas.


def draw_circle(r, ratio=1.0)
lines = []
a = 0.0
t2 = ratio / 2.0
(t2 - 0.1).step(r, ratio) do |h|
b = Math.sqrt(2.0 * h * r - h ** 2).round
u = r - b
v = [1.0, b - a].max
w = (r - u - v) * 2.0
lines << [(m = ' ' * u), (l = '#' * v), ' ' * w, l, m].join
a = b
end
out = lines.join("\n")
puts out
puts out.reverse
end

if __FILE__ == $0
draw_circle(*ARGV.map {|e| e.to_f})
end
 
Reply With Quote
 
Bill Kelly
Guest
Posts: n/a
 
      06-15-2008
My solution follows....

Regards,

Bill


# Ruby Quiz #166
#
# This draws a circle of the specified radius, modified
# by an optional aspect ratio and thickness factor.
#
# implementation notes:
# - for the fun of it, i forbade use of sqrt() and trancendentals
# - the circle is not drawn into a buffer before being printed
# - some values are empirically derived (thickness factor, in parciular)
#
# bugs:
# - the thickness factor causes bloat in small circles

ARGV.length >= 1 or abort("usage: #$0 radius [aspect] [thickness]")

radius = ARGV.shift.to_f
radius > 0 or abort("please provide radius of circle")

aspect = ARGV.shift.to_f
aspect > 0 or aspect = 1.0

thick = ARGV.shift.to_f
thick > 0 or thick = 1.0

hradius = (radius * aspect).ceil + (thick/2.0).round
vradius = radius.ceil + (thick/2.0).round

def get_radius_ch(rsq, dsq, tfactor)
(rsq - dsq).abs <= tfactor ? "*" : " "
end

tfactor = (thick * 4.0) + 2.5
rsq = radius**2
(-vradius).upto(vradius) do |y|
(-hradius).upto(hradius) do |x|
print(get_radius_ch(rsq, (x * (1.0/aspect))**2 + y**2, tfactor))
end
puts
end


# example: radius 7.0, aspect 1.0, thickness 1.0
#
# $ ruby 166_circle.rb 7 1 1
#
# *****
# ** **
# * *
# * *
# * *
# * *
# * *
# * *
# * *
# * *
# * *
# * *
# * *
# ** **
# *****
#
#
# example: radius 10.0, aspect 2.0, thickness 5.0
#
# $ ruby 166_circle.rb 10 2 5
#
#
# *****
# *******************
# *************************
# ******** ********
# ******* *******
# ****** ******
# ***** *****
# ***** *****
# ***** *****
# **** ****
# ***** *****
# ***** *****
# ***** *****
# **** ****
# ***** *****
# ***** *****
# ***** *****
# ****** ******
# ******* *******
# ******** ********
# *************************
# *******************
# *****
#



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SUMMARY] Circle Drawing (#166) Matthew Moss Ruby 0 06-19-2008 01:53 PM
Drawing a circle from the center. pjdd@rediffmail.com Computer Support 4 08-28-2007 08:09 PM
System.Drawing For Drawing Text Images jjbutera@hotmail.com ASP .Net 1 01-09-2006 09:55 PM
Jisatsu circle (Suicide Circle) Col's Cavern DVD Video 1 06-07-2004 06:55 PM
Some rather complex animated line/circle drawing Ben Javascript 7 09-12-2003 02:05 PM



Advertisments