Class: Astronoby::Angle

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

Overview

Represents an angle with radians as its internal representation. Provides conversions between radians, degrees, hours, and sexagesimal formats (DMS and HMS), as well as trigonometric operations.

Examples:

Create an angle from degrees

angle = Astronoby::Angle.from_degrees(180)
angle.radians  # => Math::PI

Create an angle from hours, minutes, seconds

angle = Astronoby::Angle.from_hms(12, 30, 0)

Constant Summary collapse

MIN_PRECISION =
10
FORMATS =
%i[dms hms].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(radians) ⇒ Angle

Returns a new instance of Angle.

Parameters:

  • radians (Numeric)

    the angle in radians



103
104
105
106
# File 'lib/astronoby/angle.rb', line 103

def initialize(radians)
  @radians = radians
  freeze
end

Instance Attribute Details

#radiansNumeric (readonly)

Returns the angle in radians.

Returns:

  • (Numeric)

    the angle in radians



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

def radians
  @radians
end

Class Method Details

.acos(ratio) ⇒ Astronoby::Angle

Returns the arccosine.

Parameters:

  • ratio (Numeric)

    the cosine value (-1..1)

Returns:



86
87
88
89
# File 'lib/astronoby/angle.rb', line 86

def acos(ratio)
  radians = Math.acos(ratio)
  from_radians(radians)
end

.asin(ratio) ⇒ Astronoby::Angle

Returns the arcsine.

Parameters:

  • ratio (Numeric)

    the sine value (-1..1)

Returns:



79
80
81
82
# File 'lib/astronoby/angle.rb', line 79

def asin(ratio)
  radians = Math.asin(ratio)
  from_radians(radians)
end

.atan(ratio) ⇒ Astronoby::Angle

Returns the arctangent.

Parameters:

  • ratio (Numeric)

    the tangent value

Returns:



93
94
95
96
# File 'lib/astronoby/angle.rb', line 93

def atan(ratio)
  radians = Math.atan(ratio)
  from_radians(radians)
end

.from_degree_arcseconds(arcseconds) ⇒ Astronoby::Angle

Returns a new Angle.

Parameters:

  • arcseconds (Numeric)

    the angle in arcseconds

Returns:



43
44
45
# File 'lib/astronoby/angle.rb', line 43

def from_degree_arcseconds(arcseconds)
  from_dms(0, 0, arcseconds)
end

.from_degrees(degrees) ⇒ Astronoby::Angle

Returns a new Angle.

Parameters:

  • degrees (Numeric)

    the angle in degrees

Returns:



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

def from_degrees(degrees)
  radians = degrees / Constants::PI_IN_DEGREES * Math::PI
  from_radians(radians)
end

.from_dms(degree, minute, second) ⇒ Astronoby::Angle

Returns a new Angle.

Parameters:

  • degree (Numeric)

    degrees component (sign determines overall sign)

  • minute (Numeric)

    arcminutes component

  • second (Numeric)

    arcseconds component

Returns:



69
70
71
72
73
74
75
# File 'lib/astronoby/angle.rb', line 69

def from_dms(degree, minute, second)
  sign = degree.negative? ? -1 : 1
  degrees = degree.abs +
    minute / Constants::ARCMINUTES_PER_DEGREE +
    second / Constants::ARCSECONDS_PER_DEGREE
  from_degrees(sign * degrees)
end

.from_hms(hour, minute, second) ⇒ Astronoby::Angle

Returns a new Angle.

Parameters:

  • hour (Numeric)

    hours component

  • minute (Numeric)

    minutes component

  • second (Numeric)

    seconds component

Returns:



58
59
60
61
62
63
# File 'lib/astronoby/angle.rb', line 58

def from_hms(hour, minute, second)
  hours = hour +
    minute / Constants::MINUTES_PER_HOUR +
    second / Constants::SECONDS_PER_HOUR
  from_hours(hours)
end

.from_hours(hours) ⇒ Astronoby::Angle

Returns a new Angle.

Parameters:

  • hours (Numeric)

    the angle in hour-angle hours

Returns:



49
50
51
52
# File 'lib/astronoby/angle.rb', line 49

def from_hours(hours)
  radians = hours * Constants::RADIAN_PER_HOUR
  from_radians(radians)
end

.from_radians(radians) ⇒ Astronoby::Angle

Returns a new Angle, normalized to (-2π, 2π).

Parameters:

  • radians (Numeric)

    the angle in radians

Returns:



29
30
31
32
# File 'lib/astronoby/angle.rb', line 29

def from_radians(radians)
  normalized_radians = radians.remainder(Constants::RADIANS_PER_CIRCLE)
  new(normalized_radians)
end

.zeroAstronoby::Angle

Returns a zero angle.

Returns:



23
24
25
# File 'lib/astronoby/angle.rb', line 23

def zero
  new(0)
end

Instance Method Details

#+(other) ⇒ Astronoby::Angle

Returns the sum.

Parameters:

Returns:



125
126
127
# File 'lib/astronoby/angle.rb', line 125

def +(other)
  self.class.from_radians(radians + other.radians)
end

#-(other) ⇒ Astronoby::Angle

Returns the difference.

Parameters:

Returns:



131
132
133
# File 'lib/astronoby/angle.rb', line 131

def -(other)
  self.class.from_radians(@radians - other.radians)
end

#-@Astronoby::Angle

Returns the negated angle.

Returns:



136
137
138
# File 'lib/astronoby/angle.rb', line 136

def -@
  self.class.from_radians(-@radians)
end

#<=>(other) ⇒ Integer?

Returns -1, 0, or 1; nil if not comparable.

Parameters:

Returns:

  • (Integer, nil)

    -1, 0, or 1; nil if not comparable



177
178
179
180
181
# File 'lib/astronoby/angle.rb', line 177

def <=>(other)
  return unless other.is_a?(self.class)

  radians <=> other.radians
end

#cosFloat

Returns the cosine of the angle.

Returns:

  • (Float)

    the cosine of the angle



146
147
148
# File 'lib/astronoby/angle.rb', line 146

def cos
  Math.cos(radians)
end

#degree_milliarcsecondsFloat

Returns the angle in milliarcseconds.

Returns:

  • (Float)

    the angle in milliarcseconds



114
115
116
# File 'lib/astronoby/angle.rb', line 114

def degree_milliarcseconds
  degrees * Constants::MILLIARCSECONDS_PER_DEGREE
end

#degreesFloat

Returns the angle in degrees.

Returns:

  • (Float)

    the angle in degrees



109
110
111
# File 'lib/astronoby/angle.rb', line 109

def degrees
  @radians * Constants::PI_IN_DEGREES / Math::PI
end

#hashInteger

Returns hash value.

Returns:

  • (Integer)

    hash value



171
172
173
# File 'lib/astronoby/angle.rb', line 171

def hash
  [radians, self.class].hash
end

#hoursFloat

Returns the angle in hour-angle hours.

Returns:

  • (Float)

    the angle in hour-angle hours



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

def hours
  @radians / Constants::RADIAN_PER_HOUR
end

#negative?Boolean

Returns true if the angle is negative.

Returns:

  • (Boolean)

    true if the angle is negative



161
162
163
# File 'lib/astronoby/angle.rb', line 161

def negative?
  radians < 0
end

#positive?Boolean

Returns true if the angle is positive.

Returns:

  • (Boolean)

    true if the angle is positive



156
157
158
# File 'lib/astronoby/angle.rb', line 156

def positive?
  radians > 0
end

#sinFloat

Returns the sine of the angle.

Returns:

  • (Float)

    the sine of the angle



141
142
143
# File 'lib/astronoby/angle.rb', line 141

def sin
  Math.sin(radians)
end

#str(format, precision: 4) ⇒ String

Formats the angle as a string in the given format.

Parameters:

  • format (Symbol)

    :dms or :hms

  • precision (Integer) (defaults to: 4)

    decimal places for seconds

Returns:

  • (String)

    the formatted angle

Raises:



190
191
192
193
194
195
196
197
198
199
# File 'lib/astronoby/angle.rb', line 190

def str(format, precision: 4)
  case format
  when :dms then to_dms.format(precision: precision)
  when :hms then to_hms.format(precision: precision)
  else
    raise UnsupportedFormatError.new(
      "Expected a format between #{FORMATS.join(", ")}, got #{format}"
    )
  end
end

#tanFloat

Returns the tangent of the angle.

Returns:

  • (Float)

    the tangent of the angle



151
152
153
# File 'lib/astronoby/angle.rb', line 151

def tan
  Math.tan(radians)
end

#to_dmsAstronoby::Dms

Returns the angle in degrees, arcminutes, arcseconds.

Returns:



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/astronoby/angle.rb', line 202

def to_dms
  sign = degrees.negative? ? "-" : "+"
  absolute_degrees = degrees.abs
  deg = absolute_degrees.floor
  decimal_minutes = Constants::ARCMINUTES_PER_DEGREE *
    (absolute_degrees - deg)
  absolute_decimal_minutes = (
    Constants::ARCMINUTES_PER_DEGREE * (absolute_degrees - deg)
  ).abs
  minutes = decimal_minutes.floor
  seconds = Constants::SECONDS_PER_MINUTE * (
    absolute_decimal_minutes - absolute_decimal_minutes.floor
  )

  Dms.new(sign, deg, minutes, seconds)
end

#to_hmsAstronoby::Hms

Returns the angle in hours, minutes, seconds.

Returns:



220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/astronoby/angle.rb', line 220

def to_hms
  absolute_hours = hours.abs
  hrs = absolute_hours.floor
  decimal_minutes = Constants::MINUTES_PER_HOUR * (absolute_hours - hrs)
  absolute_decimal_minutes = (
    Constants::MINUTES_PER_HOUR * (absolute_hours - hrs)
  ).abs
  minutes = decimal_minutes.floor
  seconds = Constants::SECONDS_PER_MINUTE * (
    absolute_decimal_minutes - absolute_decimal_minutes.floor
  )

  Hms.new(hrs, minutes, seconds)
end

#zero?Boolean

Returns true if the angle is zero.

Returns:

  • (Boolean)

    true if the angle is zero



166
167
168
# File 'lib/astronoby/angle.rb', line 166

def zero?
  radians.zero?
end