astronoby 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,249 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class MoonPhasesPeriodicTerms
5
+ # Lunar Solution ELP 2000-82B (Chapront-Touze+, 1988)
6
+
7
+ # Source:
8
+ # Title: Astronomical Algorithms
9
+ # Author: Jean Meeus
10
+ # Edition: 2nd edition
11
+ # Chapter: 49 - Phases of the Moon
12
+
13
+ # @param julian_centuries [Float] Julian centuries
14
+ # @param time [Float] Time
15
+ # @param eccentricity_correction [Float] Eccentricity correction
16
+ # @param moon_mean_anomaly [Float] Moon mean anomaly
17
+ # @param sun_mean_anomaly [Float] Sun mean anomaly
18
+ # @param moon_argument_of_latitude [Float] Moon argument of latitude
19
+ # @param longitude_of_the_ascending_node [Float] Longitude of the ascending node
20
+ def initialize(
21
+ julian_centuries:,
22
+ time:,
23
+ eccentricity_correction:,
24
+ moon_mean_anomaly:,
25
+ sun_mean_anomaly:,
26
+ moon_argument_of_latitude:,
27
+ longitude_of_the_ascending_node:
28
+
29
+ )
30
+ @julian_centuries = julian_centuries
31
+ @time = time
32
+ @eccentricity_correction = eccentricity_correction
33
+ @moon_mean_anomaly = moon_mean_anomaly
34
+ @sun_mean_anomaly = sun_mean_anomaly
35
+ @moon_argument_of_latitude = moon_argument_of_latitude
36
+ @longitude_of_the_ascending_node = longitude_of_the_ascending_node
37
+ end
38
+
39
+ # @return [Float] New moon correction
40
+ def new_moon_correction
41
+ ecc = @eccentricity_correction
42
+ mma = @moon_mean_anomaly.radians
43
+ sma = @sun_mean_anomaly.radians
44
+ maol = @moon_argument_of_latitude.radians
45
+ lotan = @longitude_of_the_ascending_node.radians
46
+ [
47
+ [-0.40720, mma],
48
+ [0.17241 * ecc, sma],
49
+ [0.01608, 2 * mma],
50
+ [0.01039, 2 * maol],
51
+ [0.00739 * ecc, mma - sma],
52
+ [-0.00514 * ecc, mma + sma],
53
+ [0.00208 * ecc * ecc, 2 * sma],
54
+ [-0.00111, mma - 2 * maol],
55
+ [-0.00057, mma + 2 * maol],
56
+ [0.00056 * ecc, 2 * mma + sma],
57
+ [-0.00042, 3 * mma],
58
+ [0.00042 * ecc, sma + 2 * maol],
59
+ [0.00038 * ecc, sma - 2 * maol],
60
+ [-0.00024 * ecc, 2 * mma - sma],
61
+ [-0.00017, lotan],
62
+ [-0.00007, mma + 2 * sma],
63
+ [0.00004, 2 * mma - 2 * maol],
64
+ [0.00004, 3 * sma],
65
+ [0.00003, mma + sma - 2 * maol],
66
+ [0.00003, 2 * mma + 2 * maol],
67
+ [-0.00003, mma + sma + 2 * maol],
68
+ [0.00003, mma - sma + 2 * maol],
69
+ [-0.00002, mma - sma - 2 * maol],
70
+ [-0.00002, 3 * mma + sma],
71
+ [0.00002, 4 * mma]
72
+ ].map { _1.first * Math.sin(_1.last) }.sum
73
+ end
74
+
75
+ # @return [Float] First quarter correction
76
+ def first_quarter_correction
77
+ first_and_last_quarter_correction + first_and_last_quarter_final_correction
78
+ end
79
+
80
+ # @return [Float] Full moon correction
81
+ def full_moon_correction
82
+ ecc = @eccentricity_correction
83
+ mma = @moon_mean_anomaly.radians
84
+ sma = @sun_mean_anomaly.radians
85
+ maol = @moon_argument_of_latitude.radians
86
+ lotan = @longitude_of_the_ascending_node.radians
87
+ [
88
+ [-0.40614, mma],
89
+ [0.17302 * ecc, sma],
90
+ [0.01614, 2 * mma],
91
+ [0.01043, 2 * maol],
92
+ [0.00734 * ecc, mma - sma],
93
+ [-0.00515 * ecc, mma + sma],
94
+ [0.00209 * ecc * ecc, 2 * sma],
95
+ [-0.00111, mma - 2 * maol],
96
+ [-0.00057, mma + 2 * maol],
97
+ [0.00056 * ecc, 2 * mma + sma],
98
+ [-0.00042, 3 * mma],
99
+ [0.00042 * ecc, sma + 2 * maol],
100
+ [0.00038 * ecc, sma - 2 * maol],
101
+ [-0.00024 * ecc, 2 * mma - sma],
102
+ [-0.00017, lotan],
103
+ [-0.00007, mma + 2 * sma],
104
+ [0.00004, 2 * mma - 2 * maol],
105
+ [0.00004, 3 * sma],
106
+ [0.00003, mma + sma - 2 * maol],
107
+ [0.00003, 2 * mma + 2 * maol],
108
+ [-0.00003, mma + sma + 2 * maol],
109
+ [0.00003, mma - sma + 2 * maol],
110
+ [-0.00002, mma - sma - 2 * maol],
111
+ [-0.00002, 3 * mma + sma],
112
+ [0.00002, 4 * mma]
113
+ ].map { _1.first * Math.sin(_1.last) }.sum
114
+ end
115
+
116
+ # @return [Float] Last quarter correction
117
+ def last_quarter_correction
118
+ first_and_last_quarter_correction - first_and_last_quarter_final_correction
119
+ end
120
+
121
+ # @return [Float] Additional corrections
122
+ def additional_corrections
123
+ [
124
+ [0.000325, a1],
125
+ [0.000165, a2],
126
+ [0.000164, a3],
127
+ [0.000126, a4],
128
+ [0.000110, a5],
129
+ [0.000062, a6],
130
+ [0.000060, a7],
131
+ [0.000056, a8],
132
+ [0.000047, a9],
133
+ [0.000042, a10],
134
+ [0.000040, a11],
135
+ [0.000037, a12],
136
+ [0.000035, a13],
137
+ [0.000023, a14]
138
+ ].map { _1.first * _1.last.sin }.sum
139
+ end
140
+
141
+ private
142
+
143
+ def a1
144
+ Angle.from_degrees(
145
+ (
146
+ 299.77 +
147
+ 0.107408 * @time -
148
+ 0.009173 * @julian_centuries**2
149
+ ) % 360
150
+ )
151
+ end
152
+
153
+ def a2
154
+ Angle.from_degrees (251.88 + 0.016321 * @time) % 360
155
+ end
156
+
157
+ def a3
158
+ Angle.from_degrees (251.83 + 26.651886 * @time) % 360
159
+ end
160
+
161
+ def a4
162
+ Angle.from_degrees (349.42 + 36.412478 * @time) % 360
163
+ end
164
+
165
+ def a5
166
+ Angle.from_degrees (84.66 + 18.206239 * @time) % 360
167
+ end
168
+
169
+ def a6
170
+ Angle.from_degrees (141.74 + 53.303771 * @time) % 360
171
+ end
172
+
173
+ def a7
174
+ Angle.from_degrees (207.14 + 2.453732 * @time) % 360
175
+ end
176
+
177
+ def a8
178
+ Angle.from_degrees (154.84 + 7.306860 * @time) % 360
179
+ end
180
+
181
+ def a9
182
+ Angle.from_degrees (34.52 + 27.261239 * @time) % 360
183
+ end
184
+
185
+ def a10
186
+ Angle.from_degrees (207.19 + 0.121824 * @time) % 360
187
+ end
188
+
189
+ def a11
190
+ Angle.from_degrees (291.34 + 1.844379 * @time) % 360
191
+ end
192
+
193
+ def a12
194
+ Angle.from_degrees (161.72 + 24.198154 * @time) % 360
195
+ end
196
+
197
+ def a13
198
+ Angle.from_degrees (239.56 + 25.513099 * @time) % 360
199
+ end
200
+
201
+ def a14
202
+ Angle.from_degrees (331.55 + 3.592518 * @time) % 360
203
+ end
204
+
205
+ def first_and_last_quarter_final_correction
206
+ 0.00306 -
207
+ 0.00038 * @eccentricity_correction * @sun_mean_anomaly.cos +
208
+ 0.00026 * @moon_mean_anomaly.cos -
209
+ 0.00002 * (@moon_mean_anomaly - @sun_mean_anomaly).cos +
210
+ 0.00002 * (@moon_mean_anomaly + @sun_mean_anomaly).cos +
211
+ 0.00002 * Math.cos(2 * @moon_argument_of_latitude.radians)
212
+ end
213
+
214
+ def first_and_last_quarter_correction
215
+ ecc = @eccentricity_correction
216
+ mma = @moon_mean_anomaly.radians
217
+ sma = @sun_mean_anomaly.radians
218
+ maol = @moon_argument_of_latitude.radians
219
+ lotan = @longitude_of_the_ascending_node.radians
220
+ [
221
+ [-0.62801, mma],
222
+ [0.17172 * ecc, sma],
223
+ [-0.01183, mma + sma],
224
+ [0.00862, 2 * mma],
225
+ [0.00804, 2 * maol],
226
+ [0.00454 * ecc, mma - sma],
227
+ [0.00204 * ecc**2, 2 * sma],
228
+ [-0.00180, mma - 2 * maol],
229
+ [-0.00070, mma + 2 * maol],
230
+ [-0.00040, 3 * mma],
231
+ [-0.00034 * ecc, 2 * mma - sma],
232
+ [0.00032 * ecc, sma + 2 * maol],
233
+ [0.00032, sma - 2 * maol],
234
+ [-0.00028 * ecc**2, mma + 2 * sma],
235
+ [0.00027 * ecc, 2 * mma + sma],
236
+ [-0.00017, lotan],
237
+ [-0.00005, mma - sma - 2 * maol],
238
+ [0.00004, 2 * mma + 2 * maol],
239
+ [-0.00004, mma + sma + 2 * maol],
240
+ [0.00004, mma - 2 * sma],
241
+ [0.00003, mma + sma - 2 * maol],
242
+ [0.00003, 3 * sma],
243
+ [0.00002, 2 * mma - 2 * maol],
244
+ [0.00002, mma - sma + 2 * maol],
245
+ [-0.00002, 3 * mma + sma]
246
+ ].map { _1.first * Math.sin(_1.last) }.sum
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,335 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class Moon
5
+ SEMIDIAMETER_VARIATION = 0.7275
6
+ MEAN_GEOCENTRIC_DISTANCE = Astronoby::Distance.from_meters(385_000_560)
7
+
8
+ # Source:
9
+ # Title: Astronomical Algorithms
10
+ # Author: Jean Meeus
11
+ # Edition: 2nd edition
12
+ # Chapter: 49 - Phases of the Moon
13
+
14
+ # @param year [Integer] Requested year
15
+ # @param month [Integer] Requested month
16
+ # @return [Array<Astronoby::MoonPhase>] Moon phases for the requested year
17
+ def self.monthly_phase_events(year:, month:)
18
+ Events::MoonPhases.phases_for(year: year, month: month)
19
+ end
20
+
21
+ def initialize(time:)
22
+ @time = time
23
+ end
24
+
25
+ # @return [Astronoby::Coordinates::Ecliptic] Apparent ecliptic coordinates
26
+ # of the Moon
27
+ def apparent_ecliptic_coordinates
28
+ @ecliptic_coordinates ||= begin
29
+ latitude = Astronoby::Angle.from_degrees(
30
+ (latitude_terms + additive_latitude_terms) *
31
+ EphemerideLunaireParisienne::DEGREES_UNIT
32
+ )
33
+
34
+ longitude = mean_longitude + Astronoby::Angle.from_degrees(
35
+ (longitude_terms + additive_longitude_terms) *
36
+ EphemerideLunaireParisienne::DEGREES_UNIT
37
+ ) + nutation
38
+
39
+ Coordinates::Ecliptic.new(
40
+ latitude: latitude,
41
+ longitude: longitude
42
+ )
43
+ end
44
+ end
45
+
46
+ # Source:
47
+ # Title: Astronomical Algorithms
48
+ # Author: Jean Meeus
49
+ # Edition: 2nd edition
50
+ # Chapter: 47 - Position of the Moon
51
+
52
+ # @return [Astronoby::Coordinates::Equatorial] Apparent geocentric
53
+ # equatorial coordinates of the Moon
54
+ def apparent_equatorial_coordinates
55
+ @apparent_equatorial_coordinates ||=
56
+ apparent_ecliptic_coordinates
57
+ .to_apparent_equatorial(epoch: Epoch.from_time(@time))
58
+ end
59
+
60
+ def horizontal_coordinates(observer:)
61
+ apparent_topocentric_equatorial_coordinates =
62
+ Astronoby::GeocentricParallax.for_equatorial_coordinates(
63
+ observer: observer,
64
+ time: @time,
65
+ coordinates: apparent_equatorial_coordinates,
66
+ distance: distance
67
+ )
68
+
69
+ apparent_topocentric_equatorial_coordinates.to_horizontal(
70
+ observer: observer,
71
+ time: @time
72
+ )
73
+ end
74
+
75
+ # @return [Astronoby::Distance] Distance between the Earth and the Moon centers
76
+ def distance
77
+ @distance ||= Astronoby::Distance.from_meters(
78
+ (MEAN_GEOCENTRIC_DISTANCE.meters + distance_terms).round
79
+ )
80
+ end
81
+
82
+ # @return [Angle] Moon's mean longitude
83
+ def mean_longitude
84
+ @mean_longitude ||= Angle.from_degrees(
85
+ (
86
+ 218.3164477 +
87
+ 481267.88123421 * elapsed_centuries -
88
+ 0.0015786 * elapsed_centuries**2 +
89
+ elapsed_centuries**3 / 538841 -
90
+ elapsed_centuries**4 / 65194000
91
+ ) % 360
92
+ )
93
+ end
94
+
95
+ # @return [Angle] Moon's mean elongation
96
+ def mean_elongation
97
+ @mean_elongation ||= Angle.from_degrees(
98
+ (
99
+ 297.8501921 +
100
+ 445267.1114034 * elapsed_centuries -
101
+ 0.0018819 * elapsed_centuries**2 +
102
+ elapsed_centuries**3 / 545868 -
103
+ elapsed_centuries**4 / 113065000
104
+ ) % 360
105
+ )
106
+ end
107
+
108
+ # @return [Angle] Moon's mean anomaly
109
+ def mean_anomaly
110
+ @mean_anomaly ||= Angle.from_degrees(
111
+ (
112
+ 134.9633964 +
113
+ 477198.8675055 * elapsed_centuries +
114
+ 0.0087414 * elapsed_centuries**2 +
115
+ elapsed_centuries**3 / 69699 -
116
+ elapsed_centuries**4 / 14712000
117
+ ) % 360
118
+ )
119
+ end
120
+
121
+ # @return [Angle] Moon's argument of latitude
122
+ def argument_of_latitude
123
+ @argument_of_latitude ||= Angle.from_degrees(
124
+ (
125
+ 93.2720950 +
126
+ 483202.0175233 * elapsed_centuries -
127
+ 0.0036539 * elapsed_centuries**2 -
128
+ elapsed_centuries**3 / 3526000
129
+ ) % 360
130
+ )
131
+ end
132
+
133
+ # Source:
134
+ # Title: Astronomical Algorithms
135
+ # Author: Jean Meeus
136
+ # Edition: 2nd edition
137
+ # Chapter: 48 - Illuminated Fraction of the Moon's Disk
138
+
139
+ # @return [Angle] Moon's phase angle
140
+ def phase_angle
141
+ @phase_angle ||= begin
142
+ sun_apparent_equatorial_coordinates = sun
143
+ .apparent_ecliptic_coordinates
144
+ .to_apparent_equatorial(epoch: Epoch.from_time(@time))
145
+ moon_apparent_equatorial_coordinates = apparent_equatorial_coordinates
146
+ geocentric_elongation = Angle.acos(
147
+ sun_apparent_equatorial_coordinates.declination.sin *
148
+ moon_apparent_equatorial_coordinates.declination.sin +
149
+ sun_apparent_equatorial_coordinates.declination.cos *
150
+ moon_apparent_equatorial_coordinates.declination.cos *
151
+ (
152
+ sun_apparent_equatorial_coordinates.right_ascension -
153
+ moon_apparent_equatorial_coordinates.right_ascension
154
+ ).cos
155
+ )
156
+
157
+ term1 = sun.earth_distance.km * geocentric_elongation.sin
158
+ term2 = distance.km - sun.earth_distance.km * geocentric_elongation.cos
159
+ angle = Angle.atan(term1 / term2)
160
+ Astronoby::Util::Trigonometry
161
+ .adjustement_for_arctangent(term1, term2, angle)
162
+ end
163
+ end
164
+
165
+ # @return [Float] Moon's illuminated fraction
166
+ def illuminated_fraction
167
+ @illuminated_fraction ||= (1 + phase_angle.cos) / 2
168
+ end
169
+
170
+ # @param observer [Astronoby::Observer] Observer of the event
171
+ # @return [Astronoby::Events::ObservationEvents] Moon's observation events
172
+ def observation_events(observer:)
173
+ today = @time.to_date
174
+ leap_seconds = Util::Time.terrestrial_universal_time_delta(today)
175
+ yesterday = today.prev_day
176
+ yesterday_midnight_terrestrial_time =
177
+ Time.utc(yesterday.year, yesterday.month, yesterday.day) - leap_seconds
178
+ today_midnight_terrestrial_time =
179
+ Time.utc(today.year, today.month, today.day) - leap_seconds
180
+ tomorrow = today.next_day
181
+ tomorrow_midnight_terrestrial_time =
182
+ Time.utc(tomorrow.year, tomorrow.month, tomorrow.day) - leap_seconds
183
+
184
+ coordinates_of_the_previous_day = self.class
185
+ .new(time: yesterday_midnight_terrestrial_time)
186
+ .apparent_equatorial_coordinates
187
+ coordinates_of_the_day = self.class
188
+ .new(time: today_midnight_terrestrial_time)
189
+ .apparent_equatorial_coordinates
190
+ coordinates_of_the_next_day = self.class
191
+ .new(time: tomorrow_midnight_terrestrial_time)
192
+ .apparent_equatorial_coordinates
193
+ additional_altitude = -Angle.from_degrees(
194
+ SEMIDIAMETER_VARIATION *
195
+ GeocentricParallax.angle(distance: distance).degrees
196
+ )
197
+
198
+ Events::ObservationEvents.new(
199
+ observer: observer,
200
+ date: today,
201
+ coordinates_of_the_previous_day: coordinates_of_the_previous_day,
202
+ coordinates_of_the_day: coordinates_of_the_day,
203
+ coordinates_of_the_next_day: coordinates_of_the_next_day,
204
+ additional_altitude: additional_altitude
205
+ )
206
+ end
207
+
208
+ private
209
+
210
+ def terrestrial_time
211
+ @terrestrial_time ||= begin
212
+ delta = Util::Time.terrestrial_universal_time_delta(@time)
213
+ @time + delta
214
+ end
215
+ end
216
+
217
+ def julian_date
218
+ Epoch.from_time(terrestrial_time)
219
+ end
220
+
221
+ def elapsed_centuries
222
+ (julian_date - Epoch::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
223
+ end
224
+
225
+ def sun
226
+ @sun ||= Sun.new(time: @time)
227
+ end
228
+
229
+ def sun_mean_anomaly
230
+ @sun_mean_anomaly ||= sun.mean_anomaly
231
+ end
232
+
233
+ def a1
234
+ @a1 ||= Angle.from_degrees(
235
+ (119.75 + 131.849 * elapsed_centuries) % 360
236
+ )
237
+ end
238
+
239
+ def a2
240
+ @a2 ||= Angle.from_degrees(
241
+ (53.09 + 479264.290 * elapsed_centuries) % 360
242
+ )
243
+ end
244
+
245
+ def a3
246
+ @a3 ||= Angle.from_degrees(
247
+ (313.45 + 481266.484 * elapsed_centuries) % 360
248
+ )
249
+ end
250
+
251
+ def eccentricity_correction
252
+ @eccentricity_correction ||=
253
+ 1 - 0.002516 * elapsed_centuries - 0.0000074 * elapsed_centuries**2
254
+ end
255
+
256
+ def latitude_terms
257
+ @latitude_terms ||=
258
+ Astronoby::EphemerideLunaireParisienne
259
+ .periodic_terms_for_moon_latitude
260
+ .inject(0) do |sum, terms|
261
+ value = terms[4] * Math.sin(
262
+ terms[0] * mean_elongation.radians +
263
+ terms[1] * sun_mean_anomaly.radians +
264
+ terms[2] * mean_anomaly.radians +
265
+ terms[3] * argument_of_latitude.radians
266
+ )
267
+
268
+ value *= eccentricity_correction if terms[1].abs == 1
269
+ value *= eccentricity_correction**2 if terms[1].abs == 2
270
+
271
+ sum + value
272
+ end
273
+ end
274
+
275
+ def additive_latitude_terms
276
+ @additive_latitude_terms ||=
277
+ -2235 * mean_longitude.sin +
278
+ 382 * a3.sin +
279
+ 175 * (a1 - argument_of_latitude).sin +
280
+ 175 * (a1 + argument_of_latitude).sin +
281
+ 127 * (mean_longitude - mean_anomaly).sin -
282
+ 115 * (mean_longitude + mean_anomaly).sin
283
+ end
284
+
285
+ def longitude_terms
286
+ @longitude_terms ||=
287
+ Astronoby::EphemerideLunaireParisienne
288
+ .periodic_terms_for_moon_longitude_and_distance
289
+ .inject(0) do |sum, terms|
290
+ value = terms[4] * Math.sin(
291
+ terms[0] * mean_elongation.radians +
292
+ terms[1] * sun_mean_anomaly.radians +
293
+ terms[2] * mean_anomaly.radians +
294
+ terms[3] * argument_of_latitude.radians
295
+ )
296
+
297
+ value *= eccentricity_correction if terms[1].abs == 1
298
+ value *= eccentricity_correction**2 if terms[1].abs == 2
299
+
300
+ sum + value
301
+ end
302
+ end
303
+
304
+ def additive_longitude_terms
305
+ @additive_longitude_terms ||=
306
+ 3958 * a1.sin +
307
+ 1962 * (mean_longitude - argument_of_latitude).sin +
308
+ 318 * a2.sin
309
+ end
310
+
311
+ def distance_terms
312
+ @distance_terms ||=
313
+ EphemerideLunaireParisienne
314
+ .periodic_terms_for_moon_longitude_and_distance
315
+ .inject(0) do |sum, terms|
316
+ value = terms[5] * Math.cos(
317
+ terms[0] * mean_elongation.radians +
318
+ terms[1] * sun_mean_anomaly.radians +
319
+ terms[2] * mean_anomaly.radians +
320
+ terms[3] * argument_of_latitude.radians
321
+ )
322
+
323
+ value *= eccentricity_correction if terms[1].abs == 1
324
+ value *= eccentricity_correction**2 if terms[1].abs == 2
325
+
326
+ sum + value
327
+ end
328
+ end
329
+
330
+ def nutation
331
+ @nutation ||=
332
+ Astronoby::Nutation.for_ecliptic_longitude(epoch: julian_date)
333
+ end
334
+ end
335
+ end
@@ -101,13 +101,12 @@ module Astronoby
101
101
 
102
102
  # Computes the Sun's horizontal coordinates
103
103
  #
104
- # @param latitude [Astronoby::Angle] Latitude of the observer
105
- # @param longitude [Astronoby::Angle] Longitude of the observer
104
+ # @param observer [Astronoby::Observer] Observer of the event
106
105
  # @return [Astronoby::Coordinates::Horizontal] Sun's horizontal coordinates
107
- def horizontal_coordinates(latitude:, longitude:)
106
+ def horizontal_coordinates(observer:)
108
107
  apparent_ecliptic_coordinates
109
108
  .to_apparent_equatorial(epoch: epoch)
110
- .to_horizontal(time: @time, latitude: latitude, longitude: longitude)
109
+ .to_horizontal(time: @time, observer: observer)
111
110
  end
112
111
 
113
112
  # @param observer [Astronoby::Observer] Observer of the event
@@ -156,9 +155,11 @@ module Astronoby
156
155
  Events::TwilightEvents.new(sun: self, observer: observer)
157
156
  end
158
157
 
159
- # @return [Numeric] Earth-Sun distance in meters
158
+ # @return [Astronoby::Distance] Earth-Sun distance
160
159
  def earth_distance
161
- SEMI_MAJOR_AXIS_IN_METERS / distance_angular_size_factor
160
+ Distance.from_meters(
161
+ SEMI_MAJOR_AXIS_IN_METERS / distance_angular_size_factor
162
+ )
162
163
  end
163
164
 
164
165
  # @return [Astronoby::Angle] Apparent Sun's angular size
@@ -186,6 +187,14 @@ module Astronoby
186
187
  )
187
188
  end
188
189
 
190
+ # @return [Astronoby::Angle] Sun's mean anomaly
191
+ def mean_anomaly
192
+ Angle.from_degrees(
193
+ (longitude_at_base_epoch - longitude_at_perigee).degrees %
194
+ Constants::DEGREES_PER_CIRCLE
195
+ )
196
+ end
197
+
189
198
  # @return [Astronoby::Angle] Sun's longitude at perigee
190
199
  def longitude_at_perigee
191
200
  Angle.from_degrees(
@@ -211,13 +220,6 @@ module Astronoby
211
220
  )
212
221
  end
213
222
 
214
- def mean_anomaly
215
- Angle.from_degrees(
216
- (longitude_at_base_epoch - longitude_at_perigee).degrees %
217
- Constants::DEGREES_PER_CIRCLE
218
- )
219
- end
220
-
221
223
  def days_since_epoch
222
224
  Epoch::DEFAULT_EPOCH - epoch
223
225
  end
@@ -21,5 +21,11 @@ module Astronoby
21
21
  PI_IN_DEGREES = 180.0
22
22
 
23
23
  EQUATION_OF_TIME_CONSTANT = 0.0057183
24
+
25
+ KILOMETER_IN_METERS = 1_000
26
+ ASTRONOMICAL_UNIT_IN_METERS = 149_597_870_700
27
+ EARTH_EQUATORIAL_RADIUS_IN_METERS = 6378140
28
+
29
+ EARTH_FLATTENING_CORRECTION = 0.996647
24
30
  end
25
31
  end
@@ -28,7 +28,9 @@ module Astronoby
28
28
  Angle.from_hours(ha)
29
29
  end
30
30
 
31
- def to_horizontal(time:, latitude:, longitude:)
31
+ def to_horizontal(time:, observer:)
32
+ latitude = observer.latitude
33
+ longitude = observer.longitude
32
34
  ha = @hour_angle || compute_hour_angle(time: time, longitude: longitude)
33
35
  t0 = @declination.sin * latitude.sin +
34
36
  @declination.cos * latitude.cos * ha.cos
@@ -46,8 +48,7 @@ module Astronoby
46
48
  Horizontal.new(
47
49
  azimuth: azimuth,
48
50
  altitude: altitude,
49
- latitude: latitude,
50
- longitude: longitude
51
+ observer: observer
51
52
  )
52
53
  end
53
54