astronoby 0.7.0 → 0.8.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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +87 -3
  4. data/README.md +56 -32
  5. data/UPGRADING.md +50 -21
  6. data/docs/README.md +196 -0
  7. data/docs/angles.md +137 -0
  8. data/docs/celestial_bodies.md +107 -0
  9. data/docs/configuration.md +98 -0
  10. data/docs/coordinates.md +167 -0
  11. data/docs/ephem.md +85 -0
  12. data/docs/equinoxes_solstices_times.md +31 -0
  13. data/docs/glossary.md +152 -0
  14. data/docs/instant.md +139 -0
  15. data/docs/moon_phases.md +79 -0
  16. data/docs/observer.md +65 -0
  17. data/docs/reference_frames.md +138 -0
  18. data/docs/rise_transit_set_times.md +119 -0
  19. data/docs/twilight_times.md +123 -0
  20. data/lib/astronoby/bodies/earth.rb +8 -2
  21. data/lib/astronoby/bodies/jupiter.rb +17 -0
  22. data/lib/astronoby/bodies/mars.rb +17 -0
  23. data/lib/astronoby/bodies/mercury.rb +21 -0
  24. data/lib/astronoby/bodies/moon.rb +29 -36
  25. data/lib/astronoby/bodies/neptune.rb +21 -0
  26. data/lib/astronoby/bodies/saturn.rb +26 -0
  27. data/lib/astronoby/bodies/solar_system_body.rb +139 -29
  28. data/lib/astronoby/bodies/sun.rb +25 -2
  29. data/lib/astronoby/bodies/uranus.rb +5 -0
  30. data/lib/astronoby/bodies/venus.rb +25 -0
  31. data/lib/astronoby/cache.rb +188 -0
  32. data/lib/astronoby/configuration.rb +92 -0
  33. data/lib/astronoby/constants.rb +4 -1
  34. data/lib/astronoby/constellation.rb +12 -0
  35. data/lib/astronoby/constellations/data.rb +42 -0
  36. data/lib/astronoby/constellations/finder.rb +35 -0
  37. data/lib/astronoby/constellations/repository.rb +20 -0
  38. data/lib/astronoby/coordinates/equatorial.rb +3 -3
  39. data/lib/astronoby/data/constellations/constellation_names.dat +88 -0
  40. data/lib/astronoby/data/constellations/indexed_abbreviations.dat +88 -0
  41. data/lib/astronoby/data/constellations/radec_to_index.dat +238 -0
  42. data/lib/astronoby/data/constellations/sorted_declinations.dat +202 -0
  43. data/lib/astronoby/data/constellations/sorted_right_ascensions.dat +237 -0
  44. data/lib/astronoby/equinox_solstice.rb +2 -2
  45. data/lib/astronoby/events/moon_phases.rb +15 -14
  46. data/lib/astronoby/events/rise_transit_set_calculator.rb +32 -8
  47. data/lib/astronoby/events/twilight_calculator.rb +115 -60
  48. data/lib/astronoby/events/twilight_events.rb +28 -0
  49. data/lib/astronoby/instant.rb +7 -2
  50. data/lib/astronoby/julian_date.rb +78 -0
  51. data/lib/astronoby/mean_obliquity.rb +8 -10
  52. data/lib/astronoby/nutation.rb +11 -3
  53. data/lib/astronoby/observer.rb +1 -1
  54. data/lib/astronoby/precession.rb +48 -38
  55. data/lib/astronoby/reference_frame.rb +2 -1
  56. data/lib/astronoby/reference_frames/apparent.rb +1 -1
  57. data/lib/astronoby/reference_frames/mean_of_date.rb +1 -1
  58. data/lib/astronoby/reference_frames/topocentric.rb +1 -11
  59. data/lib/astronoby/time/greenwich_sidereal_time.rb +2 -2
  60. data/lib/astronoby/true_obliquity.rb +2 -3
  61. data/lib/astronoby/util/time.rb +1 -1
  62. data/lib/astronoby/version.rb +1 -1
  63. data/lib/astronoby.rb +8 -1
  64. metadata +59 -11
  65. data/Gemfile +0 -5
  66. data/Gemfile.lock +0 -102
  67. data/benchmark/README.md +0 -131
  68. data/benchmark/benchmark.rb +0 -259
  69. data/benchmark/data/imcce.csv.zip +0 -0
  70. data/benchmark/data/sun_calc.csv.zip +0 -0
  71. data/lib/astronoby/epoch.rb +0 -22
@@ -24,72 +24,114 @@ module Astronoby
24
24
  @ephem = ephem
25
25
  end
26
26
 
27
- def event_on(date)
28
- observation_events = get_observation_events(date)
29
- midday_instant = create_midday_instant(date)
30
- sun_at_midday = Sun.new(instant: midday_instant, ephem: @ephem)
31
- equatorial_coordinates = sun_at_midday.apparent.equatorial
32
-
33
- morning_civil = compute_twilight_time(
34
- MORNING,
35
- TWILIGHT_ANGLES[CIVIL],
36
- observation_events,
37
- equatorial_coordinates
38
- )
39
-
40
- evening_civil = compute_twilight_time(
41
- EVENING,
42
- TWILIGHT_ANGLES[CIVIL],
43
- observation_events,
44
- equatorial_coordinates
45
- )
27
+ def event_on(date, utc_offset: 0)
28
+ start_time = Time
29
+ .new(date.year, date.month, date.day, 0, 0, 0, utc_offset)
30
+ end_time = Time
31
+ .new(date.year, date.month, date.day, 23, 59, 59, utc_offset)
32
+ events = events_between(start_time, end_time)
46
33
 
47
- morning_nautical = compute_twilight_time(
48
- MORNING,
49
- TWILIGHT_ANGLES[NAUTICAL],
50
- observation_events,
51
- equatorial_coordinates
52
- )
53
-
54
- evening_nautical = compute_twilight_time(
55
- EVENING,
56
- TWILIGHT_ANGLES[NAUTICAL],
57
- observation_events,
58
- equatorial_coordinates
34
+ TwilightEvent.new(
35
+ morning_civil_twilight_time:
36
+ events.morning_civil_twilight_times.first,
37
+ evening_civil_twilight_time:
38
+ events.evening_civil_twilight_times.first,
39
+ morning_nautical_twilight_time:
40
+ events.morning_nautical_twilight_times.first,
41
+ evening_nautical_twilight_time:
42
+ events.evening_nautical_twilight_times.first,
43
+ morning_astronomical_twilight_time:
44
+ events.morning_astronomical_twilight_times.first,
45
+ evening_astronomical_twilight_time:
46
+ events.evening_astronomical_twilight_times.first
59
47
  )
48
+ end
60
49
 
61
- morning_astronomical = compute_twilight_time(
62
- MORNING,
63
- TWILIGHT_ANGLES[ASTRONOMICAL],
64
- observation_events,
65
- equatorial_coordinates
66
- )
50
+ def events_between(start_time, end_time)
51
+ rts_events = Astronoby::RiseTransitSetCalculator.new(
52
+ body: Sun,
53
+ observer: @observer,
54
+ ephem: @ephem
55
+ ).events_between(start_time, end_time)
56
+
57
+ equatorial_by_time = {}
58
+
59
+ (rts_events.rising_times + rts_events.setting_times)
60
+ .compact
61
+ .each do |event_time|
62
+ rounded_time = event_time.round
63
+ next if equatorial_by_time.key?(rounded_time)
64
+
65
+ instant = Instant.from_time(rounded_time)
66
+ sun_at_time = Sun.new(instant: instant, ephem: @ephem)
67
+ equatorial_by_time[rounded_time] = sun_at_time.apparent.equatorial
68
+ end
69
+
70
+ morning_civil = []
71
+ evening_civil = []
72
+ morning_nautical = []
73
+ evening_nautical = []
74
+ morning_astronomical = []
75
+ evening_astronomical = []
76
+
77
+ arrays_by_period = {
78
+ MORNING => {
79
+ CIVIL => morning_civil,
80
+ NAUTICAL => morning_nautical,
81
+ ASTRONOMICAL => morning_astronomical
82
+ },
83
+ EVENING => {
84
+ CIVIL => evening_civil,
85
+ NAUTICAL => evening_nautical,
86
+ ASTRONOMICAL => evening_astronomical
87
+ }
88
+ }
89
+
90
+ [
91
+ [rts_events.rising_times, MORNING],
92
+ [rts_events.setting_times, EVENING]
93
+ ].each do |times, period|
94
+ times.each do |event_time|
95
+ next unless event_time
96
+
97
+ equatorial_coordinates = equatorial_by_time[event_time.round]
98
+ TWILIGHT_ANGLES.each do |twilight, angle|
99
+ arrays_by_period[period][twilight] << compute_twilight_time_from(
100
+ period,
101
+ angle,
102
+ event_time,
103
+ equatorial_coordinates
104
+ )
105
+ end
106
+ end
107
+ end
67
108
 
68
- evening_astronomical = compute_twilight_time(
69
- EVENING,
70
- TWILIGHT_ANGLES[ASTRONOMICAL],
71
- observation_events,
72
- equatorial_coordinates
73
- )
109
+ within_range = ->(time) { time && time >= start_time && time <= end_time }
74
110
 
75
- TwilightEvent.new(
76
- morning_civil_twilight_time: morning_civil,
77
- evening_civil_twilight_time: evening_civil,
78
- morning_nautical_twilight_time: morning_nautical,
79
- evening_nautical_twilight_time: evening_nautical,
80
- morning_astronomical_twilight_time: morning_astronomical,
81
- evening_astronomical_twilight_time: evening_astronomical
111
+ TwilightEvents.new(
112
+ morning_civil.select(&within_range),
113
+ evening_civil.select(&within_range),
114
+ morning_nautical.select(&within_range),
115
+ evening_nautical.select(&within_range),
116
+ morning_astronomical.select(&within_range),
117
+ evening_astronomical.select(&within_range)
82
118
  )
83
119
  end
84
120
 
85
- def time_for_zenith_angle(date:, period_of_the_day:, zenith_angle:)
121
+ def time_for_zenith_angle(
122
+ date:,
123
+ period_of_the_day:,
124
+ zenith_angle:,
125
+ utc_offset: 0
126
+ )
86
127
  unless PERIODS_OF_THE_DAY.include?(period_of_the_day)
87
128
  raise IncompatibleArgumentsError,
88
- "Only #{PERIODS_OF_THE_DAY.join(" or ")} are allowed as period_of_the_day, got #{period_of_the_day}"
129
+ "Only #{PERIODS_OF_THE_DAY.join(" or ")} are allowed as " \
130
+ "period_of_the_day, got #{period_of_the_day}"
89
131
  end
90
132
 
91
- observation_events = get_observation_events(date)
92
- midday_instant = create_midday_instant(date)
133
+ observation_events = get_observation_events(date, utc_offset: utc_offset)
134
+ midday_instant = create_midday_instant(date, utc_offset: utc_offset)
93
135
  sun_at_midday = Sun.new(instant: midday_instant, ephem: @ephem)
94
136
  equatorial_coordinates = sun_at_midday.apparent.equatorial
95
137
 
@@ -103,17 +145,17 @@ module Astronoby
103
145
 
104
146
  private
105
147
 
106
- def create_midday_instant(date)
107
- time = Time.utc(date.year, date.month, date.day, 12)
148
+ def create_midday_instant(date, utc_offset: 0)
149
+ time = Time.new(date.year, date.month, date.day, 12, 0, 0, utc_offset)
108
150
  Instant.from_time(time)
109
151
  end
110
152
 
111
- def get_observation_events(date)
153
+ def get_observation_events(date, utc_offset: 0)
112
154
  Astronoby::RiseTransitSetCalculator.new(
113
155
  body: Sun,
114
156
  observer: @observer,
115
157
  ephem: @ephem
116
- ).event_on(date)
158
+ ).event_on(date, utc_offset: utc_offset)
117
159
  end
118
160
 
119
161
  def compute_twilight_time(
@@ -128,8 +170,21 @@ module Astronoby
128
170
  observation_events.setting_time
129
171
  end
130
172
 
131
- # If the sun doesn't rise or set on this day, we can't calculate
132
- # twilight
173
+ compute_twilight_time_from(
174
+ period_of_the_day,
175
+ zenith_angle,
176
+ period_time,
177
+ equatorial_coordinates
178
+ )
179
+ end
180
+
181
+ def compute_twilight_time_from(
182
+ period_of_the_day,
183
+ zenith_angle,
184
+ period_time,
185
+ equatorial_coordinates
186
+ )
187
+ # If the sun doesn't rise or set on this day, we can't calculate twilight
133
188
  return nil unless period_time
134
189
 
135
190
  hour_angle_at_period = equatorial_coordinates
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class TwilightEvents
5
+ attr_reader :morning_civil_twilight_times,
6
+ :evening_civil_twilight_times,
7
+ :morning_nautical_twilight_times,
8
+ :evening_nautical_twilight_times,
9
+ :morning_astronomical_twilight_times,
10
+ :evening_astronomical_twilight_times
11
+
12
+ def initialize(
13
+ morning_civil,
14
+ evening_civil,
15
+ morning_nautical,
16
+ evening_nautical,
17
+ morning_astronomical,
18
+ evening_astronomical
19
+ )
20
+ @morning_civil_twilight_times = morning_civil
21
+ @evening_civil_twilight_times = evening_civil
22
+ @morning_nautical_twilight_times = morning_nautical
23
+ @evening_nautical_twilight_times = evening_nautical
24
+ @morning_astronomical_twilight_times = morning_astronomical
25
+ @evening_astronomical_twilight_times = evening_astronomical
26
+ end
27
+ end
28
+ end
@@ -21,7 +21,12 @@ module Astronoby
21
21
  class Instant
22
22
  include Comparable
23
23
 
24
- JULIAN_DAY_NUMBER_OFFSET = 0.5
24
+ # The adjustment value to align our noon-based Julian Date with the
25
+ # midnight-based epoch required by Ruby's `DateTime.jd` constructor.
26
+ # Our internal time values are standard astronomical Julian Dates, which
27
+ # start at noon. `DateTime.jd` expects a day that starts at the preceding
28
+ # midnight. This constant adds 0.5 days (12 hours) to make the conversion.
29
+ DATETIME_JD_EPOCH_ADJUSTMENT = 0.5
25
30
 
26
31
  class << self
27
32
  # Creates a new Instant from a Terrestrial Time value
@@ -90,7 +95,7 @@ module Astronoby
90
95
  DateTime.jd(
91
96
  @terrestrial_time -
92
97
  Rational(delta_t / Constants::SECONDS_PER_DAY) +
93
- JULIAN_DAY_NUMBER_OFFSET
98
+ DATETIME_JD_EPOCH_ADJUSTMENT
94
99
  )
95
100
  end
96
101
 
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ # @see https://en.wikipedia.org/wiki/Julian_day
5
+ # @see https://en.wikipedia.org/wiki/Epoch_(astronomy)
6
+ class JulianDate
7
+ # Starting year for Besselian epoch calculations
8
+ # @return [Integer] 1900
9
+ BESSELIAN_EPOCH_STARTING_YEAR = 1900
10
+
11
+ # Starting year for Julian epoch calculations
12
+ # @return [Integer] 2000
13
+ JULIAN_EPOCH_STARTING_YEAR = 2000
14
+
15
+ # Julian Date for Besselian epoch 1875.0
16
+ # @return [Float] 2405889.258550475
17
+ B1875 = 2405889.258550475
18
+
19
+ # Julian Date for Besselian epoch 1900.0
20
+ # @return [Float] 2415020.31352
21
+ B1900 = 2415020.31352
22
+
23
+ # Julian Date for Julian epoch 1950.0
24
+ # @return [Float] 2433282.5
25
+ J1950 = 2433282.5
26
+
27
+ # Julian Date for Julian epoch 2000.0 (current standard)
28
+ # @return [Float] 2451545.0
29
+ J2000 = 2451545.0
30
+
31
+ # Default epoch used by the library
32
+ # @return [Float] 2451545.0
33
+ DEFAULT_EPOCH = J2000
34
+
35
+ # Converts a Time object to Julian Date
36
+ #
37
+ # @param time [Time] the time to convert
38
+ # @return [Rational] the Julian Date
39
+ #
40
+ # @example
41
+ # JulianDate.from_time(Time.utc(2000, 1, 1, 12, 0, 0))
42
+ # # => 2451545.0
43
+ def self.from_time(time)
44
+ time.to_datetime.ajd
45
+ end
46
+
47
+ # Converts a Julian year to Julian Date
48
+ #
49
+ # Uses the formula: JD = J2000 + 365.25 * (year - 2000)
50
+ #
51
+ # @param julian_year [Float] the Julian year
52
+ # @return [Float] the Julian Date
53
+ #
54
+ # @example
55
+ # JulianDate.from_julian_year(2025.0)
56
+ # # => 2460676.25
57
+ def self.from_julian_year(julian_year)
58
+ J2000 + Constants::DAYS_PER_JULIAN_YEAR *
59
+ (julian_year - JULIAN_EPOCH_STARTING_YEAR)
60
+ end
61
+
62
+ # Converts a Besselian year to Julian Date
63
+ #
64
+ # Uses the formula: JD = B1900 + 365.242198781 * (year - 1900)
65
+ # where 365.242198781 is the tropical year length at B1900.
66
+ #
67
+ # @param besselian_year [Float] the Besselian year
68
+ # @return [Float] the Julian Date
69
+ #
70
+ # @example
71
+ # JulianDate.from_besselian_year(1875.0)
72
+ # # => 2405889.258550475
73
+ def self.from_besselian_year(besselian_year)
74
+ B1900 + Constants::TROPICAL_YEAR_AT_B1900 *
75
+ (besselian_year - BESSELIAN_EPOCH_STARTING_YEAR)
76
+ end
77
+ end
78
+ end
@@ -9,36 +9,34 @@ module Astronoby
9
9
  # IAU resolution in 2006 in favor of the P03 astronomical model
10
10
  # https://syrte.obspm.fr/iau2006/aa03_412_P03.pdf
11
11
 
12
- EPOCH_OF_REFERENCE = Epoch::DEFAULT_EPOCH
12
+ EPOCH_OF_REFERENCE = JulianDate::DEFAULT_EPOCH
13
13
  OBLIQUITY_OF_REFERENCE = 23.4392794
14
14
 
15
- def self.for_epoch(epoch)
16
- return obliquity_of_reference if epoch == EPOCH_OF_REFERENCE
15
+ def self.at(instant)
16
+ return obliquity_of_reference if instant.julian_date == EPOCH_OF_REFERENCE
17
17
 
18
18
  t = Rational(
19
- (epoch - EPOCH_OF_REFERENCE),
19
+ instant.julian_date - EPOCH_OF_REFERENCE,
20
20
  Constants::DAYS_PER_JULIAN_CENTURY
21
21
  )
22
22
 
23
- epsilon0 = obliquity_of_reference_in_milliarcseconds
23
+ epsilon0 = obliquity_of_reference_in_arcseconds
24
24
  c1 = -46.836769
25
25
  c2 = -0.0001831
26
26
  c3 = 0.00200340
27
27
  c4 = -0.000000576
28
28
  c5 = -0.0000000434
29
29
 
30
- Angle.from_dms(
31
- 0,
32
- 0,
30
+ Angle.from_degree_arcseconds(
33
31
  epsilon0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * c5))))
34
32
  )
35
33
  end
36
34
 
37
35
  def self.obliquity_of_reference
38
- Angle.from_dms(0, 0, obliquity_of_reference_in_milliarcseconds)
36
+ Angle.from_degree_arcseconds(obliquity_of_reference_in_arcseconds)
39
37
  end
40
38
 
41
- def self.obliquity_of_reference_in_milliarcseconds
39
+ def self.obliquity_of_reference_in_arcseconds
42
40
  84381.406
43
41
  end
44
42
  end
@@ -104,7 +104,7 @@ module Astronoby
104
104
 
105
105
  # @return [Matrix] The nutation matrix
106
106
  def matrix
107
- mean_obliquity = MeanObliquity.for_epoch(@instant.tt)
107
+ mean_obliquity = MeanObliquity.at(@instant)
108
108
  true_obliquity = mean_obliquity + nutation_in_obliquity
109
109
  build_nutation_matrix(
110
110
  mean_obliquity: mean_obliquity,
@@ -125,6 +125,14 @@ module Astronoby
125
125
 
126
126
  private
127
127
 
128
+ def cache_key
129
+ @_cache_key ||= CacheKey.generate(:nutation, @instant)
130
+ end
131
+
132
+ def cache
133
+ Astronoby.cache
134
+ end
135
+
128
136
  def iau2000a
129
137
  a = fundamental_arguments
130
138
 
@@ -172,7 +180,7 @@ module Astronoby
172
180
  end
173
181
 
174
182
  def iau2000b_angles
175
- @iau2000b_angles ||= begin
183
+ cache.fetch(cache_key) do
176
184
  dpsi, deps = iau2000b
177
185
  dpsi = Angle.from_degree_arcseconds(dpsi / 1e7)
178
186
  deps = Angle.from_degree_arcseconds(deps / 1e7)
@@ -206,7 +214,7 @@ module Astronoby
206
214
 
207
215
  def julian_centuries
208
216
  @julian_centuries ||=
209
- (@instant.tt - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
217
+ (@instant.tt - JulianDate::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
210
218
  end
211
219
 
212
220
  # IAU 2006/2000A formula for the mean anomaly of the Moon
@@ -62,7 +62,7 @@ module Astronoby
62
62
  def earth_fixed_rotation_matrix_for(instant)
63
63
  dpsi = Nutation.new(instant: instant).nutation_in_longitude
64
64
 
65
- mean_obliquity = MeanObliquity.for_epoch(instant.tt)
65
+ mean_obliquity = MeanObliquity.at(instant)
66
66
 
67
67
  gast = Angle.from_radians(
68
68
  Angle.from_hours(instant.gmst).radians +
@@ -16,41 +16,43 @@ module Astronoby
16
16
  # https://syrte.obspm.fr/iau2006/aa03_412_P03.pdf
17
17
  # P(t) = R3(χA) R1(−ωA) R3(−ψA) R1(ϵ0)
18
18
 
19
- # Precession in right ascension
20
- psi_a = ((((
21
- -0.0000000951 * t +
22
- +0.000132851) * t +
23
- -0.00114045) * t +
24
- -1.0790069) * t +
25
- +5038.481507) * t
26
-
27
- # Precession in declination
28
- omega_a = ((((
29
- +0.0000003337 * t +
30
- -0.000000467) * t +
31
- -0.00772503) * t +
32
- +0.0512623) * t +
33
- -0.025754) * t +
34
- eps0
35
-
36
- # Precession of the ecliptic
37
- chi_a = ((((
38
- -0.0000000560 * t +
39
- +0.000170663) * t +
40
- -0.00121197) * t +
41
- -2.3814292) * t +
42
- +10.556403) * t
43
-
44
- psi_a = Angle.from_degree_arcseconds(psi_a)
45
- omega_a = Angle.from_degree_arcseconds(omega_a)
46
- chi_a = Angle.from_degree_arcseconds(chi_a)
47
-
48
- r3_psi = rotation_z(-psi_a)
49
- r1_omega = rotation_x(-omega_a)
50
- r3_chi = rotation_z(chi_a)
51
- r1_eps0 = rotation_x(MeanObliquity.obliquity_of_reference)
52
-
53
- r3_chi * r1_omega * r3_psi * r1_eps0
19
+ cache.fetch(cache_key) do
20
+ # Precession in right ascension
21
+ psi_a = ((((
22
+ -0.0000000951 * t +
23
+ +0.000132851) * t +
24
+ -0.00114045) * t +
25
+ -1.0790069) * t +
26
+ +5038.481507) * t
27
+
28
+ # Precession in declination
29
+ omega_a = ((((
30
+ +0.0000003337 * t +
31
+ -0.000000467) * t +
32
+ -0.00772503) * t +
33
+ +0.0512623) * t +
34
+ -0.025754) * t +
35
+ eps0
36
+
37
+ # Precession of the ecliptic
38
+ chi_a = ((((
39
+ -0.0000000560 * t +
40
+ +0.000170663) * t +
41
+ -0.00121197) * t +
42
+ -2.3814292) * t +
43
+ +10.556403) * t
44
+
45
+ psi_a = Angle.from_degree_arcseconds(psi_a)
46
+ omega_a = Angle.from_degree_arcseconds(omega_a)
47
+ chi_a = Angle.from_degree_arcseconds(chi_a)
48
+
49
+ r3_psi = rotation_z(-psi_a)
50
+ r1_omega = rotation_x(-omega_a)
51
+ r3_chi = rotation_z(chi_a)
52
+ r1_eps0 = rotation_x(MeanObliquity.obliquity_of_reference)
53
+
54
+ r3_chi * r1_omega * r3_psi * r1_eps0
55
+ end
54
56
  end
55
57
 
56
58
  def rotation_x(angle)
@@ -106,7 +108,7 @@ module Astronoby
106
108
  end
107
109
 
108
110
  def self.matrix_for_epoch(epoch)
109
- t = (epoch - Epoch::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
111
+ t = (epoch - JulianDate::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
110
112
 
111
113
  zeta = Angle.from_degrees(
112
114
  0.6406161 * t + 0.0000839 * t * t + 0.000005 * t * t * t
@@ -146,15 +148,23 @@ module Astronoby
146
148
 
147
149
  private
148
150
 
151
+ def cache_key
152
+ @_cache_key ||= CacheKey.generate(:precession, @instant)
153
+ end
154
+
155
+ def cache
156
+ Astronoby.cache
157
+ end
158
+
149
159
  def t
150
160
  @t ||= Rational(
151
- @instant.tdb - Epoch::DEFAULT_EPOCH,
161
+ @instant.tdb - JulianDate::DEFAULT_EPOCH,
152
162
  Constants::DAYS_PER_JULIAN_CENTURY
153
163
  )
154
164
  end
155
165
 
156
166
  def eps0
157
- @eps0 ||= MeanObliquity.obliquity_of_reference_in_milliarcseconds
167
+ @eps0 ||= MeanObliquity.obliquity_of_reference_in_arcseconds
158
168
  end
159
169
  end
160
170
  end
@@ -34,7 +34,8 @@ module Astronoby
34
34
  @ecliptic ||= begin
35
35
  return Coordinates::Ecliptic.zero if distance.zero?
36
36
 
37
- equatorial.to_ecliptic(epoch: Epoch::J2000)
37
+ j2000 = Instant.from_terrestrial_time(JulianDate::J2000)
38
+ equatorial.to_ecliptic(instant: j2000)
38
39
  end
39
40
  end
40
41
 
@@ -43,7 +43,7 @@ module Astronoby
43
43
  @ecliptic ||= begin
44
44
  return Coordinates::Ecliptic.zero if distance.zero?
45
45
 
46
- equatorial.to_ecliptic(epoch: @instant.tdb)
46
+ equatorial.to_ecliptic(instant: @instant)
47
47
  end
48
48
  end
49
49
 
@@ -31,7 +31,7 @@ module Astronoby
31
31
  @ecliptic ||= begin
32
32
  return Coordinates::Ecliptic.zero if distance.zero?
33
33
 
34
- equatorial.to_ecliptic(epoch: @instant.tdb)
34
+ equatorial.to_ecliptic(instant: @instant)
35
35
  end
36
36
  end
37
37
  end
@@ -48,21 +48,11 @@ module Astronoby
48
48
  @observer = observer
49
49
  end
50
50
 
51
- def angular_diameter
52
- @angular_radius ||= begin
53
- return Angle.zero if @position.zero?
54
-
55
- Angle.from_radians(
56
- Math.atan(@target_body.class::EQUATORIAL_RADIUS.m / distance.m) * 2
57
- )
58
- end
59
- end
60
-
61
51
  def ecliptic
62
52
  @ecliptic ||= begin
63
53
  return Coordinates::Ecliptic.zero if distance.zero?
64
54
 
65
- equatorial.to_ecliptic(epoch: @instant.tdb)
55
+ equatorial.to_ecliptic(instant: @instant)
66
56
  end
67
57
  end
68
58
 
@@ -20,7 +20,7 @@ module Astronoby
20
20
  def self.from_utc(utc)
21
21
  date = utc.to_date
22
22
  julian_day = utc.to_date.ajd
23
- t = (julian_day - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
23
+ t = (julian_day - JulianDate::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
24
24
  t0 = (
25
25
  (JULIAN_CENTURIES_EXPONENTS[0] +
26
26
  (JULIAN_CENTURIES_EXPONENTS[1] * t) +
@@ -51,7 +51,7 @@ module Astronoby
51
51
  def to_utc
52
52
  date = @date
53
53
  julian_day = @date.ajd
54
- t = (julian_day - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
54
+ t = (julian_day - JulianDate::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
55
55
 
56
56
  t0 = (
57
57
  (JULIAN_CENTURIES_EXPONENTS[0] +
@@ -2,9 +2,8 @@
2
2
 
3
3
  module Astronoby
4
4
  class TrueObliquity
5
- def self.for_epoch(epoch)
6
- instant = Instant.from_utc_julian_date(epoch)
7
- mean_obliquity = MeanObliquity.for_epoch(epoch)
5
+ def self.at(instant)
6
+ mean_obliquity = MeanObliquity.at(instant)
8
7
  nutation = Nutation.new(instant: instant).nutation_in_obliquity
9
8
 
10
9
  mean_obliquity + nutation
@@ -496,7 +496,7 @@ module Astronoby
496
496
  when Numeric
497
497
  instant
498
498
  when ::Time, ::Date, ::DateTime
499
- Epoch.from_time(instant)
499
+ JulianDate.from_time(instant)
500
500
  else
501
501
  raise IncompatibleArgumentsError,
502
502
  "Expected a Numeric, Time, Date or DateTime object, got #{instant.class}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Astronoby
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end