astronoby 0.8.0 → 0.10.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +159 -0
- data/README.md +12 -5
- data/UPGRADING.md +109 -0
- data/docs/README.md +109 -16
- data/docs/angles.md +2 -1
- data/docs/configuration.md +20 -17
- data/docs/coordinates.md +73 -13
- data/docs/deep_sky_bodies.md +101 -0
- data/docs/ephem.md +6 -3
- data/docs/equinoxes_solstices_times.md +4 -3
- data/docs/glossary.md +97 -1
- data/docs/iers.md +40 -0
- data/docs/instant.md +21 -16
- data/docs/lunar_eclipses.md +93 -0
- data/docs/lunar_observation.md +87 -0
- data/docs/moon_phases.md +5 -2
- data/docs/observer.md +21 -7
- data/docs/planetary_phenomena.md +78 -0
- data/docs/reference_frames.md +193 -35
- data/docs/rise_transit_set_times.md +10 -8
- data/docs/{celestial_bodies.md → solar_system_bodies.md} +27 -5
- data/docs/twilight_times.md +25 -21
- data/lib/astronoby/angle.rb +69 -4
- data/lib/astronoby/angles/dms.rb +18 -1
- data/lib/astronoby/angles/hms.rb +14 -1
- data/lib/astronoby/angular_velocity.rb +97 -0
- data/lib/astronoby/bodies/deep_sky_object.rb +49 -0
- data/lib/astronoby/bodies/deep_sky_object_position.rb +142 -0
- data/lib/astronoby/bodies/earth.rb +9 -42
- data/lib/astronoby/bodies/jupiter.rb +10 -0
- data/lib/astronoby/bodies/mars.rb +10 -0
- data/lib/astronoby/bodies/mercury.rb +10 -0
- data/lib/astronoby/bodies/moon.rb +162 -15
- data/lib/astronoby/bodies/neptune.rb +10 -0
- data/lib/astronoby/bodies/saturn.rb +10 -0
- data/lib/astronoby/bodies/solar_system_body.rb +257 -53
- data/lib/astronoby/bodies/sun.rb +79 -4
- data/lib/astronoby/bodies/uranus.rb +10 -0
- data/lib/astronoby/bodies/venus.rb +10 -0
- data/lib/astronoby/body.rb +6 -0
- data/lib/astronoby/cache.rb +1 -0
- data/lib/astronoby/center.rb +84 -0
- data/lib/astronoby/constants.rb +7 -2
- data/lib/astronoby/constellation.rb +9 -1
- data/lib/astronoby/coordinates/ecliptic.rb +10 -1
- data/lib/astronoby/coordinates/equatorial.rb +66 -13
- data/lib/astronoby/coordinates/geodetic.rb +102 -0
- data/lib/astronoby/coordinates/horizontal.rb +13 -1
- data/lib/astronoby/distance.rb +41 -0
- data/lib/astronoby/duration.rb +116 -0
- data/lib/astronoby/earth_rotation.rb +70 -0
- data/lib/astronoby/equinox_solstice.rb +31 -8
- data/lib/astronoby/errors.rb +11 -0
- data/lib/astronoby/events/conjunction.rb +51 -0
- data/lib/astronoby/events/conjunction_opposition_calculator.rb +84 -0
- data/lib/astronoby/events/eclipse_phase.rb +27 -0
- data/lib/astronoby/events/extremum_calculator.rb +80 -0
- data/lib/astronoby/events/extremum_event.rb +15 -0
- data/lib/astronoby/events/greatest_elongation.rb +58 -0
- data/lib/astronoby/events/greatest_elongation_calculator.rb +56 -0
- data/lib/astronoby/events/lunar_eclipse.rb +99 -0
- data/lib/astronoby/events/lunar_eclipse_calculator.rb +285 -0
- data/lib/astronoby/events/opposition.rb +19 -0
- data/lib/astronoby/events/rise_transit_set_calculator.rb +9 -6
- data/lib/astronoby/events/rise_transit_set_event.rb +12 -1
- data/lib/astronoby/events/rise_transit_set_events.rb +12 -1
- data/lib/astronoby/events/twilight_calculator.rb +1 -1
- data/lib/astronoby/events/twilight_event.rb +24 -6
- data/lib/astronoby/events/twilight_events.rb +26 -6
- data/lib/astronoby/extremum_finder.rb +148 -0
- data/lib/astronoby/instant.rb +35 -9
- data/lib/astronoby/libration.rb +25 -0
- data/lib/astronoby/mean_obliquity.rb +8 -0
- data/lib/astronoby/moon_orientation_ephemeris.rb +69 -0
- data/lib/astronoby/moon_physical_ephemeris.rb +263 -0
- data/lib/astronoby/nutation.rb +10 -20
- data/lib/astronoby/observer.rb +67 -49
- data/lib/astronoby/orientation.rb +107 -0
- data/lib/astronoby/position.rb +16 -0
- data/lib/astronoby/precession.rb +61 -60
- data/lib/astronoby/reference_frame.rb +73 -7
- data/lib/astronoby/reference_frames/apparent.rb +25 -16
- data/lib/astronoby/reference_frames/astrometric.rb +14 -1
- data/lib/astronoby/reference_frames/geometric.rb +7 -1
- data/lib/astronoby/reference_frames/mean_of_date.rb +13 -1
- data/lib/astronoby/reference_frames/teme.rb +153 -0
- data/lib/astronoby/reference_frames/topocentric.rb +31 -5
- data/lib/astronoby/refraction.rb +26 -5
- data/lib/astronoby/root_finder.rb +83 -0
- data/lib/astronoby/rotation.rb +49 -0
- data/lib/astronoby/stellar_propagation.rb +162 -0
- data/lib/astronoby/time/greenwich_apparent_sidereal_time.rb +31 -0
- data/lib/astronoby/time/greenwich_mean_sidereal_time.rb +101 -0
- data/lib/astronoby/time/greenwich_sidereal_time.rb +41 -58
- data/lib/astronoby/time/local_apparent_sidereal_time.rb +63 -0
- data/lib/astronoby/time/local_mean_sidereal_time.rb +63 -0
- data/lib/astronoby/time/local_sidereal_time.rb +59 -26
- data/lib/astronoby/time/sidereal_time.rb +64 -0
- data/lib/astronoby/true_obliquity.rb +4 -0
- data/lib/astronoby/util/maths.rb +8 -0
- data/lib/astronoby/util/time.rb +10 -467
- data/lib/astronoby/vector.rb +10 -0
- data/lib/astronoby/velocity.rb +44 -0
- data/lib/astronoby/version.rb +1 -1
- data/lib/astronoby.rb +33 -0
- metadata +58 -6
data/lib/astronoby/angle.rb
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Astronoby
|
|
4
|
+
# Represents an angle with radians as its internal representation.
|
|
5
|
+
# Provides conversions between radians, degrees, hours, and sexagesimal
|
|
6
|
+
# formats (DMS and HMS), as well as trigonometric operations.
|
|
7
|
+
#
|
|
8
|
+
# @example Create an angle from degrees
|
|
9
|
+
# angle = Astronoby::Angle.from_degrees(180)
|
|
10
|
+
# angle.radians # => Math::PI
|
|
11
|
+
#
|
|
12
|
+
# @example Create an angle from hours, minutes, seconds
|
|
13
|
+
# angle = Astronoby::Angle.from_hms(12, 30, 0)
|
|
14
|
+
#
|
|
4
15
|
class Angle
|
|
5
16
|
include Comparable
|
|
6
17
|
|
|
@@ -8,29 +19,42 @@ module Astronoby
|
|
|
8
19
|
FORMATS = %i[dms hms].freeze
|
|
9
20
|
|
|
10
21
|
class << self
|
|
22
|
+
# @return [Astronoby::Angle] a zero angle
|
|
11
23
|
def zero
|
|
12
24
|
new(0)
|
|
13
25
|
end
|
|
14
26
|
|
|
27
|
+
# @param radians [Numeric] the angle in radians
|
|
28
|
+
# @return [Astronoby::Angle] a new Angle, normalized to (-2π, 2π)
|
|
15
29
|
def from_radians(radians)
|
|
16
30
|
normalized_radians = radians.remainder(Constants::RADIANS_PER_CIRCLE)
|
|
17
31
|
new(normalized_radians)
|
|
18
32
|
end
|
|
19
33
|
|
|
34
|
+
# @param degrees [Numeric] the angle in degrees
|
|
35
|
+
# @return [Astronoby::Angle] a new Angle
|
|
20
36
|
def from_degrees(degrees)
|
|
21
37
|
radians = degrees / Constants::PI_IN_DEGREES * Math::PI
|
|
22
38
|
from_radians(radians)
|
|
23
39
|
end
|
|
24
40
|
|
|
41
|
+
# @param arcseconds [Numeric] the angle in arcseconds
|
|
42
|
+
# @return [Astronoby::Angle] a new Angle
|
|
25
43
|
def from_degree_arcseconds(arcseconds)
|
|
26
44
|
from_dms(0, 0, arcseconds)
|
|
27
45
|
end
|
|
28
46
|
|
|
47
|
+
# @param hours [Numeric] the angle in hour-angle hours
|
|
48
|
+
# @return [Astronoby::Angle] a new Angle
|
|
29
49
|
def from_hours(hours)
|
|
30
50
|
radians = hours * Constants::RADIAN_PER_HOUR
|
|
31
51
|
from_radians(radians)
|
|
32
52
|
end
|
|
33
53
|
|
|
54
|
+
# @param hour [Numeric] hours component
|
|
55
|
+
# @param minute [Numeric] minutes component
|
|
56
|
+
# @param second [Numeric] seconds component
|
|
57
|
+
# @return [Astronoby::Angle] a new Angle
|
|
34
58
|
def from_hms(hour, minute, second)
|
|
35
59
|
hours = hour +
|
|
36
60
|
minute / Constants::MINUTES_PER_HOUR +
|
|
@@ -38,85 +62,118 @@ module Astronoby
|
|
|
38
62
|
from_hours(hours)
|
|
39
63
|
end
|
|
40
64
|
|
|
65
|
+
# @param degree [Numeric] degrees component (sign determines overall sign)
|
|
66
|
+
# @param minute [Numeric] arcminutes component
|
|
67
|
+
# @param second [Numeric] arcseconds component
|
|
68
|
+
# @return [Astronoby::Angle] a new Angle
|
|
41
69
|
def from_dms(degree, minute, second)
|
|
42
70
|
sign = degree.negative? ? -1 : 1
|
|
43
71
|
degrees = degree.abs +
|
|
44
|
-
minute / Constants::
|
|
45
|
-
second / Constants::
|
|
72
|
+
minute / Constants::ARCMINUTES_PER_DEGREE +
|
|
73
|
+
second / Constants::ARCSECONDS_PER_DEGREE
|
|
46
74
|
from_degrees(sign * degrees)
|
|
47
75
|
end
|
|
48
76
|
|
|
77
|
+
# @param ratio [Numeric] the sine value (-1..1)
|
|
78
|
+
# @return [Astronoby::Angle] the arcsine
|
|
49
79
|
def asin(ratio)
|
|
50
80
|
radians = Math.asin(ratio)
|
|
51
81
|
from_radians(radians)
|
|
52
82
|
end
|
|
53
83
|
|
|
84
|
+
# @param ratio [Numeric] the cosine value (-1..1)
|
|
85
|
+
# @return [Astronoby::Angle] the arccosine
|
|
54
86
|
def acos(ratio)
|
|
55
87
|
radians = Math.acos(ratio)
|
|
56
88
|
from_radians(radians)
|
|
57
89
|
end
|
|
58
90
|
|
|
91
|
+
# @param ratio [Numeric] the tangent value
|
|
92
|
+
# @return [Astronoby::Angle] the arctangent
|
|
59
93
|
def atan(ratio)
|
|
60
94
|
radians = Math.atan(ratio)
|
|
61
95
|
from_radians(radians)
|
|
62
96
|
end
|
|
63
97
|
end
|
|
64
98
|
|
|
99
|
+
# @return [Numeric] the angle in radians
|
|
65
100
|
attr_reader :radians
|
|
66
101
|
|
|
102
|
+
# @param radians [Numeric] the angle in radians
|
|
67
103
|
def initialize(radians)
|
|
68
104
|
@radians = radians
|
|
69
105
|
freeze
|
|
70
106
|
end
|
|
71
107
|
|
|
108
|
+
# @return [Float] the angle in degrees
|
|
72
109
|
def degrees
|
|
73
110
|
@radians * Constants::PI_IN_DEGREES / Math::PI
|
|
74
111
|
end
|
|
75
112
|
|
|
113
|
+
# @return [Float] the angle in milliarcseconds
|
|
114
|
+
def degree_milliarcseconds
|
|
115
|
+
degrees * Constants::MILLIARCSECONDS_PER_DEGREE
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @return [Float] the angle in hour-angle hours
|
|
76
119
|
def hours
|
|
77
120
|
@radians / Constants::RADIAN_PER_HOUR
|
|
78
121
|
end
|
|
79
122
|
|
|
123
|
+
# @param other [Astronoby::Angle] angle to add
|
|
124
|
+
# @return [Astronoby::Angle] the sum
|
|
80
125
|
def +(other)
|
|
81
126
|
self.class.from_radians(radians + other.radians)
|
|
82
127
|
end
|
|
83
128
|
|
|
129
|
+
# @param other [Astronoby::Angle] angle to subtract
|
|
130
|
+
# @return [Astronoby::Angle] the difference
|
|
84
131
|
def -(other)
|
|
85
132
|
self.class.from_radians(@radians - other.radians)
|
|
86
133
|
end
|
|
87
134
|
|
|
135
|
+
# @return [Astronoby::Angle] the negated angle
|
|
88
136
|
def -@
|
|
89
137
|
self.class.from_radians(-@radians)
|
|
90
138
|
end
|
|
91
139
|
|
|
140
|
+
# @return [Float] the sine of the angle
|
|
92
141
|
def sin
|
|
93
142
|
Math.sin(radians)
|
|
94
143
|
end
|
|
95
144
|
|
|
145
|
+
# @return [Float] the cosine of the angle
|
|
96
146
|
def cos
|
|
97
147
|
Math.cos(radians)
|
|
98
148
|
end
|
|
99
149
|
|
|
150
|
+
# @return [Float] the tangent of the angle
|
|
100
151
|
def tan
|
|
101
152
|
Math.tan(radians)
|
|
102
153
|
end
|
|
103
154
|
|
|
155
|
+
# @return [Boolean] true if the angle is positive
|
|
104
156
|
def positive?
|
|
105
157
|
radians > 0
|
|
106
158
|
end
|
|
107
159
|
|
|
160
|
+
# @return [Boolean] true if the angle is negative
|
|
108
161
|
def negative?
|
|
109
162
|
radians < 0
|
|
110
163
|
end
|
|
111
164
|
|
|
165
|
+
# @return [Boolean] true if the angle is zero
|
|
112
166
|
def zero?
|
|
113
167
|
radians.zero?
|
|
114
168
|
end
|
|
115
169
|
|
|
170
|
+
# @return [Integer] hash value
|
|
116
171
|
def hash
|
|
117
172
|
[radians, self.class].hash
|
|
118
173
|
end
|
|
119
174
|
|
|
175
|
+
# @param other [Astronoby::Angle] angle to compare with
|
|
176
|
+
# @return [Integer, nil] -1, 0, or 1; nil if not comparable
|
|
120
177
|
def <=>(other)
|
|
121
178
|
return unless other.is_a?(self.class)
|
|
122
179
|
|
|
@@ -124,6 +181,12 @@ module Astronoby
|
|
|
124
181
|
end
|
|
125
182
|
alias_method :eql?, :==
|
|
126
183
|
|
|
184
|
+
# Formats the angle as a string in the given format.
|
|
185
|
+
#
|
|
186
|
+
# @param format [Symbol] :dms or :hms
|
|
187
|
+
# @param precision [Integer] decimal places for seconds
|
|
188
|
+
# @return [String] the formatted angle
|
|
189
|
+
# @raise [Astronoby::UnsupportedFormatError] if format is not :dms or :hms
|
|
127
190
|
def str(format, precision: 4)
|
|
128
191
|
case format
|
|
129
192
|
when :dms then to_dms.format(precision: precision)
|
|
@@ -135,14 +198,15 @@ module Astronoby
|
|
|
135
198
|
end
|
|
136
199
|
end
|
|
137
200
|
|
|
201
|
+
# @return [Astronoby::Dms] the angle in degrees, arcminutes, arcseconds
|
|
138
202
|
def to_dms
|
|
139
203
|
sign = degrees.negative? ? "-" : "+"
|
|
140
204
|
absolute_degrees = degrees.abs
|
|
141
205
|
deg = absolute_degrees.floor
|
|
142
|
-
decimal_minutes = Constants::
|
|
206
|
+
decimal_minutes = Constants::ARCMINUTES_PER_DEGREE *
|
|
143
207
|
(absolute_degrees - deg)
|
|
144
208
|
absolute_decimal_minutes = (
|
|
145
|
-
Constants::
|
|
209
|
+
Constants::ARCMINUTES_PER_DEGREE * (absolute_degrees - deg)
|
|
146
210
|
).abs
|
|
147
211
|
minutes = decimal_minutes.floor
|
|
148
212
|
seconds = Constants::SECONDS_PER_MINUTE * (
|
|
@@ -152,6 +216,7 @@ module Astronoby
|
|
|
152
216
|
Dms.new(sign, deg, minutes, seconds)
|
|
153
217
|
end
|
|
154
218
|
|
|
219
|
+
# @return [Astronoby::Hms] the angle in hours, minutes, seconds
|
|
155
220
|
def to_hms
|
|
156
221
|
absolute_hours = hours.abs
|
|
157
222
|
hrs = absolute_hours.floor
|
data/lib/astronoby/angles/dms.rb
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Astronoby
|
|
4
|
+
# Represents an angle in degrees, arcminutes, arcseconds (DMS) notation.
|
|
4
5
|
class Dms
|
|
5
|
-
|
|
6
|
+
# @return [String] "+" or "-"
|
|
7
|
+
attr_reader :sign
|
|
6
8
|
|
|
9
|
+
# @return [Integer] degrees component
|
|
10
|
+
attr_reader :degrees
|
|
11
|
+
|
|
12
|
+
# @return [Integer] arcminutes component
|
|
13
|
+
attr_reader :minutes
|
|
14
|
+
|
|
15
|
+
# @return [Float] arcseconds component
|
|
16
|
+
attr_reader :seconds
|
|
17
|
+
|
|
18
|
+
# @param sign [String] "+" or "-"
|
|
19
|
+
# @param degrees [Integer] degrees component
|
|
20
|
+
# @param minutes [Integer] arcminutes component
|
|
21
|
+
# @param seconds [Float] arcseconds component
|
|
7
22
|
def initialize(sign, degrees, minutes, seconds)
|
|
8
23
|
@sign = sign
|
|
9
24
|
@degrees = degrees
|
|
@@ -11,6 +26,8 @@ module Astronoby
|
|
|
11
26
|
@seconds = seconds
|
|
12
27
|
end
|
|
13
28
|
|
|
29
|
+
# @param precision [Integer] decimal places for the seconds component
|
|
30
|
+
# @return [String] the formatted DMS string (e.g., "+45° 30′ 15.0000″")
|
|
14
31
|
def format(precision: 4)
|
|
15
32
|
"#{sign}#{degrees}° #{minutes}′ #{seconds.floor(precision)}″"
|
|
16
33
|
end
|
data/lib/astronoby/angles/hms.rb
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Astronoby
|
|
4
|
+
# Represents an angle in hours, minutes, seconds (HMS) notation.
|
|
4
5
|
class Hms
|
|
5
|
-
|
|
6
|
+
# @return [Integer] hours component
|
|
7
|
+
attr_reader :hours
|
|
6
8
|
|
|
9
|
+
# @return [Integer] minutes component
|
|
10
|
+
attr_reader :minutes
|
|
11
|
+
|
|
12
|
+
# @return [Float] seconds component
|
|
13
|
+
attr_reader :seconds
|
|
14
|
+
|
|
15
|
+
# @param hours [Integer] hours component
|
|
16
|
+
# @param minutes [Integer] minutes component
|
|
17
|
+
# @param seconds [Float] seconds component
|
|
7
18
|
def initialize(hours, minutes, seconds)
|
|
8
19
|
@hours = hours
|
|
9
20
|
@minutes = minutes
|
|
10
21
|
@seconds = seconds
|
|
11
22
|
end
|
|
12
23
|
|
|
24
|
+
# @param precision [Integer] decimal places for the seconds component
|
|
25
|
+
# @return [String] the formatted HMS string (e.g., "12h 30m 45.0000s")
|
|
13
26
|
def format(precision: 4)
|
|
14
27
|
"#{hours}h #{minutes}m #{seconds.floor(precision)}s"
|
|
15
28
|
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Astronoby
|
|
4
|
+
# Represents an angular velocity with radians per second as its internal
|
|
5
|
+
# representation. Used primarily for stellar proper motion.
|
|
6
|
+
class AngularVelocity
|
|
7
|
+
include Comparable
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# @return [Astronoby::AngularVelocity] a zero angular velocity
|
|
11
|
+
def zero
|
|
12
|
+
new(0)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param radians_per_second [Numeric] the angular velocity in rad/s
|
|
16
|
+
# @return [Astronoby::AngularVelocity] a new AngularVelocity
|
|
17
|
+
def from_radians_per_second(radians_per_second)
|
|
18
|
+
new(radians_per_second)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param mas_per_year [Numeric] the angular velocity in mas/yr
|
|
22
|
+
# @return [Astronoby::AngularVelocity] a new AngularVelocity
|
|
23
|
+
def from_milliarcseconds_per_year(mas_per_year)
|
|
24
|
+
angle = Angle.from_degree_arcseconds(mas_per_year / 1000.0)
|
|
25
|
+
radians_per_second = angle.radians / Constants::SECONDS_PER_JULIAN_YEAR
|
|
26
|
+
new(radians_per_second)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Numeric] the angular velocity in radians per second
|
|
31
|
+
attr_reader :radians_per_second
|
|
32
|
+
alias_method :rps, :radians_per_second
|
|
33
|
+
|
|
34
|
+
# @param radians_per_second [Numeric] the angular velocity in rad/s
|
|
35
|
+
def initialize(radians_per_second)
|
|
36
|
+
@radians_per_second = radians_per_second
|
|
37
|
+
freeze
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [Float] the angular velocity in milliarcseconds per year
|
|
41
|
+
def milliarcseconds_per_year
|
|
42
|
+
angle = Angle.from_radians(@radians_per_second)
|
|
43
|
+
angle.degree_milliarcseconds * Constants::SECONDS_PER_JULIAN_YEAR
|
|
44
|
+
end
|
|
45
|
+
alias_method :mas_per_year, :milliarcseconds_per_year
|
|
46
|
+
|
|
47
|
+
# @param other [Astronoby::AngularVelocity] angular velocity to add
|
|
48
|
+
# @return [Astronoby::AngularVelocity] the sum
|
|
49
|
+
def +(other)
|
|
50
|
+
self.class.from_radians_per_second(
|
|
51
|
+
@radians_per_second + other.radians_per_second
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @param other [Astronoby::AngularVelocity] angular velocity to subtract
|
|
56
|
+
# @return [Astronoby::AngularVelocity] the difference
|
|
57
|
+
def -(other)
|
|
58
|
+
self.class.from_radians_per_second(
|
|
59
|
+
@radians_per_second - other.radians_per_second
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Astronoby::AngularVelocity] the negated angular velocity
|
|
64
|
+
def -@
|
|
65
|
+
self.class.from_radians_per_second(-@radians_per_second)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @return [Boolean] true if the angular velocity is positive
|
|
69
|
+
def positive?
|
|
70
|
+
@radians_per_second > 0
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @return [Boolean] true if the angular velocity is negative
|
|
74
|
+
def negative?
|
|
75
|
+
@radians_per_second < 0
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @return [Boolean] true if the angular velocity is zero
|
|
79
|
+
def zero?
|
|
80
|
+
@radians_per_second.zero?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @return [Integer] hash value
|
|
84
|
+
def hash
|
|
85
|
+
[@radians_per_second, self.class].hash
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @param other [Astronoby::AngularVelocity] angular velocity to compare with
|
|
89
|
+
# @return [Integer, nil] -1, 0, or 1; nil if not comparable
|
|
90
|
+
def <=>(other)
|
|
91
|
+
return unless other.is_a?(self.class)
|
|
92
|
+
|
|
93
|
+
@radians_per_second <=> other.radians_per_second
|
|
94
|
+
end
|
|
95
|
+
alias_method :eql?, :==
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Astronoby
|
|
4
|
+
# Represents a deep-sky object (star, galaxy, nebula, etc.) with optional
|
|
5
|
+
# proper motion and parallax data.
|
|
6
|
+
class DeepSkyObject
|
|
7
|
+
include Body
|
|
8
|
+
|
|
9
|
+
# @param equatorial_coordinates [Astronoby::Coordinates::Equatorial]
|
|
10
|
+
# Equatorial coordinates at epoch J2000.0
|
|
11
|
+
# @param proper_motion_ra [Astronoby::AngularVelocity, nil] Proper motion in
|
|
12
|
+
# right ascension
|
|
13
|
+
# @param proper_motion_dec [Astronoby::AngularVelocity, nil] Proper motion
|
|
14
|
+
# in declination
|
|
15
|
+
# @param parallax [Astronoby::Angle, nil] Parallax angle
|
|
16
|
+
# @param radial_velocity [Astronoby::Velocity, nil] Radial velocity
|
|
17
|
+
def initialize(
|
|
18
|
+
equatorial_coordinates:,
|
|
19
|
+
proper_motion_ra: nil,
|
|
20
|
+
proper_motion_dec: nil,
|
|
21
|
+
parallax: nil,
|
|
22
|
+
radial_velocity: nil
|
|
23
|
+
)
|
|
24
|
+
@initial_equatorial_coordinates = equatorial_coordinates
|
|
25
|
+
@proper_motion_ra = proper_motion_ra
|
|
26
|
+
@proper_motion_dec = proper_motion_dec
|
|
27
|
+
@parallax = parallax
|
|
28
|
+
@radial_velocity = radial_velocity
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @param instant [Astronoby::Instant] Instant of the observation
|
|
32
|
+
# @param ephem [Astronoby::Ephemeris, nil] Ephemeris to use for Earth
|
|
33
|
+
# position calculation
|
|
34
|
+
# @return [Astronoby::DeepSkyObjectPosition] Position of the deep-sky object
|
|
35
|
+
# at the given instant
|
|
36
|
+
def at(instant, ephem: nil)
|
|
37
|
+
DeepSkyObjectPosition.new(
|
|
38
|
+
instant: instant,
|
|
39
|
+
equatorial_coordinates: @initial_equatorial_coordinates,
|
|
40
|
+
ephem: ephem,
|
|
41
|
+
proper_motion_ra: @proper_motion_ra,
|
|
42
|
+
proper_motion_dec: @proper_motion_dec,
|
|
43
|
+
parallax: @parallax,
|
|
44
|
+
radial_velocity: @radial_velocity,
|
|
45
|
+
deep_sky_object: self
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Astronoby
|
|
4
|
+
# Represents the computed position of a deep-sky object at a specific
|
|
5
|
+
# instant, providing astrometric, apparent, and topocentric reference frames.
|
|
6
|
+
class DeepSkyObjectPosition
|
|
7
|
+
include Position
|
|
8
|
+
|
|
9
|
+
DEFAULT_DISTANCE = Distance.from_parsecs(1e9)
|
|
10
|
+
|
|
11
|
+
# @return [Astronoby::Instant] the time instant
|
|
12
|
+
attr_reader :instant
|
|
13
|
+
|
|
14
|
+
# @return [Astronoby::Apparent] the apparent reference frame
|
|
15
|
+
attr_reader :apparent
|
|
16
|
+
|
|
17
|
+
# @return [Astronoby::DeepSkyObject, nil] the body definition
|
|
18
|
+
attr_reader :body
|
|
19
|
+
|
|
20
|
+
# @param instant [Astronoby::Instant] Instant of the observation
|
|
21
|
+
# @param equatorial_coordinates [Astronoby::Coordinates::Equatorial]
|
|
22
|
+
# Equatorial coordinates at epoch J2000.0
|
|
23
|
+
# @param ephem [::Ephem::SPK, nil] Ephemeris data source for Earth position
|
|
24
|
+
# @param proper_motion_ra [Astronoby::AngularVelocity, nil] Proper motion in
|
|
25
|
+
# right ascension
|
|
26
|
+
# @param proper_motion_dec [Astronoby::AngularVelocity, nil] Proper motion
|
|
27
|
+
# in declination
|
|
28
|
+
# @param parallax [Astronoby::Angle, nil] Parallax angle
|
|
29
|
+
# @param radial_velocity [Astronoby::Velocity, nil] Radial velocity
|
|
30
|
+
# @param deep_sky_object [Astronoby::DeepSkyObject, nil] the body definition
|
|
31
|
+
def initialize(
|
|
32
|
+
instant:,
|
|
33
|
+
equatorial_coordinates:,
|
|
34
|
+
ephem: nil,
|
|
35
|
+
proper_motion_ra: nil,
|
|
36
|
+
proper_motion_dec: nil,
|
|
37
|
+
parallax: nil,
|
|
38
|
+
radial_velocity: nil,
|
|
39
|
+
deep_sky_object: nil
|
|
40
|
+
)
|
|
41
|
+
@instant = instant
|
|
42
|
+
@initial_equatorial_coordinates = equatorial_coordinates
|
|
43
|
+
@proper_motion_ra = proper_motion_ra
|
|
44
|
+
@proper_motion_dec = proper_motion_dec
|
|
45
|
+
@parallax = parallax
|
|
46
|
+
@radial_velocity = radial_velocity
|
|
47
|
+
@body = deep_sky_object
|
|
48
|
+
if ephem
|
|
49
|
+
@earth_geometric = Earth.geometric(ephem: ephem, instant: @instant)
|
|
50
|
+
end
|
|
51
|
+
compute_apparent
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Astronoby::Astrometric] Astrometric position of the object
|
|
55
|
+
def astrometric
|
|
56
|
+
@astrometric ||= Astrometric.new(
|
|
57
|
+
instant: @instant,
|
|
58
|
+
position: astrometric_position,
|
|
59
|
+
velocity: astrometric_velocity,
|
|
60
|
+
center: Center.geocentric,
|
|
61
|
+
target_body: body
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def astrometric_position
|
|
68
|
+
@astrometric_position ||=
|
|
69
|
+
if @earth_geometric
|
|
70
|
+
barycentric_position - @earth_geometric.position
|
|
71
|
+
else
|
|
72
|
+
barycentric_position
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def barycentric_position
|
|
77
|
+
if use_stellar_propagation?
|
|
78
|
+
stellar_propagation.position
|
|
79
|
+
else
|
|
80
|
+
astronomical_distance = DEFAULT_DISTANCE.meters
|
|
81
|
+
right_ascension = @initial_equatorial_coordinates.right_ascension
|
|
82
|
+
declination = @initial_equatorial_coordinates.declination
|
|
83
|
+
Distance.vector_from_meters([
|
|
84
|
+
declination.cos * right_ascension.cos * astronomical_distance,
|
|
85
|
+
declination.cos * right_ascension.sin * astronomical_distance,
|
|
86
|
+
declination.sin * astronomical_distance
|
|
87
|
+
])
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def astrometric_velocity
|
|
92
|
+
@astrometric_velocity ||= if use_stellar_propagation?
|
|
93
|
+
stellar_propagation.velocity_vector
|
|
94
|
+
else
|
|
95
|
+
Velocity.vector_from_meters_per_second([0.0, 0.0, 0.0])
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def use_stellar_propagation?
|
|
100
|
+
@proper_motion_ra && @proper_motion_dec && @parallax && @radial_velocity
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def stellar_propagation
|
|
104
|
+
@stellar_propagation ||= StellarPropagation.new(
|
|
105
|
+
equatorial_coordinates: @initial_equatorial_coordinates,
|
|
106
|
+
proper_motion_ra: @proper_motion_ra,
|
|
107
|
+
proper_motion_dec: @proper_motion_dec,
|
|
108
|
+
parallax: @parallax,
|
|
109
|
+
radial_velocity: @radial_velocity,
|
|
110
|
+
instant: @instant,
|
|
111
|
+
earth_geometric: @earth_geometric
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def compute_apparent
|
|
116
|
+
@apparent = if @earth_geometric
|
|
117
|
+
Apparent.build_from_astrometric(
|
|
118
|
+
instant: @instant,
|
|
119
|
+
target_astrometric: astrometric,
|
|
120
|
+
earth_geometric: @earth_geometric,
|
|
121
|
+
target_body: body
|
|
122
|
+
)
|
|
123
|
+
else
|
|
124
|
+
precession_matrix = Precession.matrix_for(@instant)
|
|
125
|
+
nutation_matrix = Nutation.matrix_for(@instant)
|
|
126
|
+
corrected_position = Distance.vector_from_meters(
|
|
127
|
+
precession_matrix * nutation_matrix * astrometric.position.map(&:m)
|
|
128
|
+
)
|
|
129
|
+
corrected_velocity = Velocity.vector_from_mps(
|
|
130
|
+
precession_matrix * nutation_matrix * astrometric.velocity.map(&:mps)
|
|
131
|
+
)
|
|
132
|
+
Apparent.new(
|
|
133
|
+
position: corrected_position,
|
|
134
|
+
velocity: corrected_velocity,
|
|
135
|
+
instant: @instant,
|
|
136
|
+
center: Center.geocentric,
|
|
137
|
+
target_body: body
|
|
138
|
+
)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Astronoby
|
|
4
|
+
# Represents the Earth. Provides ephemeris segments for computing Earth's
|
|
5
|
+
# geometric position.
|
|
4
6
|
class Earth < SolarSystemBody
|
|
7
|
+
ORBITAL_PERIOD = 365.256
|
|
8
|
+
|
|
9
|
+
# @param ephem_source [Symbol] the ephemeris source type
|
|
10
|
+
# @return [Array<Array>] ephemeris segment identifiers
|
|
5
11
|
def self.ephemeris_segments(ephem_source)
|
|
6
12
|
if ephem_source == ::Ephem::SPK::JPL_DE
|
|
7
13
|
[
|
|
@@ -15,48 +21,9 @@ module Astronoby
|
|
|
15
21
|
end
|
|
16
22
|
end
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# applicable for Earth.
|
|
22
|
-
def requires_sun_data?
|
|
23
|
-
false
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def compute_astrometric(_ephem)
|
|
27
|
-
Astrometric.new(
|
|
28
|
-
position: Vector[
|
|
29
|
-
Distance.zero,
|
|
30
|
-
Distance.zero,
|
|
31
|
-
Distance.zero
|
|
32
|
-
],
|
|
33
|
-
velocity: Vector[
|
|
34
|
-
Velocity.zero,
|
|
35
|
-
Velocity.zero,
|
|
36
|
-
Velocity.zero
|
|
37
|
-
],
|
|
38
|
-
instant: @instant,
|
|
39
|
-
center_identifier: EARTH,
|
|
40
|
-
target_body: self.class
|
|
41
|
-
)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def compute_mean_of_date(_ephem)
|
|
45
|
-
MeanOfDate.new(
|
|
46
|
-
position: Vector[
|
|
47
|
-
Distance.zero,
|
|
48
|
-
Distance.zero,
|
|
49
|
-
Distance.zero
|
|
50
|
-
],
|
|
51
|
-
velocity: Vector[
|
|
52
|
-
Velocity.zero,
|
|
53
|
-
Velocity.zero,
|
|
54
|
-
Velocity.zero
|
|
55
|
-
],
|
|
56
|
-
instant: @instant,
|
|
57
|
-
center_identifier: EARTH,
|
|
58
|
-
target_body: self.class
|
|
59
|
-
)
|
|
24
|
+
# @return [nil] Earth has no phase angle as seen from itself
|
|
25
|
+
def phase_angle
|
|
26
|
+
nil
|
|
60
27
|
end
|
|
61
28
|
end
|
|
62
29
|
end
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Astronoby
|
|
4
|
+
# Represents Jupiter.
|
|
4
5
|
class Jupiter < SolarSystemBody
|
|
5
6
|
EQUATORIAL_RADIUS = Distance.from_meters(71_492_000)
|
|
6
7
|
ABSOLUTE_MAGNITUDE = -9.395
|
|
8
|
+
ORBITAL_PERIOD = 4332.59
|
|
7
9
|
|
|
10
|
+
# @return [Boolean] true; Jupiter is a superior planet
|
|
11
|
+
def self.superior_planet?
|
|
12
|
+
true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param _ephem_source [Symbol] the ephemeris source type
|
|
16
|
+
# @return [Array<Array>] ephemeris segment identifiers
|
|
8
17
|
def self.ephemeris_segments(_ephem_source)
|
|
9
18
|
[[SOLAR_SYSTEM_BARYCENTER, JUPITER_BARYCENTER]]
|
|
10
19
|
end
|
|
11
20
|
|
|
21
|
+
# @return [Float] absolute magnitude
|
|
12
22
|
def self.absolute_magnitude
|
|
13
23
|
ABSOLUTE_MAGNITUDE
|
|
14
24
|
end
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Astronoby
|
|
4
|
+
# Represents Mars.
|
|
4
5
|
class Mars < SolarSystemBody
|
|
5
6
|
EQUATORIAL_RADIUS = Distance.from_meters(3_396_200)
|
|
6
7
|
ABSOLUTE_MAGNITUDE = -1.601
|
|
8
|
+
ORBITAL_PERIOD = 686.98
|
|
7
9
|
|
|
10
|
+
# @return [Boolean] true; Mars is a superior planet
|
|
11
|
+
def self.superior_planet?
|
|
12
|
+
true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param _ephem_source [Symbol] the ephemeris source type
|
|
16
|
+
# @return [Array<Array>] ephemeris segment identifiers
|
|
8
17
|
def self.ephemeris_segments(_ephem_source)
|
|
9
18
|
[[SOLAR_SYSTEM_BARYCENTER, MARS_BARYCENTER]]
|
|
10
19
|
end
|
|
11
20
|
|
|
21
|
+
# @return [Float] absolute magnitude
|
|
12
22
|
def self.absolute_magnitude
|
|
13
23
|
ABSOLUTE_MAGNITUDE
|
|
14
24
|
end
|