astronoby 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,319 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ module Events
5
+ class ObservationEvents
6
+ STANDARD_ALTITUDE = Angle.from_dms(0, -34, 0)
7
+ RISING_SETTING_HOUR_ANGLE_RATIO_RANGE = (-1..1)
8
+ EARTH_SIDEREAL_ROTATION_RATE = 360.98564736629
9
+
10
+ attr_reader :rising_time,
11
+ :rising_azimuth,
12
+ :transit_time,
13
+ :transit_altitude,
14
+ :setting_time,
15
+ :setting_azimuth
16
+
17
+ # Source:
18
+ # Title: Astronomical Algorithms
19
+ # Author: Jean Meeus
20
+ # Edition: 2nd edition
21
+ # Chapter: 15 - Rising, Transit, and Setting
22
+
23
+ # @param observer [Astronoby::Observer] Observer
24
+ # @param date [Date] Date of the event
25
+ # @param coordinates_of_the_previous_day [Astronoby::Coordinates::Equatorial]
26
+ # Coordinates of the body of the previous day
27
+ # @param coordinates_of_the_day [Astronoby::Coordinates::Equatorial]
28
+ # Coordinates of the body of the day
29
+ # @param coordinates_of_the_next_day [Astronoby::Coordinates::Equatorial]
30
+ # Coordinates of the body of the next day
31
+ # @param additional_altitude [Astronoby::Angle] Additional altitude to the
32
+ # standard altitude adjustment
33
+ def initialize(
34
+ observer:,
35
+ date:,
36
+ coordinates_of_the_previous_day:,
37
+ coordinates_of_the_day:,
38
+ coordinates_of_the_next_day:,
39
+ additional_altitude: Angle.zero
40
+ )
41
+ @observer = observer
42
+ @date = date
43
+ @coordinates_of_the_previous_day = coordinates_of_the_previous_day
44
+ @coordinates_of_the_day = coordinates_of_the_day
45
+ @coordinates_of_the_next_day = coordinates_of_the_next_day
46
+ @standard_altitude = STANDARD_ALTITUDE
47
+ @additional_altitude = additional_altitude
48
+ compute
49
+ end
50
+
51
+ private
52
+
53
+ def compute
54
+ @transit_time = Util::Time.decimal_hour_to_time(@date, initial_transit)
55
+ @transit_altitude = local_horizontal_altitude_transit
56
+
57
+ return if h0.nil?
58
+
59
+ delta_m_rising = (local_horizontal_altitude_rising - shift).degrees./(
60
+ Constants::DEGREES_PER_CIRCLE *
61
+ declination_rising.cos *
62
+ @observer.latitude.cos *
63
+ local_hour_angle_rising.sin
64
+ )
65
+ delta_m_transit = -local_hour_angle_transit.degrees / Constants::DEGREES_PER_CIRCLE
66
+ delta_m_setting = (local_horizontal_altitude_setting - shift).degrees./(
67
+ Constants::DEGREES_PER_CIRCLE *
68
+ declination_setting.cos *
69
+ @observer.latitude.cos *
70
+ local_hour_angle_setting.sin
71
+ )
72
+
73
+ corrected_rising = rationalize_decimal_hours(
74
+ Constants::HOURS_PER_DAY * (initial_rising + delta_m_rising)
75
+ )
76
+ corrected_transit = rationalize_decimal_hours(
77
+ Constants::HOURS_PER_DAY * (initial_transit + delta_m_transit)
78
+ )
79
+ corrected_setting = rationalize_decimal_hours(
80
+ Constants::HOURS_PER_DAY * (initial_setting + delta_m_setting)
81
+ )
82
+
83
+ @rising_time = Util::Time.decimal_hour_to_time(@date, corrected_rising)
84
+ @rising_azimuth = local_horizontal_azimuth_rising
85
+ @transit_time = Util::Time.decimal_hour_to_time(@date, corrected_transit)
86
+ @setting_time = Util::Time.decimal_hour_to_time(@date, corrected_setting)
87
+ @setting_azimuth = local_horizontal_azimuth_setting
88
+ end
89
+
90
+ def observer_longitude
91
+ # Longitude must be treated positively westwards from the meridian of
92
+ # Greenwich, and negatively to the east
93
+ @observer_longitude ||= -@observer.longitude
94
+ end
95
+
96
+ def h0
97
+ @h0 ||= begin
98
+ term1 = shift.sin -
99
+ @observer.latitude.sin * @coordinates_of_the_day.declination.sin
100
+ term2 = @observer.latitude.cos * @coordinates_of_the_day.declination.cos
101
+ ratio = term1 / term2
102
+ return nil unless RISING_SETTING_HOUR_ANGLE_RATIO_RANGE.cover?(ratio)
103
+
104
+ Angle.acos(ratio)
105
+ end
106
+ end
107
+
108
+ def apparent_gst_at_midnight
109
+ @apparent_gst_at_midnight ||= Angle.from_hours(
110
+ GreenwichSiderealTime.from_utc(
111
+ Time.utc(@date.year, @date.month, @date.day)
112
+ ).time
113
+ )
114
+ end
115
+
116
+ def initial_transit
117
+ @initial_transit ||= rationalize_decimal_time(
118
+ (
119
+ @coordinates_of_the_day.right_ascension.degrees +
120
+ observer_longitude.degrees -
121
+ apparent_gst_at_midnight.degrees
122
+ ) / Constants::DEGREES_PER_CIRCLE
123
+ )
124
+ end
125
+
126
+ def initial_rising
127
+ @initial_rising ||=
128
+ rationalize_decimal_time(
129
+ initial_transit - h0.degrees / Constants::DEGREES_PER_CIRCLE
130
+ )
131
+ end
132
+
133
+ def initial_setting
134
+ @initial_setting ||=
135
+ rationalize_decimal_time(
136
+ initial_transit + h0.degrees / Constants::DEGREES_PER_CIRCLE
137
+ )
138
+ end
139
+
140
+ def gst_rising
141
+ @gst_rising ||= Angle.from_degrees(
142
+ apparent_gst_at_midnight.degrees +
143
+ EARTH_SIDEREAL_ROTATION_RATE * initial_rising
144
+ )
145
+ end
146
+
147
+ def gst_transit
148
+ @gst_transit ||= Angle.from_degrees(
149
+ apparent_gst_at_midnight.degrees +
150
+ EARTH_SIDEREAL_ROTATION_RATE * initial_transit
151
+ )
152
+ end
153
+
154
+ def gst_setting
155
+ @gst_setting ||= Angle.from_degrees(
156
+ apparent_gst_at_midnight.degrees +
157
+ EARTH_SIDEREAL_ROTATION_RATE * initial_setting
158
+ )
159
+ end
160
+
161
+ def leap_day_portion
162
+ @leap_day_portion ||= begin
163
+ leap_seconds = Util::Time.terrestrial_universal_time_delta(@date)
164
+ leap_seconds / Constants::SECONDS_PER_DAY
165
+ end
166
+ end
167
+
168
+ def local_hour_angle_rising
169
+ @local_hour_angle_rising ||=
170
+ gst_rising - observer_longitude - right_ascension_rising
171
+ end
172
+
173
+ def local_hour_angle_transit
174
+ @local_hour_angle_transit ||=
175
+ gst_transit - observer_longitude - right_ascension_transit
176
+ end
177
+
178
+ def local_hour_angle_setting
179
+ @local_hour_angle_setting ||=
180
+ gst_setting - observer_longitude - right_ascension_setting
181
+ end
182
+
183
+ def local_horizontal_altitude_rising
184
+ @local_horizontal_altitude_rising ||= Angle.asin(
185
+ @observer.latitude.sin * declination_rising.sin +
186
+ @observer.latitude.cos * declination_rising.cos * local_hour_angle_rising.cos
187
+ )
188
+ end
189
+
190
+ def local_horizontal_azimuth_rising
191
+ @local_horizontal_azimuth_rising ||= begin
192
+ shift = -@standard_altitude
193
+ term1 = declination_rising.sin + shift.sin * @observer.latitude.cos
194
+ term2 = shift.cos * @observer.latitude.cos
195
+ angle = term1 / term2
196
+ Angle.acos(angle)
197
+ end
198
+ end
199
+
200
+ def local_horizontal_altitude_transit
201
+ @local_horizontal_altitude_transit ||= Angle.asin(
202
+ @observer.latitude.sin * declination_transit.sin +
203
+ @observer.latitude.cos * declination_transit.cos * local_hour_angle_transit.cos
204
+ )
205
+ end
206
+
207
+ def local_horizontal_altitude_setting
208
+ @local_horizontal_altitude_setting ||= Angle.asin(
209
+ @observer.latitude.sin * declination_setting.sin +
210
+ @observer.latitude.cos * declination_setting.cos * local_hour_angle_setting.cos
211
+ )
212
+ end
213
+
214
+ def local_horizontal_azimuth_setting
215
+ shift = -@standard_altitude
216
+ term1 = declination_setting.sin + shift.sin * @observer.latitude.cos
217
+ term2 = shift.cos * @observer.latitude.cos
218
+ angle = term1 / term2
219
+ Angle.from_degrees(
220
+ Constants::DEGREES_PER_CIRCLE - Angle.acos(angle).degrees
221
+ )
222
+ end
223
+
224
+ def rationalize_decimal_time(decimal_time)
225
+ decimal_time += 1 if decimal_time.negative?
226
+ decimal_time -= 1 if decimal_time > 1
227
+ decimal_time
228
+ end
229
+
230
+ def rationalize_decimal_hours(decimal_hours)
231
+ decimal_hours += Constants::HOURS_PER_DAY if decimal_hours.negative?
232
+ decimal_hours -= Constants::HOURS_PER_DAY if decimal_hours > Constants::HOURS_PER_DAY
233
+ decimal_hours
234
+ end
235
+
236
+ def right_ascension_rising
237
+ Angle.from_degrees(
238
+ Util::Maths.interpolate(
239
+ [
240
+ @coordinates_of_the_previous_day.right_ascension.degrees,
241
+ @coordinates_of_the_day.right_ascension.degrees,
242
+ @coordinates_of_the_next_day.right_ascension.degrees
243
+ ],
244
+ initial_rising + leap_day_portion
245
+ )
246
+ )
247
+ end
248
+
249
+ def right_ascension_transit
250
+ Angle.from_degrees(
251
+ Util::Maths.interpolate(
252
+ [
253
+ @coordinates_of_the_previous_day.right_ascension.degrees,
254
+ @coordinates_of_the_day.right_ascension.degrees,
255
+ @coordinates_of_the_next_day.right_ascension.degrees
256
+ ],
257
+ initial_transit + leap_day_portion
258
+ )
259
+ )
260
+ end
261
+
262
+ def right_ascension_setting
263
+ Angle.from_degrees(
264
+ Util::Maths.interpolate(
265
+ [
266
+ @coordinates_of_the_previous_day.right_ascension.degrees,
267
+ @coordinates_of_the_day.right_ascension.degrees,
268
+ @coordinates_of_the_next_day.right_ascension.degrees
269
+ ],
270
+ initial_setting + leap_day_portion
271
+ )
272
+ )
273
+ end
274
+
275
+ def declination_rising
276
+ Angle.from_degrees(
277
+ Util::Maths.interpolate(
278
+ [
279
+ @coordinates_of_the_previous_day.declination.degrees,
280
+ @coordinates_of_the_day.declination.degrees,
281
+ @coordinates_of_the_next_day.declination.degrees
282
+ ],
283
+ initial_rising + leap_day_portion
284
+ )
285
+ )
286
+ end
287
+
288
+ def declination_transit
289
+ Angle.from_degrees(
290
+ Util::Maths.interpolate(
291
+ [
292
+ @coordinates_of_the_previous_day.declination.degrees,
293
+ @coordinates_of_the_day.declination.degrees,
294
+ @coordinates_of_the_next_day.declination.degrees
295
+ ],
296
+ initial_transit + leap_day_portion
297
+ )
298
+ )
299
+ end
300
+
301
+ def declination_setting
302
+ Angle.from_degrees(
303
+ Util::Maths.interpolate(
304
+ [
305
+ @coordinates_of_the_previous_day.declination.degrees,
306
+ @coordinates_of_the_day.declination.degrees,
307
+ @coordinates_of_the_next_day.declination.degrees
308
+ ],
309
+ initial_setting + leap_day_portion
310
+ )
311
+ )
312
+ end
313
+
314
+ def shift
315
+ @standard_altitude - @additional_altitude
316
+ end
317
+ end
318
+ end
319
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ module Events
5
+ class TwilightEvents
6
+ TWILIGHTS = [
7
+ CIVIL = :civil,
8
+ NAUTICAL = :nautical,
9
+ ASTRONOMICAL = :astronomical
10
+ ].freeze
11
+
12
+ TWILIGHT_ANGLES = {
13
+ CIVIL => Angle.from_degrees(96),
14
+ NAUTICAL => Angle.from_degrees(102),
15
+ ASTRONOMICAL => Angle.from_degrees(108)
16
+ }.freeze
17
+
18
+ PERIODS_OF_THE_DAY = [
19
+ MORNING = :morning,
20
+ EVENING = :evening
21
+ ].freeze
22
+
23
+ attr_reader :morning_civil_twilight_time,
24
+ :evening_civil_twilight_time,
25
+ :morning_nautical_twilight_time,
26
+ :evening_nautical_twilight_time,
27
+ :morning_astronomical_twilight_time,
28
+ :evening_astronomical_twilight_time
29
+
30
+ def initialize(observer:, sun:)
31
+ @observer = observer
32
+ @sun = sun
33
+ PERIODS_OF_THE_DAY.each do |period_of_the_day|
34
+ TWILIGHT_ANGLES.each do |twilight, _|
35
+ zenith_angle = TWILIGHT_ANGLES[twilight]
36
+ instance_variable_set(
37
+ :"@#{period_of_the_day}_#{twilight}_twilight_time",
38
+ compute(period_of_the_day, zenith_angle)
39
+ )
40
+ end
41
+ end
42
+ end
43
+
44
+ # @param period_of_the_day [Symbol] :morning or :evening
45
+ # @param zenith_angle [Angle] The zenith angle of the twilight
46
+ def time_for_zenith_angle(period_of_the_day:, zenith_angle:)
47
+ unless PERIODS_OF_THE_DAY.include?(period_of_the_day)
48
+ raise IncompatibleArgumentsError,
49
+ "Only #{PERIODS_OF_THE_DAY.join(" or ")} are allowed as period_of_the_day, got #{period_of_the_day}"
50
+ end
51
+
52
+ compute(period_of_the_day, zenith_angle)
53
+ end
54
+
55
+ private
56
+
57
+ # Source:
58
+ # Title: Practical Astronomy with your Calculator or Spreadsheet
59
+ # Authors: Peter Duffett-Smith and Jonathan Zwart
60
+ # Edition: Cambridge University Press
61
+ # Chapter: 50 - Twilight
62
+ def compute(period_of_the_day, zenith_angle)
63
+ period_time = if period_of_the_day == MORNING
64
+ observation_events.rising_time
65
+ else
66
+ observation_events.setting_time
67
+ end
68
+
69
+ hour_angle_at_period = equatorial_coordinates_at_midday
70
+ .compute_hour_angle(time: period_time, longitude: @observer.longitude)
71
+
72
+ term1 = zenith_angle.cos -
73
+ @observer.latitude.sin *
74
+ @equatorial_coordinates_at_midday.declination.sin
75
+ term2 = @observer.latitude.cos *
76
+ equatorial_coordinates_at_midday.declination.cos
77
+ hour_angle_ratio_at_twilight = term1 / term2
78
+
79
+ return unless hour_angle_ratio_at_twilight.between?(-1, 1)
80
+
81
+ hour_angle_at_twilight = Angle.acos(hour_angle_ratio_at_twilight)
82
+ time_sign = -1
83
+
84
+ if period_of_the_day == MORNING
85
+ hour_angle_at_twilight = Angle.from_degrees(
86
+ Constants::DEGREES_PER_CIRCLE - hour_angle_at_twilight.degrees
87
+ )
88
+ time_sign = 1
89
+ end
90
+
91
+ twilight_in_hours =
92
+ time_sign * (hour_angle_at_twilight - hour_angle_at_period).hours *
93
+ GreenwichSiderealTime::SIDEREAL_MINUTE_IN_UT_MINUTE
94
+ twilight_in_seconds = time_sign *
95
+ twilight_in_hours *
96
+ Constants::SECONDS_PER_HOUR
97
+
98
+ (period_time + twilight_in_seconds).round
99
+ end
100
+
101
+ def observation_events
102
+ @observation_events ||= @sun.observation_events(observer: @observer)
103
+ end
104
+
105
+ def midday
106
+ date = @sun.time.to_date
107
+ Time.utc(date.year, date.month, date.day, 12)
108
+ end
109
+
110
+ def sun_at_midday
111
+ Sun.new(time: midday)
112
+ end
113
+
114
+ def equatorial_coordinates_at_midday
115
+ @equatorial_coordinates_at_midday ||= sun_at_midday
116
+ .apparent_ecliptic_coordinates
117
+ .to_apparent_equatorial(epoch: Epoch.from_time(midday))
118
+ end
119
+ end
120
+ end
121
+ end
@@ -9,8 +9,8 @@ module Astronoby
9
9
  # Chapter: 39 - Calculating correction for parallax
10
10
 
11
11
  ASTRONOMICAL_UNIT_IN_METERS = 149_597_870_700
12
- EARTH_FLATTENING_CORRECTION = BigDecimal("0.996647")
13
- EARTH_EQUATORIAL_RADIUS = BigDecimal("6378140")
12
+ EARTH_FLATTENING_CORRECTION = 0.996647
13
+ EARTH_EQUATORIAL_RADIUS = 6378140.0
14
14
 
15
15
  # Equatorial horizontal parallax
16
16
  # @param distance [Numeric] Distance of the body from the center of the
@@ -14,14 +14,14 @@ module Astronoby
14
14
  def self.for_epoch(epoch)
15
15
  return obliquity_of_reference if epoch == EPOCH_OF_REFERENCE
16
16
 
17
- t = (epoch - EPOCH_OF_REFERENCE) / Epoch::DAYS_PER_JULIAN_CENTURY
17
+ t = (epoch - EPOCH_OF_REFERENCE) / Constants::DAYS_PER_JULIAN_CENTURY
18
18
 
19
19
  Angle.from_degrees(
20
20
  obliquity_of_reference.degrees - (
21
21
  46.815 * t -
22
22
  0.0006 * t * t +
23
23
  0.00181 * t * t * t
24
- ) / 3600
24
+ ) / Constants::SECONDS_PER_DEGREE
25
25
  )
26
26
  end
27
27
 
@@ -45,18 +45,20 @@ module Astronoby
45
45
  private
46
46
 
47
47
  def julian_centuries
48
- (@epoch - Epoch::J1900) / Epoch::DAYS_PER_JULIAN_CENTURY
48
+ (@epoch - Epoch::J1900) / Constants::DAYS_PER_JULIAN_CENTURY
49
49
  end
50
50
 
51
51
  def sun_mean_longitude
52
52
  Angle.from_degrees(
53
- (279.6967 + 360.0 * (centuries_a - centuries_a.to_i)) % 360
53
+ (279.6967 + Constants::DEGREES_PER_CIRCLE * (centuries_a - centuries_a.to_i)) %
54
+ Constants::DEGREES_PER_CIRCLE
54
55
  )
55
56
  end
56
57
 
57
58
  def moon_ascending_node_longitude
58
59
  Angle.from_degrees(
59
- (259.1833 - 360.0 * (centuries_b - centuries_b.to_i)) % 360
60
+ (259.1833 - Constants::DEGREES_PER_CIRCLE * (centuries_b - centuries_b.to_i)) %
61
+ Constants::DEGREES_PER_CIRCLE
60
62
  )
61
63
  end
62
64
 
@@ -3,14 +3,14 @@
3
3
  module Astronoby
4
4
  class Observer
5
5
  DEFAULT_ELEVATION = 0
6
- DEFAULT_TEMPERATURE = BigDecimal("283.15")
7
- PRESSURE_AT_SEA_LEVEL = BigDecimal("1013.25")
8
- PASCAL_PER_MILLIBAR = BigDecimal("0.01")
9
- EARTH_GRAVITATIONAL_ACCELERATION = BigDecimal("9.80665")
10
- MOLAR_MASS_OF_AIR = BigDecimal("0.0289644")
11
- UNIVERSAL_GAS_CONSTANT = BigDecimal("8.31432")
6
+ DEFAULT_TEMPERATURE = 283.15
7
+ PRESSURE_AT_SEA_LEVEL = 1013.25
8
+ PASCAL_PER_MILLIBAR = 0.01
9
+ EARTH_GRAVITATIONAL_ACCELERATION = 9.80665
10
+ MOLAR_MASS_OF_AIR = 0.0289644
11
+ UNIVERSAL_GAS_CONSTANT = 8.31432
12
12
 
13
- attr_reader :latitude, :longitude, :elevation, :temperature
13
+ attr_reader :latitude, :longitude, :elevation, :temperature, :pressure
14
14
 
15
15
  # @param latitude [Angle] geographic latitude of the observer
16
16
  # @param longitude [Angle] geographic longitude of the observer
@@ -31,19 +31,38 @@ module Astronoby
31
31
  @longitude = longitude
32
32
  @elevation = elevation
33
33
  @temperature = temperature
34
- @pressure = pressure
34
+ @pressure = pressure || compute_pressure
35
35
  end
36
36
 
37
- # Compute an estimation of the atmospheric pressure based on the elevation
38
- # and temperature
39
- #
40
- # @return [BigDecimal] the atmospheric pressure in millibars.
41
- def pressure
42
- @pressure ||= PRESSURE_AT_SEA_LEVEL * pressure_ratio
37
+ def ==(other)
38
+ return false unless other.is_a?(self.class)
39
+
40
+ @latitude == other.latitude &&
41
+ @longitude == other.longitude &&
42
+ @elevation == other.elevation &&
43
+ @temperature == other.temperature &&
44
+ @pressure == other.pressure
45
+ end
46
+ alias_method :eql?, :==
47
+
48
+ def hash
49
+ [
50
+ self.class,
51
+ @latitude,
52
+ @longitude,
53
+ @elevation,
54
+ @temperature,
55
+ @pressure
56
+ ].hash
43
57
  end
44
58
 
45
59
  private
46
60
 
61
+ # @return [Float] the atmospheric pressure in millibars.
62
+ def compute_pressure
63
+ @pressure ||= PRESSURE_AT_SEA_LEVEL * pressure_ratio
64
+ end
65
+
47
66
  # Source:
48
67
  # Barometric formula
49
68
  # https://en.wikipedia.org/wiki/Barometric_formula
@@ -45,7 +45,7 @@ module Astronoby
45
45
  private
46
46
 
47
47
  def matrix_for_epoch(epoch)
48
- t = (epoch - Epoch::DEFAULT_EPOCH) / Epoch::DAYS_PER_JULIAN_CENTURY
48
+ t = (epoch - Epoch::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
49
49
 
50
50
  zeta = Angle.from_degrees(
51
51
  0.6406161 * t + 0.0000839 * t * t + 0.000005 * t * t * t
@@ -3,11 +3,13 @@
3
3
  module Astronoby
4
4
  class GreenwichSiderealTime
5
5
  JULIAN_CENTURIES_EXPONENTS = [
6
- BigDecimal("6.697374558"),
7
- BigDecimal("2400.051336"),
8
- BigDecimal("0.000025862")
6
+ 6.697374558,
7
+ 2400.051336,
8
+ 0.000025862
9
9
  ].freeze
10
10
 
11
+ SIDEREAL_MINUTE_IN_UT_MINUTE = 0.9972695663
12
+
11
13
  attr_reader :date, :time
12
14
 
13
15
  # Source:
@@ -18,20 +20,20 @@ module Astronoby
18
20
  def self.from_utc(utc)
19
21
  date = utc.to_date
20
22
  julian_day = utc.to_date.ajd
21
- t = (julian_day - Epoch::J2000) / Epoch::DAYS_PER_JULIAN_CENTURY
23
+ t = (julian_day - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
22
24
  t0 = (
23
25
  (JULIAN_CENTURIES_EXPONENTS[0] +
24
26
  (JULIAN_CENTURIES_EXPONENTS[1] * t) +
25
- (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % 24
27
+ (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % Constants::HOURS_PER_DAY
26
28
  ).abs
27
29
 
28
30
  ut_in_hours = utc.hour +
29
- utc.min / 60.0 +
30
- (utc.sec + utc.subsec) / 3600.0
31
+ utc.min / Constants::MINUTES_PER_HOUR +
32
+ (utc.sec + utc.subsec) / Constants::SECONDS_PER_HOUR
31
33
 
32
- gmst = BigDecimal("1.002737909") * ut_in_hours + t0
33
- gmst += 24 if gmst.negative?
34
- gmst -= 24 if gmst > 24
34
+ gmst = 1.002737909 * ut_in_hours + t0
35
+ gmst += Constants::HOURS_PER_DAY if gmst.negative?
36
+ gmst -= Constants::HOURS_PER_DAY if gmst > Constants::HOURS_PER_DAY
35
37
 
36
38
  new(date: date, time: gmst)
37
39
  end
@@ -49,38 +51,25 @@ module Astronoby
49
51
  def to_utc
50
52
  date = @date
51
53
  julian_day = @date.ajd
52
- t = (julian_day - Epoch::J2000) / Epoch::DAYS_PER_JULIAN_CENTURY
54
+ t = (julian_day - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
53
55
 
54
56
  t0 = (
55
57
  (JULIAN_CENTURIES_EXPONENTS[0] +
56
58
  (JULIAN_CENTURIES_EXPONENTS[1] * t) +
57
- (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % 24
59
+ (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % Constants::HOURS_PER_DAY
58
60
  ).abs
59
61
 
60
62
  a = @time - t0
61
- a += 24 if a.negative?
62
- a -= 24 if a > 24
63
+ a += Constants::HOURS_PER_DAY if a.negative?
64
+ a -= Constants::HOURS_PER_DAY if a > Constants::HOURS_PER_DAY
63
65
 
64
- utc = BigDecimal("0.9972695663") * a
66
+ utc = SIDEREAL_MINUTE_IN_UT_MINUTE * a
65
67
 
66
- decimal_hour_to_time(date, utc)
68
+ Util::Time.decimal_hour_to_time(date, utc)
67
69
  end
68
70
 
69
71
  def to_lst(longitude:)
70
72
  LocalSiderealTime.from_gst(gst: self, longitude: longitude)
71
73
  end
72
-
73
- private
74
-
75
- def decimal_hour_to_time(date, decimal)
76
- absolute_hour = decimal.abs
77
- hour = absolute_hour.floor
78
- decimal_minute = 60 * (absolute_hour - hour)
79
- absolute_decimal_minute = (60 * (absolute_hour - hour)).abs
80
- minute = decimal_minute.floor
81
- second = 60 * (absolute_decimal_minute - absolute_decimal_minute.floor)
82
-
83
- ::Time.utc(date.year, date.month, date.day, hour, minute, second).round
84
- end
85
74
  end
86
75
  end
@@ -12,8 +12,8 @@ module Astronoby
12
12
  def self.from_gst(gst:, longitude:)
13
13
  date = gst.date
14
14
  time = gst.time + longitude.hours
15
- time += 24 if time.negative?
16
- time -= 24 if time > 24
15
+ time += Constants::HOURS_PER_DAY if time.negative?
16
+ time -= Constants::HOURS_PER_DAY if time > Constants::HOURS_PER_DAY
17
17
 
18
18
  new(date: date, time: time, longitude: longitude)
19
19
  end
@@ -32,8 +32,8 @@ module Astronoby
32
32
  def to_gst
33
33
  date = @date
34
34
  time = @time - @longitude.hours
35
- time += 24 if time.negative?
36
- time -= 24 if time > 24
35
+ time += Constants::HOURS_PER_DAY if time.negative?
36
+ time -= Constants::HOURS_PER_DAY if time > Constants::HOURS_PER_DAY
37
37
 
38
38
  GreenwichSiderealTime.new(date: date, time: time)
39
39
  end