Class: AsciiParadise::Circle

Inherits:
Object
  • Object
show all
Defined in:
lib/ascii_paradise/static_ascii/circle.rb

Overview

AsciiParadise::Circle

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(radius, aspect_ratio = 1.0, char = '#') ⇒ Circle

#

initialize

Initialize a Circle object passing a value for radius, aspect ratio and drawing character.

#


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 52

def initialize(
    radius,
    aspect_ratio = 1.0,
    char         = '#'
  )    
  @radius = radius.to_i
  @aspect_ratio = aspect_ratio.to_f
  @char   = char
  @radius = 10 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).round    
  # ======================================================================= #
  # calculate the size of the canvas
  # ======================================================================= #
  @w, @h = @a * 2 + 1, @b * 2 + 1    
  # ======================================================================= #
  # The 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 the canvas
  # ======================================================================= #
  draw_ellipse(@a, @b)
end

Instance Attribute Details

#cxObject (readonly)

#

cx, cy are the coordinates of the circle’s center.

#


38
39
40
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 38

def cx
  @cx
end

#cyObject (readonly)

Returns the value of attribute cy.



39
40
41
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 39

def cy
  @cy
end

#hObject (readonly)

#

w, h are width and height of the canvas

#


44
45
46
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 44

def h
  @h
end

#radiusObject (readonly)

Returns the value of attribute radius.



40
41
42
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 40

def radius
  @radius
end

#wObject (readonly)

#

w, h are width and height of the canvas

#


44
45
46
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 44

def w
  @w
end

Instance Method Details

#canvas?Boolean Also known as: canvas

#

canvas?

#

Returns:

  • (Boolean)


218
219
220
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 218

def canvas?
  @canvas
end

#draw_ellipse(a, b) ⇒ Object

#

draw_ellipse

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.

#


128
129
130
131
132
133
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 128

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

#draw_first_set(a, b, a_square, b_square) ⇒ Object

#

draw_first_set

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.

#


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 143

def draw_first_set(a, b, a_square, b_square)
  x, y = a, 0
  x_change, y_change = b_square / 2 * (1 - 2 * a), a_square / 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

#draw_second_set(a, b, a_square, b_square) ⇒ Object

#

draw_second_set

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.

#


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 172

def draw_second_set(a, b, a_square, b_square)
  x, y = 0, b
  x_change, y_change = b_square / 2, a_square / 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

#outputObject Also known as: display

#

output

#


209
210
211
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 209

def output
  print to_s
end

#plot_four_points(x, y) ⇒ Object

#

plot_four_points

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.

#


106
107
108
109
110
111
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 106

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

#point(x, y) ⇒ Object

#

point

Draw the given character on canvas to the given coordinates.

#


95
96
97
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 95

def point(x, y)
  @canvas[y * @w + x] = @char
end

#to_sObject

#

to_s

Return the circle-data on as a String.

#


198
199
200
201
202
203
204
# File 'lib/ascii_paradise/static_ascii/circle.rb', line 198

def to_s
  result = ''.dup
  (0..@h - 1).each { |line|
    result << @canvas[line * @w..line * @w + @w - 1].join << "\n"
  }
  result
end