Class: Angle

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/angles.rb

Constant Summary collapse

@@PI =

constants

Math::PI
@@TWO_PI =
Math::PI * 2
@@PI_SYMBOL =
"\u03c0"
@@DEGREE_SYMBOL =
"\u00b0"
@@SECONDS_DECIMAL_PLACES =
2
@@ROUND_SECONDS =
10
@@ROUND_TRIG =
12

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(angle = 0, mode = :degrees, display = :readable) ⇒ Angle

initializers



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/angles.rb', line 24

def initialize(angle=0, mode=:degrees, display=:readable)
  @mode = mode
  @display = display

  case mode
    when :degrees
      self.from_radians Angle.normalize_radians(Angle.degrees_to_radians(angle))
    when :radians
      self.from_radians Angle.normalize_radians angle
  end
end

Instance Attribute Details

#angleObject (readonly)

make mode and display attributes mutable



10
11
12
# File 'lib/angles.rb', line 10

def angle
  @angle
end

#displayObject

Returns the value of attribute display.



11
12
13
# File 'lib/angles.rb', line 11

def display
  @display
end

#modeObject

Returns the value of attribute mode.



11
12
13
# File 'lib/angles.rb', line 11

def mode
  @mode
end

Class Method Details

.acos(x) ⇒ Object



272
273
274
# File 'lib/angles.rb', line 272

def self.acos(x)
  Angle.new.from_radians(Math.acos(x))
end

.acot(x) ⇒ Object



292
293
294
# File 'lib/angles.rb', line 292

def self.acot(x)
  degrees(90) - atan(x)
end

.acsc(x) ⇒ Object



286
287
288
289
290
# File 'lib/angles.rb', line 286

def self.acsc(x)
  return nil if x == 0

  asin(1 / x)
end

.asec(x) ⇒ Object



280
281
282
283
284
# File 'lib/angles.rb', line 280

def self.asec(x)
  return nil if x == 0

  acos(1 / x)
end

.asin(x) ⇒ Object

inverse trig functions



268
269
270
# File 'lib/angles.rb', line 268

def self.asin(x)
  Angle.new.from_radians(Math.asin(x))
end

.atan(x) ⇒ Object



276
277
278
# File 'lib/angles.rb', line 276

def self.atan(x)
  Angle.new.from_radians(Math.atan(x))
end

.atan2(y, x) ⇒ Object



296
297
298
# File 'lib/angles.rb', line 296

def self.atan2(y, x)
  Angle.new.from_radians(Math.atan2(y, x))
end

.coefficient_to_degrees(coefficient) ⇒ Object

convert coefficient of pi as rational to degrees as float



150
151
152
# File 'lib/angles.rb', line 150

def self.coefficient_to_degrees(coefficient)
  Angle.normalize_degrees(coefficient.to_f * 180.0)
end

.coefficient_to_radians(coefficient) ⇒ Object

convert coefficient of pi as rational to radians as float



160
161
162
# File 'lib/angles.rb', line 160

def self.coefficient_to_radians(coefficient)
  Angle.normalize_radians(coefficient.to_f * @@PI)
end

.degrees_to_coefficient(degrees) ⇒ Object

convert degrees as float to coefficient of pi as rational



145
146
147
# File 'lib/angles.rb', line 145

def self.degrees_to_coefficient(degrees)
  Angle.radians_to_coefficient(Angle.degrees_to_radians(degrees))
end

.degrees_to_radians(degrees) ⇒ Object

convert degrees as float to radians as float



119
120
121
# File 'lib/angles.rb', line 119

def self.degrees_to_radians(degrees)
  Angle.normalize_radians(degrees.to_f * @@PI / 180)
end

.degrees_to_sexagesimal(degrees) ⇒ Object

convert degrees as float to degrees, minutes, seconds



129
130
131
132
133
134
135
136
# File 'lib/angles.rb', line 129

def self.degrees_to_sexagesimal(degrees)
  degrees = Angle.normalize_degrees(degrees.to_f)
  degrees, remainder = degrees.to_f.modf
  remainder = remainder.round(9)
  minutes, seconds = (remainder * 60).modf
  seconds *= 60
  return degrees, minutes, seconds
end

.normalize_degrees(degrees) ⇒ Object

normalize a value of degrees to [0, 360)



105
106
107
108
109
# File 'lib/angles.rb', line 105

def self.normalize_degrees(degrees)
  degrees -= 360 while degrees >= 360
  degrees += 360 while degrees < 0
  degrees
end

.normalize_radians(radians) ⇒ Object

normalize a value of radians to [0, 2pi)



112
113
114
115
116
# File 'lib/angles.rb', line 112

def self.normalize_radians(radians)
  radians -= @@TWO_PI while radians >= @@TWO_PI
  radians += @@TWO_PI while radians < 0
  radians
end

.radians_to_coefficient(radians) ⇒ Object

convert radians as float to coefficient of pi as rational



155
156
157
# File 'lib/angles.rb', line 155

def self.radians_to_coefficient(radians)
  (radians.to_f / @@PI).to_r
end

.radians_to_degrees(radians) ⇒ Object

convert radians as float to degrees as float



124
125
126
# File 'lib/angles.rb', line 124

def self.radians_to_degrees(radians)
  Angle.normalize_degrees(radians.to_f * 180 / @@PI)
end

.sexagesimal_to_degrees(degrees, minutes, seconds) ⇒ Object

convert degrees, minutes, seconds to degrees as float



139
140
141
142
# File 'lib/angles.rb', line 139

def self.sexagesimal_to_degrees(degrees, minutes, seconds)
  degrees = Angle.normalize_degrees(degrees.to_f)
  degrees + minutes.to_f / 60.0 + seconds.to_f / 3600.0
end

Instance Method Details

#*(number) ⇒ Object



451
452
453
# File 'lib/angles.rb', line 451

def *(number)
  self.clone.from_radians(Angle.normalize_radians(self.radians * number))
end

#+(other_angle) ⇒ Object

operator overloads



443
444
445
# File 'lib/angles.rb', line 443

def +(other_angle)
  self.clone.from_radians(Angle.normalize_radians(self.radians + other_angle.angle))
end

#-(other_angle) ⇒ Object



447
448
449
# File 'lib/angles.rb', line 447

def -(other_angle)
  self.clone.from_radians(Angle.normalize_radians(self.radians - other_angle.angle))
end

#/(number) ⇒ Object



455
456
457
# File 'lib/angles.rb', line 455

def /(number)
  self.clone.from_radians(Angle.normalize_radians(self.radians / number))
end

#<=>(other_angle) ⇒ Object

add comparison operators



460
461
462
# File 'lib/angles.rb', line 460

def <=>(other_angle)
  self.angle <=> other_angle.angle
end

#absObject



431
432
433
434
435
# File 'lib/angles.rb', line 431

def abs
  new_angle = self.clone
  new_angle.from_radians new_angle.angle.abs
  new_angle
end

#abs!Object



437
438
439
# File 'lib/angles.rb', line 437

def abs!
  @angle = @angle.abs
end

#acute?Boolean

trigonometric properties of angle

Returns:

  • (Boolean)


302
303
304
# File 'lib/angles.rb', line 302

def acute?
  self.degrees < 90
end

#cosObject Also known as: cosine



174
175
176
177
# File 'lib/angles.rb', line 174

def cos
  cos = Math.cos(self.radians).round(@@ROUND_TRIG)
  (cos == 0) ? 0 : cos
end

#cotObject Also known as: cotangent



207
208
209
210
211
212
# File 'lib/angles.rb', line 207

def cot
  return nil if self.radians == 0 or self.radians == @@PI
  return 0 if self.radians == @@PI / 2

  1 / self.tan
end

#covercosinObject



234
235
236
# File 'lib/angles.rb', line 234

def covercosin
  1 + self.sin
end

#coversinObject



230
231
232
# File 'lib/angles.rb', line 230

def coversin
  1 - self.sin
end

#crdObject Also known as: chord



216
217
218
# File 'lib/angles.rb', line 216

def crd
  2 * (self / 2).sin
end

#cscObject Also known as: cosecant



191
192
193
194
195
# File 'lib/angles.rb', line 191

def csc
  return nil if self.radians == 0 or self.radians == @@PI

  1 / self.sin
end

#dObject



64
65
66
# File 'lib/angles.rb', line 64

def d
  self.degrees.floor
end

#d=(degrees) ⇒ Object



68
69
70
# File 'lib/angles.rb', line 68

def d=(degrees)
  self.degrees = self.degrees - self.d + degrees
end

#degreesObject



56
57
58
# File 'lib/angles.rb', line 56

def degrees
  Angle.radians_to_degrees(self.radians).to_f
end

#degrees=(degrees) ⇒ Object



60
61
62
# File 'lib/angles.rb', line 60

def degrees=(degrees)
  self.from_degrees degrees
end

#excscObject



262
263
264
# File 'lib/angles.rb', line 262

def excsc
  self.csc - 1
end

#exsecObject



254
255
256
# File 'lib/angles.rb', line 254

def exsec
  self.sec - 1
end

#exsecantObject



258
259
260
# File 'lib/angles.rb', line 258

def exsecant
  self.exsec
end

#from_degrees(degrees) ⇒ Object



36
37
38
39
# File 'lib/angles.rb', line 36

def from_degrees(degrees)
  @angle = Angle.normalize_radians(Angle.degrees_to_radians(degrees))
  self
end

#from_radians(radians) ⇒ Object



41
42
43
44
# File 'lib/angles.rb', line 41

def from_radians(radians)
  @angle = Angle.normalize_radians(radians)
  self
end

#full?Boolean

Returns:

  • (Boolean)


324
325
326
# File 'lib/angles.rb', line 324

def full?
  self.degrees == 0
end

#hacovercosinObject



250
251
252
# File 'lib/angles.rb', line 250

def hacovercosin
  self.covercosin / 2
end

#hacoversinObject



246
247
248
# File 'lib/angles.rb', line 246

def hacoversin
  self.coversin / 2
end

#havercosinObject



242
243
244
# File 'lib/angles.rb', line 242

def havercosin
  self.vercosin / 2
end

#haversinObject



238
239
240
# File 'lib/angles.rb', line 238

def haversin
  self.versin / 2
end

#mObject



80
81
82
# File 'lib/angles.rb', line 80

def m
  self.minutes.floor % 60
end

#m=(minutes) ⇒ Object



84
85
86
# File 'lib/angles.rb', line 84

def m=(minutes)
  self.minutes = self.minutes - self.m + minutes
end

#minutesObject



72
73
74
# File 'lib/angles.rb', line 72

def minutes
  self.degrees * 60
end

#minutes=(minutes) ⇒ Object



76
77
78
# File 'lib/angles.rb', line 76

def minutes=(minutes)
  self.from_degrees minutes.to_f / 60
end

#oblique?Boolean

Returns:

  • (Boolean)


328
329
330
# File 'lib/angles.rb', line 328

def oblique?
  not [0, 90, 180, 270].include? self.degrees
end

#obtuse?Boolean

Returns:

  • (Boolean)


310
311
312
313
# File 'lib/angles.rb', line 310

def obtuse?
  d = self.degrees
  d > 90 and d < 180
end

#radiansObject

getters



48
49
50
# File 'lib/angles.rb', line 48

def radians
  self.angle
end

#radians=(radians) ⇒ Object



52
53
54
# File 'lib/angles.rb', line 52

def radians=(radians)
  self.from_radians radians
end

#reflex?Boolean

Returns:

  • (Boolean)


319
320
321
322
# File 'lib/angles.rb', line 319

def reflex?
  d = self.degrees
  d > 180 and d < 360
end

#right?Boolean

Returns:

  • (Boolean)


306
307
308
# File 'lib/angles.rb', line 306

def right?
  self.degrees == 90
end

#sObject



96
97
98
# File 'lib/angles.rb', line 96

def s
  (self.seconds % 60).round @@ROUND_SECONDS
end

#s=(seconds) ⇒ Object



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

def s=(seconds)
  self.seconds = self.seconds - self.s + seconds
end

#secObject Also known as: secant



199
200
201
202
203
# File 'lib/angles.rb', line 199

def sec
  return nil if self.radians == @@PI / 2

  1 / self.cos
end

#secondsObject



88
89
90
# File 'lib/angles.rb', line 88

def seconds
  (self.minutes * 60).round @@ROUND_SECONDS
end

#seconds=(seconds) ⇒ Object



92
93
94
# File 'lib/angles.rb', line 92

def seconds=(seconds)
  self.from_degrees seconds.to_f / 3600
end

#sinObject Also known as: sine, jiba

trig functions



166
167
168
169
# File 'lib/angles.rb', line 166

def sin
  sin = Math.sin(self.radians).round(@@ROUND_TRIG)
  (sin == 0) ? 0 : sin
end

#straight?Boolean

Returns:

  • (Boolean)


315
316
317
# File 'lib/angles.rb', line 315

def straight?
  self.degrees == 180
end

#tanObject Also known as: tangent, slope



181
182
183
184
185
186
# File 'lib/angles.rb', line 181

def tan
  return nil if self.radians == @@PI / 2 or self.radians == 3 * @@PI / 2

  tan = Math.tan(self.radians).round(@@ROUND_TRIG)
  (tan == 0) ? 0 : tan
end

#to_degreesObject



423
424
425
# File 'lib/angles.rb', line 423

def to_degrees
  Angle.new(Angle.radians_to_degrees(self.radians), mode=:degrees, display=@display)
end

#to_fObject



408
409
410
411
412
413
414
415
416
417
# File 'lib/angles.rb', line 408

def to_f
  case @mode
    when :degrees
      return Angle.radians_to_degrees(self.radians).round(12)
    when :radians
      return self.radians
    else
      return Angle.radians_to_degrees self.radians
  end
end

#to_rObject



419
420
421
# File 'lib/angles.rb', line 419

def to_r
  Angle.radians_to_coefficient(self.radians) / 2
end

#to_radiansObject



427
428
429
# File 'lib/angles.rb', line 427

def to_radians
  Angle.new(self.radians, mode=:radians, display=@display)
end

#to_sObject



397
398
399
400
401
402
403
404
405
406
# File 'lib/angles.rb', line 397

def to_s
  case @mode
    when :degrees
      return to_s_deg
    when :radians
      return to_s_rad
    else
      return to_s_deg
  end
end

#to_s_degObject

output and type conversions



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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/angles.rb', line 334

def to_s_deg
  case @display
    when :readable
      degrees = Angle.radians_to_degrees(self.radians.round(10))
      degrees, minutes, seconds = Angle.degrees_to_sexagesimal(degrees)
      seconds = seconds.round(@@SECONDS_DECIMAL_PLACES)

      output = ''
      output += (@angle < 0 ? '-' : '')
      output += "#{degrees}" + @@DEGREE_SYMBOL

      if minutes > 0 or seconds > 0
        output += "%02.0f" % minutes
        output += "\'"

        if seconds > 0
          seconds, remainder = seconds.modf
          remainder = remainder.round(@@SECONDS_DECIMAL_PLACES)

          if remainder >= 1
            seconds += Integer(remainder).to_f
            remainder -= Integer(remainder).to_f
          end

          output += "%02.0f" % seconds

          if not (remainder == 0 or (remainder.abs < (10.0 ** -@@SECONDS_DECIMAL_PLACES)))
            output += ("#{remainder.round(@@SECONDS_DECIMAL_PLACES)}"[1..-1])
          end

          output += "\""
        end
      end

      return output
    when :decimal
      return Angle.radians_to_degrees(self.radians).to_s
    else
      return Angle.radians_to_degrees(self.radians).to_s
  end
end

#to_s_radObject



376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/angles.rb', line 376

def to_s_rad
  case @display
    when :readable
      coefficient = Angle.radians_to_coefficient(self.radians.round(10))

      return '0' if coefficient.numerator == 0

      output = ''
      output += '-' if @angle < 0
      output += "#{coefficient.numerator}" if coefficient.numerator.abs != 1
      output += @@PI_SYMBOL
      output += "/#{coefficient.denominator}" if coefficient.denominator.abs != 1

      return output
    when :decimal
      self.radians.to_f.to_s
    else
      self.radians.to_f.to_s
  end
end

#vercosinObject



226
227
228
# File 'lib/angles.rb', line 226

def vercosin
  1 + self.cos
end

#versinObject



222
223
224
# File 'lib/angles.rb', line 222

def versin
  1 - self.cos
end