Class: PerfectShape::Arc

Inherits:
Shape
  • Object
show all
Includes:
RectangularShape
Defined in:
lib/perfect_shape/arc.rb

Overview

Direct Known Subclasses

Ellipse

Constant Summary collapse

TYPES =
[:open, :chord, :pie]

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RectangularShape

#max_x, #max_y

Methods included from PointLocation

#min_x, #min_y

Methods inherited from Shape

#==, #bounding_box, #max_x, #max_y, #min_x, #min_y, #normalize_point

Constructor Details

#initialize(type: :open, x: 0, y: 0, width: 1, height: 1, start: 0, extent: 360, center_x: nil, center_y: nil, radius_x: nil, radius_y: nil) ⇒ Arc

Returns a new instance of Arc.



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/perfect_shape/arc.rb', line 36

def initialize(type: :open, x: 0, y: 0, width: 1, height: 1, start: 0, extent: 360, center_x: nil, center_y: nil, radius_x: nil, radius_y: nil)
  if center_x && center_y && radius_x && radius_y
    self.center_x = center_x
    self.center_y = center_y
    self.radius_x = radius_x
    self.radius_y = radius_y
  else
    super(x: x, y: y, width: width, height: height)
  end
  @type = type
  self.start = start
  self.extent = extent
end

Instance Attribute Details

#extentObject

Returns the value of attribute extent.



34
35
36
# File 'lib/perfect_shape/arc.rb', line 34

def extent
  @extent
end

#startObject

Returns the value of attribute start.



34
35
36
# File 'lib/perfect_shape/arc.rb', line 34

def start
  @start
end

#typeObject

Returns the value of attribute type.



33
34
35
# File 'lib/perfect_shape/arc.rb', line 33

def type
  @type
end

Instance Method Details

#center_xObject



100
101
102
# File 'lib/perfect_shape/arc.rb', line 100

def center_x
  super || @center_x
end

#center_x=(value) ⇒ Object



116
117
118
119
120
# File 'lib/perfect_shape/arc.rb', line 116

def center_x=(value)
  @center_x = BigDecimal(value.to_s)
  @x = nil
  self.radius_x = radius_x if @width
end

#center_yObject



104
105
106
# File 'lib/perfect_shape/arc.rb', line 104

def center_y
  super || @center_y
end

#center_y=(value) ⇒ Object



122
123
124
125
126
# File 'lib/perfect_shape/arc.rb', line 122

def center_y=(value)
  @center_y = BigDecimal(value.to_s)
  @y = nil
  self.radius_y = radius_y if @height
end

#contain?(x_or_point, y = nil) ⇒ @code true

Checks if arc contains point (two-number Array or x, y args)

the arc, false if the point lies outside of the arc’s bounds.

Parameters:

  • x

    The X coordinate of the point to test.

  • y (defaults to: nil)

    The Y coordinate of the point to test.

Returns:

  • (@code true)

    if the point lies within the bound of



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/perfect_shape/arc.rb', line 146

def contain?(x_or_point, y = nil)
  x, y = normalize_point(x_or_point, y)
  return unless x && y
  # Normalize the coordinates compared to the ellipse
  # having a center at 0,0 and a radius of 0.5.
  ellw = width
  return false if (ellw <= 0.0)
  normx = (x - self.x) / ellw - 0.5
  ellh = height
  return false if (ellh <= 0.0)
  normy = (y - self.y) / ellh - 0.5
  dist_sq = (normx * normx) + (normy * normy)
  return false if (dist_sq >= 0.25)
  ang_ext = self.extent.abs
  return true if (ang_ext >= 360.0)
  inarc = contain_angle?(-1*Math.radians_to_degrees(Math.atan2(normy, normx)))
  
  return inarc if type == :pie
  # CHORD and OPEN behave the same way
  if inarc
    return true if ang_ext >= 180.0
    # point must be outside the "pie triangle"
  else
    return false if ang_ext <= 180.0
    # point must be inside the "pie triangle"
  end
  
  # The point is inside the pie triangle iff it is on the same
  # side of the line connecting the ends of the arc as the center.
  angle = Math.degrees_to_radians(-start)
  x1 = Math.cos(angle)
  y1 = Math.sin(angle)
  angle += Math.degrees_to_radians(-extent)
  x2 = Math.cos(angle)
  y2 = Math.sin(angle)
  inside = (Line.relative_counterclockwise(x1, y1, x2, y2, 2*normx, 2*normy) *
                    Line.relative_counterclockwise(x1, y1, x2, y2, 0, 0) >= 0)
  inarc ? !inside : inside
end

#contain_angle?(angle) ⇒ Boolean

Determines whether or not the specified angle is within the angular extents of the arc.

Returns:

  • (Boolean)


188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/perfect_shape/arc.rb', line 188

def contain_angle?(angle)
  ang_ext = self.extent
  backwards = ang_ext < 0.0
  ang_ext = -ang_ext if backwards
  return true if ang_ext >= 360.0

  angle = Math.normalize_degrees(angle) - Math.normalize_degrees(start)
  angle = -angle if backwards
  angle += 360.0 if angle < 0.0

  (angle >= 0.0) && (angle < ang_ext)
end

#heightObject



70
71
72
# File 'lib/perfect_shape/arc.rb', line 70

def height
  @radius_y ? @radius_y * BigDecimal('2.0') : super
end

#height=(value) ⇒ Object

Sets height, normalizing to BigDecimal



95
96
97
98
# File 'lib/perfect_shape/arc.rb', line 95

def height=(value)
  super
  @radius_y = nil
end

#radius_xObject



108
109
110
# File 'lib/perfect_shape/arc.rb', line 108

def radius_x
  @width ? @width/BigDecimal('2.0') : @radius_x
end

#radius_x=(value) ⇒ Object



128
129
130
131
# File 'lib/perfect_shape/arc.rb', line 128

def radius_x=(value)
  @radius_x = BigDecimal(value.to_s)
  @width = nil
end

#radius_yObject



112
113
114
# File 'lib/perfect_shape/arc.rb', line 112

def radius_y
  @height ? @height/BigDecimal('2.0') : @radius_y
end

#radius_y=(value) ⇒ Object



133
134
135
136
# File 'lib/perfect_shape/arc.rb', line 133

def radius_y=(value)
  @radius_y = BigDecimal(value.to_s)
  @height = nil
end

#widthObject



66
67
68
# File 'lib/perfect_shape/arc.rb', line 66

def width
  @radius_x ? @radius_x * BigDecimal('2.0') : super
end

#width=(value) ⇒ Object

Sets width, normalizing to BigDecimal



89
90
91
92
# File 'lib/perfect_shape/arc.rb', line 89

def width=(value)
  super
  @radius_x = nil
end

#xObject



58
59
60
# File 'lib/perfect_shape/arc.rb', line 58

def x
  @center_x && @radius_x ? @center_x - @radius_x : super
end

#x=(value) ⇒ Object

Sets x, normalizing to BigDecimal



75
76
77
78
79
# File 'lib/perfect_shape/arc.rb', line 75

def x=(value)
  super
  @center_x = nil
  self.width = width if @radius_x
end

#yObject



62
63
64
# File 'lib/perfect_shape/arc.rb', line 62

def y
  @center_y && @radius_y ? @center_y - @radius_y : super
end

#y=(value) ⇒ Object

Sets y, normalizing to BigDecimal



82
83
84
85
86
# File 'lib/perfect_shape/arc.rb', line 82

def y=(value)
  super
  @center_y = nil
  self.height = height if @radius_y
end