Class: Angle
Overview
Class Angle is a utility class that allows * Angle arithmetic ( +,-,,/,,% and unary +,-) Angle comparison ( <=>, hence, <, >, >=, <=, == ) * Conversion to and from degrees and radians * Conversion to string as radians or DMS format
Instance Attribute Summary collapse
-
#angle ⇒ Float
(also: #value)
Stored in radians.
Class Method Summary collapse
-
.decimal_deg(degrees = 0, minutes = 0, seconds = 0, direction = 'N') ⇒ Float
Class level function that converts 4 arguments into decimal degrees.
-
.decimal_deg_from_ary(a) ⇒ Float
Class level function that takes an array of [degress,minutes, seconds, direction] or [degrees,minutes,seconds].
-
.degrees(d = 0) ⇒ Angle
Class level function equivalent to Angle.new(d, false) or just Angle.new(d).
-
.dms(angle, radians = false) ⇒ Array
Class level utility function to return the angle as deg,min,sec Assumes decimal degress unless radians == true .
-
.radians(r = 0) ⇒ Angle
Class level function equivalent to Angle.new(r, true).
Instance Method Summary collapse
-
#%(other) ⇒ Angle, self
Binary mod operator.
-
#*(other) ⇒ Angle, self
Binary multiply operator.
-
#**(other) ⇒ Angle, self
Binary power of operator.
-
#+(other) ⇒ Angle, self
Binary addition operator.
-
#+@ ⇒ Angle, self
unary +.
-
#-(other) ⇒ Angle, self
Binary subtraction operator.
-
#-@ ⇒ Angle, self
Unary -.
-
#/(other) ⇒ Angle, self
Binary division operator.
-
#<=>(other) ⇒ true, false
Provides test for Module Comparable, giving us <,>,<=,>=,== between angles.
-
#abs ⇒ Float
The absolute angle of the angle in radians.
-
#coerce(angle) ⇒ Array
The angle parameter as a Float and the @angle parameter from this class.
-
#initialize(angle = 0, radians = false) ⇒ Angle
constructor
A new instance of Angle.
-
#reverse ⇒ Float
The reverse angle in radians.
-
#sign ⇒ Fixnum
The sign of the angle.
-
#strf(fmt = "%d %2m'%2.4s\"") ⇒ String
formated output of the angle.
-
#to_bearing ⇒ Float
Compass bearings are clockwise, Math angles are counter clockwise.
-
#to_degrees ⇒ Float
(also: #to_deg)
Angle in degrees.
-
#to_dms ⇒ Array
Returns @angle as decimal_degrees Nb.
-
#to_i ⇒ Fixnum
(also: #to_int)
The angle truncated to an integer, in radians.
-
#to_radians ⇒ Float
(also: #to_rad, #to_r, #to_f)
Angle in radians.
-
#to_s(fmt = nil) ⇒ String
Angle in radians as a string.
Constructor Details
#initialize(angle = 0, radians = false) ⇒ Angle
Returns a new instance of Angle.
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/angle.rb', line 18 def initialize(angle = 0, radians = false) # assumes that we are getting an angle in degrees. @angle = if radians == true || radians == :radians angle.to_f # works for String, Fixed, other Angles and for Float. elsif angle.instance_of?(Array) self.class.decimal_deg(*angle).to_radians else angle.to_radians # we have a String and Numeric class version of this. Another Angle will work too. end end |
Instance Attribute Details
#angle ⇒ Float Also known as: value
Returns stored in radians.
12 13 14 |
# File 'lib/angle.rb', line 12 def angle @angle end |
Class Method Details
.decimal_deg(degrees = 0, minutes = 0, seconds = 0, direction = 'N') ⇒ Float
Class level function that converts 4 arguments into decimal degrees.
35 36 37 38 39 40 41 42 43 |
# File 'lib/angle.rb', line 35 def self.decimal_deg(degrees = 0, minutes = 0, seconds = 0, direction = 'N') s = { 'N' => 1, 'S' => -1, 'E' => 1, 'W' => -1, 'n' => 1, 's' => -1, 'e' => 1, 'w' => -1 } sign = s[direction] sign = 1 if sign.nil? # Assume 'N' or 'E' if the direction is not set. # Shouldn't have a negative value for degrees if the direction is specified. # I am defaulting to the degrees sign if it is set, otherwise the direction given sign = -1 if degrees.sign == -1 || (degrees == 0 && (minutes < 0 || (minutes == 0 && seconds < 0))) return sign * (degrees.abs + (minutes / 60.0) + (seconds / 3600.0)) end |
.decimal_deg_from_ary(a) ⇒ Float
Class level function that takes an array of [degress,minutes, seconds, direction] or [degrees,minutes,seconds]
48 49 50 |
# File 'lib/angle.rb', line 48 def self.decimal_deg_from_ary(a) return self.decimal_deg(*a) end |
.degrees(d = 0) ⇒ Angle
Class level function equivalent to Angle.new(d, false) or just Angle.new(d)
92 93 94 |
# File 'lib/angle.rb', line 92 def self.degrees(d = 0) return self.new(d.to_radians, true) end |
.dms(angle, radians = false) ⇒ Array
Class level utility function to return the angle as deg,min,sec Assumes decimal degress unless radians == true . Nb. * That min will be negative if the angle is negative and deg == 0 * That sec will be negative if the angle is negative and deg == 0 && min == 0
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/angle.rb', line 59 def self.dms(angle, radians = false) angle = angle.to_f # means Strings, Numeric, and anything accepting a #to_f will work. angle = angle.to_degrees if radians == true || radians == :radians v = angle.abs deg = v.floor min = ((v - deg) * 60.0).floor sec = ((v - deg - (min / 60.0)) * 3600.0) if angle < 0 if deg == 0 if min == 0 sec = -sec else min = -min end else deg = -deg end end return deg, min, sec end |
.radians(r = 0) ⇒ Angle
Class level function equivalent to Angle.new(r, true)
85 86 87 |
# File 'lib/angle.rb', line 85 def self.radians(r = 0) return self.new(r.to_f, true) # Nb. self is Angle, be we don't Angle.new, as we want subclasses to return their class, not Angle. end |
Instance Method Details
#%(other) ⇒ Angle, self
Binary mod operator. Can add angles and numbers, or two angles.
157 158 159 |
# File 'lib/angle.rb', line 157 def %(other) return self.class.radians(@angle % other) end |
#*(other) ⇒ Angle, self
Binary multiply operator. Can add angles and numbers, or two angles.
136 137 138 |
# File 'lib/angle.rb', line 136 def *(other) self.class.radians(@angle * other) end |
#**(other) ⇒ Angle, self
Binary power of operator. Can add angles and numbers, or two angles.
143 144 145 |
# File 'lib/angle.rb', line 143 def **(other) return self.class.radians(@angle**other) end |
#+(other) ⇒ Angle, self
Binary addition operator. Can add angles and numbers, or two angles.
122 123 124 |
# File 'lib/angle.rb', line 122 def +(other) return self.class.radians(@angle + other) end |
#+@ ⇒ Angle, self
unary +
109 110 111 |
# File 'lib/angle.rb', line 109 def +@ return self.class.radians(@angle) # Nb. Not Angle.new, as we want subclasses to return their class, not Angle. end |
#-(other) ⇒ Angle, self
Binary subtraction operator. Can add angles and numbers, or two angles.
129 130 131 |
# File 'lib/angle.rb', line 129 def -(other) return self.class.radians(@angle - other) end |
#-@ ⇒ Angle, self
Unary -
115 116 117 |
# File 'lib/angle.rb', line 115 def -@ return self.class.radians(-@angle) end |
#/(other) ⇒ Angle, self
Binary division operator. Can add angles and numbers, or two angles.
150 151 152 |
# File 'lib/angle.rb', line 150 def /(other) return self.class.radians(@angle / other) end |
#<=>(other) ⇒ true, false
Provides test for Module Comparable, giving us <,>,<=,>=,== between angles
99 100 101 102 103 104 105 |
# File 'lib/angle.rb', line 99 def <=>(other) @angle <=> if other.instance_of?(Angle) other.angle else other end end |
#abs ⇒ Float
Returns the absolute angle of the angle in radians.
226 227 228 |
# File 'lib/angle.rb', line 226 def abs return @angle.abs end |
#coerce(angle) ⇒ Array
Returns the angle parameter as a Float and the @angle parameter from this class.
216 217 218 |
# File 'lib/angle.rb', line 216 def coerce(angle) return [ Float(angle), @angle ] end |
#reverse ⇒ Float
Returns the reverse angle in radians. i.e. angle + PI (or angle + 180 degrees).
237 238 239 240 241 242 |
# File 'lib/angle.rb', line 237 def reverse if (angle = @angle + Math::PI) > Math::PI * 2 angle -= Math::PI * 2 end return self.class.new(angle, true) end |
#sign ⇒ Fixnum
Returns the sign of the angle. 1 for positive, -1 for negative.
221 222 223 |
# File 'lib/angle.rb', line 221 def sign return @angle.sign end |
#strf(fmt = "%d %2m'%2.4s\"") ⇒ String
formated output of the angle. formats are: * %wd output the degrees as an integer. ** where w is 0, 1, 2 or 3 and represents the field width. * 1 is the default, which indicates that at least 1 digit is displayed * 2 indicates that at least 2 digits are displayed. 1 to 9 will be displayed as 01 0 to 09 0 *** 3 indicates that at least 4 digits are displayed. 10 to 99 will be displayed as 010 0 to 099 0
-
%w.pD outputs degrees as a float.
-
p is the number of decimal places.
-
p is the number of decimal places.
-
-
%wm output minutes as an integer.
-
where the width w is 0, 1 , 2 with similar meaning to %d. p is again the number of decimal places.
-
-
%w.pM outputs minutes as a float .e.g. 01.125'.
-
p is the number of decimal places.
-
-
%wW outputs secs/60 as a float without the leading '0.'. Used with %m like this %2m'%4W , to get minute marker before the decimal places. e.g. -37 001'.1167 rather than -37 001.1167'
-
p is the number of decimal places.
-
-
%w.ps output seconds as a float.
-
where the width w is 1 , 2 with similar meaning to %d. p is again the number of decimal places.
-
-
%N outputs N if the angle is positive and S if the angle is negative.
-
%E outputs E if the angle is positive and W if the angle is negative.
-
%r outputs Radians
-
%% outputs %
Other strings in the format are printed as is.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
# File 'lib/angle.rb', line 288 def strf(fmt = "%d %2m'%2.4s\"") tokens = fmt.scan(/%[0-9.]*[%dmsDMNErW]|[^%]*/) have_dir = have_dms = false tokens.collect! do |t| if t[0, 1] == '%' # format had_dot = false decimals = -1 width = -1 format = nil t[1..-1].scan(/[0-9]+|\.|[0-9]+|[%dmsDMNErW]/) do |t2| case t2 when /[0-9]+/ if had_dot decimals = t2.to_i else width = t2.to_i end when '%', /[Dr]/ format = t2 when /[dmsMwW]/ have_dms = true format = t2 when /[NE]/ have_dir = true format = t2 when '.' had_dot = true else raise "unknown format character '#{t2}'" # shouldn't be able to get here. end end [ :format, width, decimals, format ] else [ :filler, t ] end end deg, min, sec = to_dms if have_dms s = '' tokens.each do |t| if t[0] == :format case t[3] when '%' s += '%' when 'd' s += s_int(deg, t[1], have_dir) when 'D' s += s_float(@angle.to_deg, t[1], t[2], have_dir) when 'm' s += s_int(min, t[1], have_dir) when 'M' s += s_float(min + (sec / 60), t[1], t[2], have_dir) when 'W' s += s_only_places(sec / 60, t[1]) when 's' s += s_float(sec, t[1], t[2], have_dir) when 'r' s += s_float(@angle, t[1], t[2], have_dir) when 'N' s += (@angle < 0 ? 'S' : 'N') when 'E' s += (@angle < 0 ? 'W' : 'E') end else s += t[1] # the fillers. end end return s end |
#to_bearing ⇒ Float
Compass bearings are clockwise, Math angles are counter clockwise.
232 233 234 |
# File 'lib/angle.rb', line 232 def to_bearing return self.class.new((Math::PI * 2) - @angle, true) end |
#to_degrees ⇒ Float Also known as: to_deg
Returns angle in degrees.
162 163 164 |
# File 'lib/angle.rb', line 162 def to_degrees return @angle.to_degrees end |
#to_dms ⇒ Array
Returns @angle as decimal_degrees Nb. * That min will be negative if the angle is negative and deg == 0 * That sec will be negative if the angle is negative and deg == 0 && min == 0
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/angle.rb', line 182 def to_dms d = to_degrees.abs deg = d.floor min = ((d - deg) * 60).floor sec = ((d - deg - (min / 60.0)) * 3600.0) if @angle < 0 if deg == 0 if min == 0 sec = -sec else min = -min end else deg = -deg end end return deg, min, sec end |
#to_i ⇒ Fixnum Also known as: to_int
Returns the angle truncated to an integer, in radians.
207 208 209 |
# File 'lib/angle.rb', line 207 def to_i return to_radians.to_i end |
#to_radians ⇒ Float Also known as: to_rad, to_r, to_f
Returns angle in radians.
171 172 173 |
# File 'lib/angle.rb', line 171 def to_radians return @angle end |
#to_s(fmt = nil) ⇒ String
Returns angle in radians as a string.
246 247 248 249 250 |
# File 'lib/angle.rb', line 246 def to_s(fmt = nil) return to_radians.to_s if fmt.nil? return strf(fmt) end |