astronoby 0.7.0 → 0.9.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +145 -3
  4. data/README.md +59 -33
  5. data/UPGRADING.md +75 -21
  6. data/docs/README.md +224 -0
  7. data/docs/angles.md +137 -0
  8. data/docs/configuration.md +98 -0
  9. data/docs/coordinates.md +167 -0
  10. data/docs/deep_sky_bodies.md +101 -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/solar_system_bodies.md +107 -0
  20. data/docs/twilight_times.md +123 -0
  21. data/lib/astronoby/angle.rb +6 -2
  22. data/lib/astronoby/angular_velocity.rb +76 -0
  23. data/lib/astronoby/bodies/deep_sky_object.rb +44 -0
  24. data/lib/astronoby/bodies/deep_sky_object_position.rb +127 -0
  25. data/lib/astronoby/bodies/earth.rb +12 -2
  26. data/lib/astronoby/bodies/jupiter.rb +17 -0
  27. data/lib/astronoby/bodies/mars.rb +17 -0
  28. data/lib/astronoby/bodies/mercury.rb +21 -0
  29. data/lib/astronoby/bodies/moon.rb +50 -36
  30. data/lib/astronoby/bodies/neptune.rb +21 -0
  31. data/lib/astronoby/bodies/saturn.rb +26 -0
  32. data/lib/astronoby/bodies/solar_system_body.rb +162 -27
  33. data/lib/astronoby/bodies/sun.rb +25 -2
  34. data/lib/astronoby/bodies/uranus.rb +5 -0
  35. data/lib/astronoby/bodies/venus.rb +25 -0
  36. data/lib/astronoby/cache.rb +189 -0
  37. data/lib/astronoby/configuration.rb +92 -0
  38. data/lib/astronoby/constants.rb +11 -3
  39. data/lib/astronoby/constellation.rb +12 -0
  40. data/lib/astronoby/constellations/data.rb +42 -0
  41. data/lib/astronoby/constellations/finder.rb +35 -0
  42. data/lib/astronoby/constellations/repository.rb +20 -0
  43. data/lib/astronoby/coordinates/equatorial.rb +5 -8
  44. data/lib/astronoby/data/constellations/constellation_names.dat +88 -0
  45. data/lib/astronoby/data/constellations/indexed_abbreviations.dat +88 -0
  46. data/lib/astronoby/data/constellations/radec_to_index.dat +238 -0
  47. data/lib/astronoby/data/constellations/sorted_declinations.dat +202 -0
  48. data/lib/astronoby/data/constellations/sorted_right_ascensions.dat +237 -0
  49. data/lib/astronoby/distance.rb +6 -0
  50. data/lib/astronoby/equinox_solstice.rb +2 -2
  51. data/lib/astronoby/events/extremum_calculator.rb +233 -0
  52. data/lib/astronoby/events/extremum_event.rb +15 -0
  53. data/lib/astronoby/events/moon_phases.rb +15 -14
  54. data/lib/astronoby/events/rise_transit_set_calculator.rb +39 -12
  55. data/lib/astronoby/events/twilight_calculator.rb +116 -61
  56. data/lib/astronoby/events/twilight_events.rb +28 -0
  57. data/lib/astronoby/instant.rb +34 -6
  58. data/lib/astronoby/julian_date.rb +78 -0
  59. data/lib/astronoby/mean_obliquity.rb +8 -10
  60. data/lib/astronoby/nutation.rb +11 -3
  61. data/lib/astronoby/observer.rb +1 -1
  62. data/lib/astronoby/precession.rb +48 -38
  63. data/lib/astronoby/reference_frame.rb +2 -1
  64. data/lib/astronoby/reference_frames/apparent.rb +1 -11
  65. data/lib/astronoby/reference_frames/mean_of_date.rb +1 -1
  66. data/lib/astronoby/reference_frames/topocentric.rb +2 -12
  67. data/lib/astronoby/stellar_propagation.rb +162 -0
  68. data/lib/astronoby/time/greenwich_apparent_sidereal_time.rb +22 -0
  69. data/lib/astronoby/time/greenwich_mean_sidereal_time.rb +64 -0
  70. data/lib/astronoby/time/greenwich_sidereal_time.rb +20 -58
  71. data/lib/astronoby/time/local_apparent_sidereal_time.rb +42 -0
  72. data/lib/astronoby/time/local_mean_sidereal_time.rb +42 -0
  73. data/lib/astronoby/time/local_sidereal_time.rb +35 -26
  74. data/lib/astronoby/time/sidereal_time.rb +42 -0
  75. data/lib/astronoby/true_obliquity.rb +2 -3
  76. data/lib/astronoby/util/time.rb +62 -44
  77. data/lib/astronoby/velocity.rb +5 -0
  78. data/lib/astronoby/version.rb +1 -1
  79. data/lib/astronoby.rb +19 -1
  80. metadata +71 -11
  81. data/Gemfile +0 -5
  82. data/Gemfile.lock +0 -102
  83. data/benchmark/README.md +0 -131
  84. data/benchmark/benchmark.rb +0 -259
  85. data/benchmark/data/imcce.csv.zip +0 -0
  86. data/benchmark/data/sun_calc.csv.zip +0 -0
  87. data/lib/astronoby/epoch.rb +0 -22
data/docs/README.md ADDED
@@ -0,0 +1,224 @@
1
+ # Quick Start
2
+
3
+ ## Download an ephemeris
4
+
5
+ You only need to run this once, it will download and store an ephemeris on your
6
+ file system.
7
+
8
+ ```rb
9
+ Ephem::IO::Download.call(name: "de421.bsp", target: "tmp/de421.bsp")
10
+ ```
11
+
12
+ Ephemerides can be large files, but Astronoby provides a tool to drastically
13
+ reduce the size to your needs. You can learn more about ephemerides on the
14
+ [Ephem page].
15
+
16
+ ## Load an ephemeris
17
+
18
+ ```rb
19
+ ephem = Astronoby::Ephem.load("tmp/de421.bsp")
20
+ ```
21
+
22
+ ## Define a time and create an `Instant` object from it
23
+
24
+ ```rb
25
+ time = Time.utc(2025, 6, 19, 12, 0, 0)
26
+ instant = Astronoby::Instant.from_time(time)
27
+ ```
28
+
29
+ You can learn more about time scales on the [Instant page].
30
+
31
+ ## Instantiate a Solar System body object
32
+
33
+ ```rb
34
+ jupiter = Astronoby::Jupiter.new(instant: instant, ephem: ephem)
35
+ ```
36
+
37
+ You can learn more about planets and bodies on the [Solar System Bodies page].
38
+
39
+ ## Define an observer from geographic coordinates
40
+
41
+ ```rb
42
+ observer = Astronoby::Observer.new(
43
+ latitude: Astronoby::Angle.from_degrees(48.83661378408946),
44
+ longitude: Astronoby::Angle.from_degrees(2.3366748126024466),
45
+ elevation: Astronoby::Distance.from_meters(65)
46
+ )
47
+ ```
48
+
49
+ You can learn more about angles on the [Angles page], and about observers on the
50
+ [Observer page].
51
+
52
+ ## Compute the topocentric position of the body as seen from the observer
53
+
54
+ ```rb
55
+ topocentric = jupiter.observed_by(observer)
56
+ ```
57
+
58
+ You can learn more about reference frames and positions on the
59
+ [Reference Frames page].
60
+
61
+ ## Get the horizontal coordinates from the position
62
+
63
+ ```rb
64
+ topocentric.horizontal.azimuth.str(:dms)
65
+ # => "+175° 34′ 28.2724″"
66
+
67
+ topocentric.horizontal.altitude.str(:dms)
68
+ # => "+64° 22′ 58.1084″"
69
+ ```
70
+
71
+ You can learn more about coordinates on the [Coordinates page].
72
+
73
+ ## Get the rising, transit and setting times between two times
74
+
75
+ ```rb
76
+ calculator = Astronoby::RiseTransitSetCalculator.new(
77
+ body: Astronoby::Jupiter,
78
+ observer: observer,
79
+ ephem: ephem
80
+ )
81
+
82
+ events = calculator.events_between(
83
+ Time.utc(2025, 5, 1),
84
+ Time.utc(2025, 5, 3),
85
+ )
86
+
87
+ events.rising_times
88
+ # => [2025-05-01 06:35:35 UTC, 2025-05-02 06:32:26 UTC]
89
+
90
+ events.transit_times
91
+ # => [2025-05-01 14:34:34 UTC, 2025-05-02 14:31:31 UTC]
92
+
93
+ events.setting_times
94
+ # => [2025-05-01 22:33:37 UTC, 2025-05-02 22:30:39 UTC]
95
+ ```
96
+
97
+ You can learn more about this calculator on the
98
+ [Rise, transit and setting times page].
99
+
100
+ ## Get the twilight times of the day
101
+
102
+ ```rb
103
+ calculator = Astronoby::TwilightCalculator.new(
104
+ observer: observer,
105
+ ephem: ephem
106
+ )
107
+
108
+ event = calculator.event_on(Date.new(2025, 5, 1))
109
+
110
+ event.morning_astronomical_twilight_time
111
+ # => 2025-05-01 02:17:28 UTC
112
+
113
+ event.morning_nautical_twilight_time
114
+ # => 2025-05-01 03:10:17 UTC
115
+
116
+ event.morning_civil_twilight_time
117
+ # => 2025-05-01 03:55:17 UTC
118
+
119
+ event.evening_civil_twilight_time
120
+ # => 2025-05-01 19:40:12 UTC
121
+
122
+ event.evening_nautical_twilight_time
123
+ # => 2025-05-01 20:25:12 UTC
124
+
125
+ event.evening_astronomical_twilight_time
126
+ # => 2025-05-01 21:18:01 UTC
127
+ ```
128
+
129
+ You can learn more about this calculator on the [Twilight times page].
130
+
131
+ ## Moon phases
132
+
133
+ You can either get all the major Moon phases that will happen in a month, or get
134
+ information about the current Moon phase.
135
+
136
+ ```rb
137
+ may_2024_phases = Astronoby::Events::MoonPhases.phases_for(year: 2024, month: 5)
138
+
139
+ may_2024_phases.each { puts "#{_1.phase}: #{_1.time}" }
140
+ # last_quarter: 2024-05-01 11:27:15 UTC
141
+ # new_moon: 2024-05-08 03:21:56 UTC
142
+ # first_quarter: 2024-05-15 11:48:02 UTC
143
+ # full_moon: 2024-05-23 13:53:12 UTC
144
+ # last_quarter: 2024-05-30 17:12:43 UTC
145
+ ```
146
+
147
+ ```rb
148
+ time = Time.utc(2025, 5, 15)
149
+ instant = Astronoby::Instant.from_time(time)
150
+ moon = Astronoby::Moon.new(ephem: ephem, instant: instant)
151
+
152
+ moon.illuminated_fraction.round(2)
153
+ # => 0.15
154
+
155
+ moon.current_phase_fraction.round(2)
156
+ # => 0.11
157
+ ```
158
+
159
+ You can learn more about phases on the [Moon phases page].
160
+
161
+ ## Equinox and solstice times
162
+
163
+ ```rb
164
+
165
+ Astronoby::EquinoxSolstice.march_equinox(2025, ephem)
166
+ # => 2025-03-20 09:01:29 UTC
167
+
168
+ Astronoby::EquinoxSolstice.june_solstice(2025, ephem)
169
+ # => 2025-06-21 02:42:19 UTC
170
+
171
+ Astronoby::EquinoxSolstice.september_equinox(2025, ephem)
172
+ # => 2025-09-22 18:19:22 UTC
173
+
174
+ Astronoby::EquinoxSolstice.december_solstice(2025, ephem)
175
+ # => 2025-12-21 15:03:03 UTC
176
+ ```
177
+
178
+ You can learn more about equinoxes and solstices on the
179
+ [Equinoxes and solstices times page].
180
+
181
+ ## Deep-sky objects
182
+
183
+ It is possible to manipulate any deep-sky possible, given equatorial coordinates
184
+ from a catalogue at J2000 epoch.
185
+
186
+ ```rb
187
+ time = Time.utc(2025, 10, 1)
188
+ instant = Astronoby::Instant.from_time(time)
189
+
190
+ vega_j2000 = Astronoby::Coordinates::Equatorial.new(
191
+ right_ascension: Astronoby::Angle.from_hms(18, 36, 56.33635),
192
+ declination: Astronoby::Angle.from_dms(38, 47, 1.2802),
193
+ epoch: Astronoby::JulianDate::J2000
194
+ )
195
+
196
+ # Build the body for star Vega
197
+ vega = Astronoby::DeepSkyObject.new(equatorial_coordinates: vega_j2000)
198
+
199
+ # Build the position of star Vega for a given instant
200
+ vega_position = vega.at(instant)
201
+
202
+ vega_position.apparent.equatorial.right_ascension.str(:hms)
203
+ # => "18h 36m 56.3363s"
204
+ ```
205
+
206
+ You can learn more about deep-sky objects on the [Deep-sky Bodies page].
207
+
208
+ ## See also
209
+ - [Glossary](glossary.md) - for astronomical and technical terms
210
+ - [Configuration](configuration.md) - for performance tuning
211
+ - [Performance Benchmarks](../benchmarks/README.md) - for testing improvements
212
+
213
+ [Ephem page]: ephem.md
214
+ [Instant page]: instant.md
215
+ [Solar System Bodies page]: solar_system_bodies.md
216
+ [Observer page]: observer.md
217
+ [Reference Frames page]: reference_frames.md
218
+ [Angles page]: angles.md
219
+ [Coordinates page]: coordinates.md
220
+ [Rise, transit and setting times page]: rise_transit_set_times.md
221
+ [Twilight times page]: twilight_times.md
222
+ [Moon phases page]: moon_phases.md
223
+ [Equinoxes and solstices times page]: equinoxes_solstices_times.md
224
+ [Deep-sky Bodies page]: deep_sky_bodies.md
data/docs/angles.md ADDED
@@ -0,0 +1,137 @@
1
+ # Angles
2
+
3
+ `Astronoby::Angle` is one of the most important object in the library. An object
4
+ on the celestial sphere is described with angles, an observer's location on
5
+ Earth is described with angles, the distance between two points in the sky is
6
+ described with an angle.
7
+
8
+ ## Create an angle
9
+
10
+ You can create an instance of `Astronoby::Angle` with a value in different
11
+ units: radians, degrees or hours.
12
+
13
+ ```rb
14
+ Astronoby::Angle.from_radians(Math::PI)
15
+ Astronoby::Angle.from_degrees(180)
16
+ Astronoby::Angle.from_hours(12)
17
+ ```
18
+
19
+ You can also use the hour-minute-second (HMS) or degree-minute-second (DMS)
20
+ formats.
21
+
22
+ ```rb
23
+ Astronoby::Angle.from_hms(22, 45, 23)
24
+ Astronoby::Angle.from_dms(340, 45, 23)
25
+ ```
26
+
27
+ Alternatively, you can create an angle of 0 (regardless of the unit).
28
+
29
+ ```rb
30
+ Astronoby::Angle.zero
31
+ ```
32
+
33
+ Finally, you can create an angle from the ratio of a trigonometric function.
34
+
35
+ ```rb
36
+ Astronoby::Angle.acos(0)
37
+ Astronoby::Angle.asin(-1)
38
+ Astronoby::Angle.atan(1 / Math.sqrt(3))
39
+ ```
40
+
41
+ ## Convert between units
42
+
43
+ Once an angle object is instantiated, its value lives inside it. You need to
44
+ specify a unit to extract it.
45
+
46
+ ```rb
47
+ angle = Astronoby::Angle.from_degrees(180)
48
+
49
+ angle.degrees # => 180.0
50
+ angle.radians # => 3.141592653589793
51
+ angle.hours # => 12.0
52
+ ```
53
+
54
+ ## Format an angle
55
+
56
+ You can format an angle in HMS or DMS formatted strings.
57
+
58
+ ```rb
59
+ angle = Astronoby::Angle.from_degrees(155.76479)
60
+
61
+ angle.str(:dms) # => "+155° 45′ 53.2439″"
62
+ angle.str(:hms) # => "10h 23m 3.5496s"
63
+ ```
64
+
65
+ Alternatively you can extract these numbers without having to format them into a
66
+ string.
67
+
68
+ ```rb
69
+ angle = Astronoby::Angle.from_degrees(155.76479)
70
+
71
+ dms = angle.to_dms
72
+ dms.sign # => "+"
73
+ dms.degrees # => 155
74
+ dms.minutes # => 45
75
+ dms.seconds # => 53.2439
76
+
77
+ hms = angle.to_hms
78
+ hms.hours # => 10
79
+ hms.minutes # => 23
80
+ hms.seconds # => 3.5496
81
+ ```
82
+
83
+ ## Manipulate angles
84
+
85
+ You can compare an angle with another angle.
86
+
87
+ ```rb
88
+ Astronoby::Angle.from_hours(12) == Astronoby::Angle.from_degrees(180)
89
+ # => true
90
+
91
+ angle1 = Astronoby::Angle.from_degrees(90)
92
+ angle2 = Astronoby::Angle.from_hours(12)
93
+
94
+ angle1 < angle2 # => true
95
+ ```
96
+
97
+ ## Math with angles
98
+
99
+ Trigonometric functions can be applied to angles to get the value as a `Float`.
100
+ Please be aware some results won't be strictly exact because of the limited
101
+ precision of floating-point numbers and the limited amount of digits
102
+ of `Math::PI`.
103
+
104
+ ```rb
105
+ angle = Astronoby::Angle.from_degrees(180)
106
+
107
+ angle.cos # => -1.0
108
+ angle.sin # => 1.2246467991473532e-16, strictly supposed to be 0
109
+ angle.tan # => -1.2246467991473532e-16, strictly supposed to be 0
110
+ ```
111
+
112
+ You can add up or subtract angles into a new one. Multiplication and division
113
+ are not supported as they mathematically should return something else than an
114
+ angle.
115
+
116
+ ```rb
117
+ angle1 = Astronoby::Angle.from_hours(12)
118
+ angle2 = Astronoby::Angle.from_degrees(90)
119
+
120
+ angle3 = angle1 + angle2
121
+ angle3.degrees # => 270.0
122
+
123
+ angle4 = angle1 - angle2
124
+ angle4.degrees # => 90.0
125
+
126
+ angle5 = -angle1
127
+ angle5.degrees # => -180.0
128
+
129
+ angle1.positive? # => true
130
+ angle1.negative? # => false
131
+ ```
132
+
133
+ ## See also
134
+ - [Coordinates](coordinates.md) - for using angles in coordinate systems
135
+ - [Observer](observer.md) - for latitude and longitude
136
+ - [Reference Frames](reference_frames.md) - for position calculations
137
+ - [Solar System Bodies](solar_system_bodies.md) - for object positions
@@ -0,0 +1,98 @@
1
+ # Configuration
2
+
3
+ Astronoby handles an internal configuration to enable users to tweak the
4
+ performance and precision of computed data.
5
+
6
+ ## Cache
7
+
8
+ Some calculations are expensive but also repetitive in the intermediate computed
9
+ data. To improve performance, an internal cache system has been developed.
10
+
11
+ ➡️ **Please note caching is disabled by default.**
12
+
13
+ ### Enable caching
14
+
15
+ You can turn caching on with the following command:
16
+
17
+ ```rb
18
+ Astronoby.configuration.cache_enabled = true
19
+ ```
20
+
21
+ Once caching is enabled, it will be used for the following parts of the library
22
+ with default precision values:
23
+ * [Geometric positions]
24
+ * [Topocentric positions] when computing rising/transit/setting times
25
+ * [Moon phases]
26
+ * Nutation
27
+ * Precession
28
+
29
+ ## Cache precision
30
+
31
+ When cache is enabled, some data is cached following a default precision
32
+ threshold so that precision doesn't noticeably decrease.
33
+
34
+ However, users may want to improve performance even more at the cost of some
35
+ precision.
36
+
37
+ It is possible to change the precision value for the following:
38
+ * Geometric position, default: `9`
39
+ * Topocentric position, default: `5`
40
+ * Nutation, default: `2`
41
+ * Precession, default: `2`
42
+
43
+ ### Precision value
44
+
45
+ The precision value is how much rounded instants are. Because instants are
46
+ stored as a [Julian Day], rounding may not seem very natural.
47
+
48
+ Let's take the example of `1`. Rounding a Julian Day with only one digit means
49
+ that all times within 8640 seconds will be rounded to the same instant, which
50
+ means a maximum rounding of 2.4 hours.
51
+
52
+ * `1`: 2.4 hours
53
+ * `2`: 14.4 minutes
54
+ * `3`: 86.4 seconds
55
+ * `4`: 8.6 seconds
56
+ * `5`: 0.86 seconds
57
+ * `6`: 0.086 seconds
58
+ * `7`: 0.0086 seconds
59
+ * ...
60
+
61
+ ### Setting custom precision
62
+
63
+ To set up your own precision, you can use:
64
+
65
+ ```rb
66
+ Astronoby.cache_precision(:geometric, 5)
67
+ ```
68
+
69
+ All geometric positions of the same celestial body within 0.86 seconds will be
70
+ rounded and cached.
71
+
72
+ ## Cache size
73
+
74
+ Cache has limited and configurable capacity, set by default to 10,000 stored
75
+ items. This value can be changed to any positive number.
76
+
77
+ ```rb
78
+ Astronoby.configuration.cache_enabled = true
79
+
80
+ Astronoby.cache.max_size
81
+ # => 10000
82
+
83
+ Astronoby.cache.max_size = 1000000
84
+
85
+ Astronoby.cache.max_size
86
+ # => 1000000
87
+ ```
88
+
89
+ [Geometric positions]: reference_frames.md#geometric
90
+ [Topocentric positions]: reference_frames.md#topocentric
91
+ [Moon phases]: moon_phases.md
92
+ [Julian Day]: https://en.wikipedia.org/wiki/Julian_day
93
+
94
+ ## See also
95
+ - [Reference Frames](reference_frames.md) - for understanding position calculations
96
+ - [Ephemerides](ephem.md) - for data sources
97
+ - [Performance Benchmarks](benchmarks/README.md) - for testing improvements
98
+ - [Cache System](cache.md) - for detailed caching information
@@ -0,0 +1,167 @@
1
+ # Coordinates
2
+
3
+ Astronoby provides three different types of coordinates:
4
+
5
+ * Equatorial
6
+ * Ecliptic
7
+ * Horizontal
8
+
9
+ Equatorial and ecliptic coordinates are available for each [reference frame],
10
+ while horizontal coordinates are only available for a topocentric position.
11
+
12
+ ## Equatorial
13
+
14
+ In Astronoby, equatorial coordinates are geocentric spherical coordinates. As
15
+ per [Wikipedia]'s definition:
16
+
17
+ > defined by an origin at the centre of Earth, fundamental plane consisting of
18
+ > the projection of Earth's equator onto the celestial sphere (forming the
19
+ > celestial equator, a primary direction towards the March equinox, and a
20
+ > right-handed convention.
21
+
22
+ They have two main angular attributes:
23
+
24
+ ### Right ascension
25
+
26
+ Angle measured East from the Vernal Equinox, the point where the Sun crosses the
27
+ celestial equator in March as it passes from the southern to the northern half
28
+ of the sky. By convention, right ascension is usually displayed in hours.
29
+
30
+ ```rb
31
+ ephem = Astronoby::Ephem.load("inpop19a.bsp")
32
+ time = Time.utc(1962, 7, 24)
33
+ instant = Astronoby::Instant.from_time(time)
34
+
35
+ saturn = Astronoby::Saturn.new(ephem: ephem, instant: instant)
36
+ equatorial = saturn.apparent.equatorial
37
+
38
+ equatorial.right_ascension.str(:hms)
39
+ # => "20h 45m 2.6702s"
40
+ ```
41
+
42
+ You can learn more about angles on the [Angle page].
43
+
44
+ ### Declination
45
+
46
+ Angle measured north and south of the celestial equator in degrees, with north
47
+ being positive. The North Celestial Pole is at +90° and the South Celestial Pole
48
+ is at -90°.
49
+
50
+ ```rb
51
+ equatorial.declination.str(:dms)
52
+ # => "-18° 46′ 16.1226″"
53
+ ```
54
+
55
+ ### Hour angle
56
+
57
+ Sometimes convenient for astronomers, a third attribute can be derived from
58
+ equatorial coordinates: the hour angle. It is the angle between the meridian
59
+ plane and the hour circle, meaning it depends on the observer's longitude and
60
+ time. By convention, the hour angle is usually displayed in hours.
61
+
62
+ ```rb
63
+ longitude = Astronoby::Angle.from_degrees(2)
64
+
65
+ equatorial.compute_hour_angle(longitude: longitude, time: time).str(:hms)
66
+ # => "23h 27m 54.9585s"
67
+ ```
68
+
69
+ ## Ecliptic
70
+
71
+ In Astronoby, ecliptic coordinates are geocentric spherical coordinates. Their
72
+ origin is the centre of Earth, their primary direction is towards the March
73
+ equinox, and they have a right-hand convention. Ecliptic coordinates are
74
+ particularly handy for representing positions of Solar System objects.
75
+
76
+ As per Wikipedia's definition:
77
+
78
+ > The celestial equator and the ecliptic are slowly moving due to perturbing
79
+ > forces on the Earth, therefore the orientation of the primary direction, their
80
+ > intersection at the March equinox, is not quite fixed. A slow motion of
81
+ > Earth's axis, precession, causes a slow, continuous turning of the coordinate
82
+ > system westward about the poles of the ecliptic. Superimposed on this is a
83
+ > smaller motion of the ecliptic, and a small oscillation of the Earth's axis,
84
+ > nutation.
85
+
86
+ This primary direction depends on the [reference frame] used.
87
+
88
+ They have two main angular attributes:
89
+
90
+ ### Latitude
91
+
92
+ The ecliptic latitude measures the angular distance of an object along the
93
+ ecliptic from the primary direction.
94
+
95
+ ```rb
96
+ ephem = Astronoby::Ephem.load("inpop19a.bsp")
97
+ time = Time.utc(1962, 7, 24)
98
+ instant = Astronoby::Instant.from_time(time)
99
+
100
+ saturn = Astronoby::Saturn.new(ephem: ephem, instant: instant)
101
+ ecliptic = saturn.apparent.ecliptic
102
+
103
+ ecliptic.latitude.str(:dms)
104
+ # => "-0° 41′ 27.5439″"
105
+ ```
106
+
107
+ ### Longitude
108
+
109
+ The ecliptic latitude measures the angular distance of an object from the
110
+ ecliptic towards the north (positive) or south (negative) ecliptic pole.
111
+
112
+ ```rb
113
+ ecliptic.longitude.str(:dms)
114
+ # => "+308° 38′ 33.1744″"
115
+ ```
116
+
117
+ ## Horizontal
118
+
119
+ Horizontal coordinates are the most observer-centred and human-intuitive
120
+ coordinates. They measure where an object is in the sky as seen from an observer
121
+ on Earth as "up and down" and "left and right".
122
+
123
+ In Astronoby, they can only be computed from a [topocentric position].
124
+
125
+ They have two main angular attributes:
126
+
127
+ ### Altitude
128
+
129
+ The angle between the object and the observer's local horizon.
130
+
131
+ ```rb
132
+ ephem = Astronoby::Ephem.load("inpop19a.bsp")
133
+ time = Time.utc(1962, 7, 24)
134
+ instant = Astronoby::Instant.from_time(time)
135
+
136
+ observer = Astronoby::Observer.new(
137
+ latitude: Astronoby::Angle.from_degrees(42),
138
+ longitude: Astronoby::Angle.from_degrees(2)
139
+ )
140
+
141
+ saturn = Astronoby::Saturn.new(ephem: ephem, instant: instant)
142
+ horizontal = saturn.observed_by(observer).horizontal
143
+
144
+ horizontal.altitude.str(:dms)
145
+ # => "+28° 46′ 39.5994″"
146
+ ```
147
+
148
+ ### Azimuth
149
+
150
+ The angle of the object around the horizon from the north and increasing
151
+ eastward.
152
+
153
+ ```rb
154
+ horizontal.azimuth.str(:dms)
155
+ # => "+171° 19′ 50.5798″"
156
+ ```
157
+
158
+ [reference frame]: reference_frames.md
159
+ [Wikipedia]: https://en.wikipedia.org/wiki/Equatorial_coordinate_system
160
+ [Angle page]: angles.md
161
+ [topocentric position]: reference_frames.md#topocentric
162
+
163
+ ## See also
164
+ - [Reference Frames](reference_frames.md) - for coordinate system details
165
+ - [Angles](angles.md) - for working with angular measurements
166
+ - [Observer](observer.md) - for location setup
167
+ - [Solar System Bodies](solar_system_bodies.md) - for object positions