ephem 0.4.1 → 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.
- checksums.yaml +4 -4
- data/.tool-versions +1 -1
- data/CHANGELOG.md +121 -32
- data/README.md +81 -4
- data/benchmarks/run.rb +431 -0
- data/lib/ephem/cli.rb +26 -13
- data/lib/ephem/computation/chebyshev_polynomial.rb +63 -4
- data/lib/ephem/core/orientation.rb +118 -0
- data/lib/ephem/core/rotation.rb +82 -0
- data/lib/ephem/core/state.rb +5 -0
- data/lib/ephem/download.rb +33 -3
- data/lib/ephem/excerpt.rb +17 -12
- data/lib/ephem/io/binary_reader.rb +6 -4
- data/lib/ephem/io/daf.rb +18 -1
- data/lib/ephem/io/record_parser.rb +2 -2
- data/lib/ephem/io/summary_manager.rb +14 -15
- data/lib/ephem/pck.rb +118 -0
- data/lib/ephem/segments/base_segment.rb +25 -8
- data/lib/ephem/segments/chebyshev_type2.rb +142 -0
- data/lib/ephem/segments/orientation_group.rb +59 -0
- data/lib/ephem/segments/orientation_segment.rb +118 -0
- data/lib/ephem/segments/orientation_source.rb +17 -0
- data/lib/ephem/segments/position_group.rb +46 -0
- data/lib/ephem/segments/registry.rb +9 -3
- data/lib/ephem/segments/segment.rb +24 -224
- data/lib/ephem/segments/segment_group.rb +84 -0
- data/lib/ephem/spk.rb +20 -9
- data/lib/ephem/version.rb +1 -1
- data/lib/ephem.rb +9 -0
- metadata +27 -17
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "numo/narray"
|
|
4
|
-
|
|
5
3
|
module Ephem
|
|
6
4
|
module Segments
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# Each segment contains data for a specific celestial body (target) relative
|
|
12
|
-
# to another body (center) within a specific time range. The data is stored
|
|
13
|
-
# as Chebyshev polynomial coefficients that can be evaluated to obtain
|
|
14
|
-
# position and velocity vectors.
|
|
15
|
-
#
|
|
16
|
-
# The class provides thread-safe data loading and caching mechanisms to
|
|
17
|
-
# optimize performance while ensuring data consistency in multithreaded
|
|
18
|
-
# environments.
|
|
5
|
+
# SPK trajectory segment: position (type 2) and position/velocity (type 3)
|
|
6
|
+
# of a target body relative to a center body, stored as Chebyshev
|
|
7
|
+
# coefficients.
|
|
19
8
|
#
|
|
20
9
|
# @example Computing position at a specific time
|
|
21
10
|
# segment = Ephem::Segments::Segment.new(
|
|
@@ -27,29 +16,18 @@ module Ephem
|
|
|
27
16
|
#
|
|
28
17
|
# @example Computing position and velocity
|
|
29
18
|
# state = segment.compute_and_differentiate(time) # returns State
|
|
30
|
-
# position = state.position # Vector
|
|
31
|
-
# velocity = state.velocity # Vector
|
|
32
19
|
#
|
|
33
20
|
# @see Ephem::Core::Vector
|
|
34
21
|
# @see Ephem::Core::State
|
|
35
|
-
# @see Ephem::
|
|
22
|
+
# @see Ephem::Segments::ChebyshevType2
|
|
36
23
|
class Segment < BaseSegment
|
|
24
|
+
include ChebyshevType2
|
|
25
|
+
|
|
37
26
|
COMPONENT_COUNTS = {
|
|
38
27
|
2 => 3, # Type 2: position (x, y, z)
|
|
39
28
|
3 => 6 # Type 3: position (x, y, z) and velocity (vx, vy, vz)
|
|
40
29
|
}.freeze
|
|
41
30
|
|
|
42
|
-
# @param daf [Ephem::IO::DAF] DAF file object containing the segment data
|
|
43
|
-
# @param source [String] Name of the source SPK file
|
|
44
|
-
# @param descriptor [Array] Array containing segment metadata:
|
|
45
|
-
# - start_second [Float] Start time in seconds from J2000
|
|
46
|
-
# - end_second [Float] End time in seconds from J2000
|
|
47
|
-
# - target [Integer] NAIF ID of target body
|
|
48
|
-
# - center [Integer] NAIF ID of center body
|
|
49
|
-
# - frame [Integer] Reference frame ID
|
|
50
|
-
# - data_type [Integer] Type of data (2 for position, 3 for pos/vel)
|
|
51
|
-
# - start_i [Integer] Start index in DAF array
|
|
52
|
-
# - end_i [Integer] End index in DAF array
|
|
53
31
|
def initialize(daf:, source:, descriptor:)
|
|
54
32
|
super
|
|
55
33
|
@data_loaded = false
|
|
@@ -59,39 +37,35 @@ module Ephem
|
|
|
59
37
|
# Computes the position of the target body relative to the center body at
|
|
60
38
|
# the specified time.
|
|
61
39
|
#
|
|
62
|
-
# Uses Chebyshev polynomial approximation to interpolate the position from
|
|
63
|
-
# stored coefficients. The computation is thread-safe and uses cached data
|
|
64
|
-
# when available.
|
|
65
|
-
#
|
|
66
40
|
# @param tdb [Numeric, Array<Numeric>] Time(s) in TDB Julian Date
|
|
67
41
|
# @param tdb2 [Numeric] Optional fractional part of TDB date
|
|
68
42
|
# @return [Ephem::Core::Vector] Position vector in kilometers
|
|
69
43
|
# @raise [Ephem::OutOfRangeError] if time is outside segment coverage
|
|
70
|
-
#
|
|
71
|
-
# @example Computing Earth's position relative to Solar System Barycenter
|
|
72
|
-
# position = segment.compute(2451545.0) # J2000 epoch
|
|
73
44
|
def compute(tdb, tdb2 = 0.0)
|
|
74
|
-
|
|
45
|
+
load_data
|
|
46
|
+
tdb_seconds = convert_to_seconds(tdb, tdb2)
|
|
47
|
+
|
|
48
|
+
case tdb_seconds
|
|
49
|
+
when Numeric
|
|
50
|
+
position = generate_position(tdb_seconds)
|
|
51
|
+
Core::Vector.new(position[0], position[1], position[2])
|
|
52
|
+
else
|
|
53
|
+
tdb_seconds.map do |t|
|
|
54
|
+
position = generate_position(t)
|
|
55
|
+
Core::Vector.new(position[0], position[1], position[2])
|
|
56
|
+
end
|
|
57
|
+
end
|
|
75
58
|
end
|
|
76
59
|
alias_method :position_at, :compute
|
|
77
60
|
|
|
78
61
|
# Computes both position and velocity vectors at the specified time.
|
|
79
62
|
#
|
|
80
|
-
# Uses Chebyshev polynomial approximation and its derivative to compute
|
|
81
|
-
# both position and velocity. The computation is thread-safe and uses
|
|
82
|
-
# cached data when available.
|
|
83
|
-
#
|
|
84
63
|
# @param tdb [Numeric, Array<Numeric>] Time(s) in TDB Julian Date
|
|
85
64
|
# @param tdb2 [Numeric] Optional fractional part of TDB date
|
|
86
65
|
# @return [Ephem::Core::State, Array<Ephem::Core::State>] State object(s)
|
|
87
|
-
# containing position and velocity vectors. Returns
|
|
88
|
-
# array.
|
|
66
|
+
# containing position (km) and velocity (km/day) vectors. Returns an
|
|
67
|
+
# array if the input is an array.
|
|
89
68
|
# @raise [Ephem::OutOfRangeError] if time is outside segment coverage
|
|
90
|
-
#
|
|
91
|
-
# @example Computing Earth's state vector
|
|
92
|
-
# state = segment.compute_and_differentiate(2451545.0)
|
|
93
|
-
# position = state.position # in kilometers
|
|
94
|
-
# velocity = state.velocity # in kilometers/second
|
|
95
69
|
def compute_and_differentiate(tdb, tdb2 = 0.0)
|
|
96
70
|
load_data
|
|
97
71
|
tdb_seconds = convert_to_seconds(tdb, tdb2)
|
|
@@ -114,190 +88,16 @@ module Ephem
|
|
|
114
88
|
end
|
|
115
89
|
alias_method :state_at, :compute_and_differentiate
|
|
116
90
|
|
|
117
|
-
# Clears cached coefficient data, forcing reload on next computation.
|
|
118
|
-
#
|
|
119
|
-
# This method is thread-safe and can be used to free memory or force
|
|
120
|
-
# fresh data loading if needed.
|
|
121
|
-
#
|
|
122
|
-
# @return [void]
|
|
123
|
-
def clear_data
|
|
124
|
-
@data_lock.synchronize do
|
|
125
|
-
@data_loaded = false
|
|
126
|
-
@midpoints = nil
|
|
127
|
-
@radii = nil
|
|
128
|
-
@coefficients = nil
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
91
|
private
|
|
133
92
|
|
|
134
|
-
def
|
|
135
|
-
# Synchronize access to data loading using a mutex lock
|
|
136
|
-
# to prevent race conditions in multithreaded environments
|
|
137
|
-
@data_lock.synchronize do
|
|
138
|
-
return if @data_loaded
|
|
139
|
-
|
|
140
|
-
component_count = determine_component_count
|
|
141
|
-
coefficients_data = load_coefficient_data
|
|
142
|
-
process_coefficient_data(coefficients_data, component_count)
|
|
143
|
-
|
|
144
|
-
@data_loaded = true
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def determine_component_count
|
|
93
|
+
def component_count
|
|
149
94
|
COMPONENT_COUNTS.fetch(@data_type) do
|
|
150
95
|
raise "Unsupported data type: #{@data_type}"
|
|
151
96
|
end
|
|
152
97
|
end
|
|
153
98
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
# start_index: index of first coefficient in segment
|
|
157
|
-
# end_index: index of last coefficient in segment
|
|
158
|
-
# record_size: total size of each record (coefficients + 2)
|
|
159
|
-
# segment_count: number of records in the segment
|
|
160
|
-
metadata = @daf.read_array(@end_i - 3, @end_i)
|
|
161
|
-
_start_index, _end_index, record_size, segment_count = metadata
|
|
162
|
-
|
|
163
|
-
coefficient_count = ((record_size - 2) / determine_component_count).to_i
|
|
164
|
-
coefficients_raw = @daf.map_array(@start_i, @end_i - 4)
|
|
165
|
-
|
|
166
|
-
[
|
|
167
|
-
coefficients_raw,
|
|
168
|
-
record_size.to_i,
|
|
169
|
-
segment_count.to_i,
|
|
170
|
-
coefficient_count
|
|
171
|
-
]
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def process_coefficient_data(data, component_count)
|
|
175
|
-
coefficients_raw, record_size, segment_count, coefficient_count = data
|
|
176
|
-
|
|
177
|
-
# Convert raw coefficient data to Numo::DFloat and reshape to 2D array.
|
|
178
|
-
# Numo::NArray allows efficient numerical computations on arrays.
|
|
179
|
-
# It provides ndarray data structures and supports various arithmetic
|
|
180
|
-
# operations. Using Numo::DFloat ensures the array elements are 64-bit
|
|
181
|
-
# floating point numbers.
|
|
182
|
-
coefficients = Numo::DFloat.cast(coefficients_raw)
|
|
183
|
-
coefficients = coefficients.reshape(segment_count, record_size)
|
|
184
|
-
|
|
185
|
-
@midpoints = coefficients[0...segment_count, 0].to_a
|
|
186
|
-
@radii = coefficients[0...segment_count, 1].to_a
|
|
187
|
-
n_terms = coefficient_count
|
|
188
|
-
n_components = component_count
|
|
189
|
-
|
|
190
|
-
@coefficients = Array.new(segment_count) do |i|
|
|
191
|
-
row = coefficients[i, 2..-1].to_a
|
|
192
|
-
Array.new(n_terms) do |k|
|
|
193
|
-
Array.new(n_components) do |j|
|
|
194
|
-
row[k + j * n_terms]
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def convert_to_seconds(tdb, tdb2)
|
|
201
|
-
case tdb
|
|
202
|
-
when Array
|
|
203
|
-
tdb.map { |t| time_to_seconds(t, tdb2) }
|
|
204
|
-
when Numo::NArray
|
|
205
|
-
tdb.to_a.map { |t| time_to_seconds(t, tdb2) }
|
|
206
|
-
else
|
|
207
|
-
time_to_seconds(tdb, tdb2)
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def time_to_seconds(time, offset)
|
|
212
|
-
(time - Time::J2000_EPOCH) *
|
|
213
|
-
Time::SECONDS_PER_DAY +
|
|
214
|
-
offset *
|
|
215
|
-
Time::SECONDS_PER_DAY
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def generate(tdb, tdb2)
|
|
219
|
-
load_data
|
|
220
|
-
tdb_seconds = convert_to_seconds(tdb, tdb2)
|
|
221
|
-
|
|
222
|
-
case tdb_seconds
|
|
223
|
-
when Numeric
|
|
224
|
-
generate_single(tdb_seconds)
|
|
225
|
-
else
|
|
226
|
-
generate_multiple(tdb_seconds)
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
def generate_single(tdb_seconds)
|
|
231
|
-
interval = find_interval(tdb_seconds)
|
|
232
|
-
normalized_time = compute_normalized_time(tdb_seconds, interval)
|
|
233
|
-
|
|
234
|
-
coeffs = @coefficients[interval] # already [n_terms][3]
|
|
235
|
-
position = Computation::ChebyshevPolynomial.evaluate(
|
|
236
|
-
coeffs,
|
|
237
|
-
normalized_time
|
|
238
|
-
)
|
|
239
|
-
velocity = Computation::ChebyshevPolynomial.evaluate_derivative(
|
|
240
|
-
coeffs,
|
|
241
|
-
normalized_time,
|
|
242
|
-
@radii[interval]
|
|
243
|
-
)
|
|
244
|
-
[position, velocity]
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
def generate_multiple(tdb_seconds)
|
|
248
|
-
positions = []
|
|
249
|
-
velocities = []
|
|
250
|
-
|
|
251
|
-
tdb_seconds.each do |time|
|
|
252
|
-
pos, vel = generate_single(time)
|
|
253
|
-
positions << pos
|
|
254
|
-
velocities << vel
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
[positions, velocities]
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
def find_interval(tdb_seconds)
|
|
261
|
-
left = 0
|
|
262
|
-
right = @midpoints.size - 1
|
|
263
|
-
|
|
264
|
-
if @last_interval && time_in_interval?(tdb_seconds, @last_interval)
|
|
265
|
-
return @last_interval
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
while left <= right
|
|
269
|
-
mid = (left + right) / 2
|
|
270
|
-
min_time = @midpoints[mid] - @radii[mid]
|
|
271
|
-
max_time = @midpoints[mid] + @radii[mid]
|
|
272
|
-
|
|
273
|
-
if tdb_seconds < min_time
|
|
274
|
-
right = mid - 1
|
|
275
|
-
elsif tdb_seconds > max_time
|
|
276
|
-
left = mid + 1
|
|
277
|
-
else
|
|
278
|
-
@last_interval = mid
|
|
279
|
-
return mid
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
raise OutOfRangeError.new(
|
|
284
|
-
"Time #{tdb_seconds} is outside the coverage of this segment",
|
|
285
|
-
tdb_seconds
|
|
286
|
-
)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
def time_in_interval?(time, interval)
|
|
290
|
-
min_time = @midpoints[interval] - @radii[interval]
|
|
291
|
-
max_time = @midpoints[interval] + @radii[interval]
|
|
292
|
-
time.between?(min_time, max_time)
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
def compute_normalized_time(time_seconds, interval)
|
|
296
|
-
(time_seconds - @midpoints[interval]) / @radii[interval]
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
Registry.register(2, self)
|
|
300
|
-
Registry.register(3, self)
|
|
99
|
+
Registry.register(:spk, 2, self)
|
|
100
|
+
Registry.register(:spk, 3, self)
|
|
301
101
|
end
|
|
302
102
|
end
|
|
303
103
|
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ephem
|
|
4
|
+
module Segments
|
|
5
|
+
# Several segments that share the same key (an SPK center/target pair, or a
|
|
6
|
+
# PCK body) but cover different, contiguous time intervals. Each query is
|
|
7
|
+
# routed to the segment covering the requested time, so a body that a kernel
|
|
8
|
+
# splits across several intervals behaves as a single, continuous source.
|
|
9
|
+
#
|
|
10
|
+
# SPK and PCK only build a group when a key actually has more than one
|
|
11
|
+
# segment; the common single-segment case returns the bare segment, so this
|
|
12
|
+
# routing never sits in the hot path for it.
|
|
13
|
+
#
|
|
14
|
+
# Subclasses ({PositionGroup}, {OrientationGroup}) add the query methods
|
|
15
|
+
# appropriate to the segments they hold.
|
|
16
|
+
class SegmentGroup
|
|
17
|
+
# Wraps segments that share a key. A single segment is returned as-is, so
|
|
18
|
+
# the common case carries no routing overhead; only a key spanning several
|
|
19
|
+
# time intervals becomes a group.
|
|
20
|
+
#
|
|
21
|
+
# @param segments [Array<BaseSegment>] segments sharing the same key
|
|
22
|
+
# @return [BaseSegment, SegmentGroup]
|
|
23
|
+
def self.wrap(segments)
|
|
24
|
+
segments.one? ? segments.first : new(segments)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [Array<BaseSegment>] the underlying segments
|
|
28
|
+
attr_reader :segments
|
|
29
|
+
|
|
30
|
+
# @param segments [Array<BaseSegment>] segments sharing the same key
|
|
31
|
+
def initialize(segments)
|
|
32
|
+
@segments = segments
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Clears cached data for every segment in the group.
|
|
36
|
+
#
|
|
37
|
+
# @return [void]
|
|
38
|
+
def clear_data
|
|
39
|
+
@segments.each(&:clear_data)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
@segments.join("\n")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# Routes a query to the covering segment(s) and assembles the result. For
|
|
49
|
+
# a scalar time the block is called once with that segment and time; for
|
|
50
|
+
# an array, times are grouped by covering segment so each is queried in a
|
|
51
|
+
# single batched call, then results are reassembled in input order.
|
|
52
|
+
def query(tdb, tdb2)
|
|
53
|
+
if tdb.is_a?(Array)
|
|
54
|
+
query_many(tdb, tdb2) { |segment, times| yield segment, times, tdb2 }
|
|
55
|
+
else
|
|
56
|
+
yield segment_for(tdb, tdb2), tdb, tdb2
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def query_many(times, tdb2)
|
|
61
|
+
results = Array.new(times.size)
|
|
62
|
+
indices_by_segment = times.each_index.group_by do |index|
|
|
63
|
+
segment_for(times[index], tdb2)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
indices_by_segment.each do |segment, indices|
|
|
67
|
+
segment_results = yield(segment, indices.map { |index| times[index] })
|
|
68
|
+
indices.each_with_index do |original_index, position|
|
|
69
|
+
results[original_index] = segment_results[position]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
results
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def segment_for(tdb, tdb2)
|
|
77
|
+
@segments.reverse_each.find { |segment| segment.covers?(tdb, tdb2) } ||
|
|
78
|
+
raise(OutOfRangeError.new(
|
|
79
|
+
"Time #{tdb} is outside the coverage of this group", tdb
|
|
80
|
+
))
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/ephem/spk.rb
CHANGED
|
@@ -25,9 +25,8 @@ module Ephem
|
|
|
25
25
|
DE_FILENAME = "NIO2SPK"
|
|
26
26
|
|
|
27
27
|
DATA_TYPE_IDENTIFIER = 5
|
|
28
|
-
SEGMENT_CLASSES = {}
|
|
29
28
|
|
|
30
|
-
attr_reader :segments, :pairs
|
|
29
|
+
attr_reader :daf, :segments, :pairs
|
|
31
30
|
|
|
32
31
|
# Creates a new SPK instance with the given DAF.
|
|
33
32
|
#
|
|
@@ -49,9 +48,16 @@ module Ephem
|
|
|
49
48
|
# @raise [ArgumentError] If the file cannot be accessed due to permissions
|
|
50
49
|
def self.open(path)
|
|
51
50
|
daf = IO::DAF.new(File.open(path, "rb"))
|
|
51
|
+
if daf.file_type == :pck
|
|
52
|
+
raise ArgumentError, "#{path} is a binary PCK file, use Ephem::PCK.open"
|
|
53
|
+
end
|
|
54
|
+
|
|
52
55
|
new(daf: daf)
|
|
53
56
|
rescue Errno::EACCES => e
|
|
54
57
|
raise ArgumentError, "File permission denied: #{path} (#{e.message})"
|
|
58
|
+
rescue
|
|
59
|
+
daf&.close
|
|
60
|
+
raise
|
|
55
61
|
end
|
|
56
62
|
|
|
57
63
|
# Closes the SPK file and cleans up resources.
|
|
@@ -69,7 +75,7 @@ module Ephem
|
|
|
69
75
|
def to_s
|
|
70
76
|
<<~DESCRIPTION
|
|
71
77
|
SPK file with #{@segments.size} segments:
|
|
72
|
-
#{@segments.
|
|
78
|
+
#{@segments.join("\n")}
|
|
73
79
|
DESCRIPTION
|
|
74
80
|
end
|
|
75
81
|
|
|
@@ -77,8 +83,9 @@ module Ephem
|
|
|
77
83
|
#
|
|
78
84
|
# @param center [Integer] NAIF ID of the center body
|
|
79
85
|
# @param target [Integer] NAIF ID of the target body
|
|
80
|
-
# @return [Segments::
|
|
81
|
-
#
|
|
86
|
+
# @return [Segments::Segment, Segments::PositionGroup] the position source
|
|
87
|
+
# for the pair: a single segment, or a group routing each query to the
|
|
88
|
+
# covering segment when the pair spans several time intervals
|
|
82
89
|
# @raise [KeyError] If no segment is found for the given center-target pair
|
|
83
90
|
def [](center, target)
|
|
84
91
|
@pairs.fetch([center, target]) do
|
|
@@ -139,14 +146,18 @@ module Ephem
|
|
|
139
146
|
end
|
|
140
147
|
|
|
141
148
|
def build_pairs
|
|
142
|
-
@segments
|
|
143
|
-
[
|
|
144
|
-
|
|
149
|
+
@segments
|
|
150
|
+
.group_by { |segment| [segment.center, segment.target] }
|
|
151
|
+
.transform_values { |segments| Segments::PositionGroup.wrap(segments) }
|
|
145
152
|
end
|
|
146
153
|
|
|
147
154
|
def build_segment(source:, descriptor:)
|
|
148
155
|
data_type = descriptor[DATA_TYPE_IDENTIFIER]
|
|
149
|
-
segment_class =
|
|
156
|
+
segment_class = Segments::Registry.lookup(
|
|
157
|
+
:spk,
|
|
158
|
+
data_type,
|
|
159
|
+
Segments::BaseSegment
|
|
160
|
+
)
|
|
150
161
|
segment_class.new(daf: @daf, source: source, descriptor: descriptor)
|
|
151
162
|
end
|
|
152
163
|
end
|
data/lib/ephem/version.rb
CHANGED
data/lib/ephem.rb
CHANGED
|
@@ -6,6 +6,8 @@ require_relative "ephem/computation/chebyshev_polynomial"
|
|
|
6
6
|
require_relative "ephem/core/calendar_calculations"
|
|
7
7
|
require_relative "ephem/core/state"
|
|
8
8
|
require_relative "ephem/core/vector"
|
|
9
|
+
require_relative "ephem/core/orientation"
|
|
10
|
+
require_relative "ephem/core/rotation"
|
|
9
11
|
require_relative "ephem/error"
|
|
10
12
|
require_relative "ephem/io/binary_reader"
|
|
11
13
|
require_relative "ephem/io/daf"
|
|
@@ -15,9 +17,16 @@ require_relative "ephem/io/record_data"
|
|
|
15
17
|
require_relative "ephem/io/record_parser"
|
|
16
18
|
require_relative "ephem/io/summary_manager"
|
|
17
19
|
require_relative "ephem/spk"
|
|
20
|
+
require_relative "ephem/pck"
|
|
18
21
|
require_relative "ephem/segments/base_segment"
|
|
19
22
|
require_relative "ephem/segments/registry"
|
|
23
|
+
require_relative "ephem/segments/chebyshev_type2"
|
|
24
|
+
require_relative "ephem/segments/orientation_source"
|
|
20
25
|
require_relative "ephem/segments/segment"
|
|
26
|
+
require_relative "ephem/segments/orientation_segment"
|
|
27
|
+
require_relative "ephem/segments/segment_group"
|
|
28
|
+
require_relative "ephem/segments/position_group"
|
|
29
|
+
require_relative "ephem/segments/orientation_group"
|
|
21
30
|
require_relative "ephem/excerpt"
|
|
22
31
|
require_relative "ephem/cli"
|
|
23
32
|
require_relative "ephem/version"
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ephem
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rémy Hannequin
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: minitar
|
|
@@ -23,20 +23,6 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0.12'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: numo-narray
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.9.2.1
|
|
33
|
-
type: :runtime
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.9.2.1
|
|
40
26
|
- !ruby/object:Gem::Dependency
|
|
41
27
|
name: zlib
|
|
42
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,6 +107,20 @@ dependencies:
|
|
|
121
107
|
- - "~>"
|
|
122
108
|
- !ruby/object:Gem::Version
|
|
123
109
|
version: '3.13'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: benchmark-ips
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '2.14'
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '2.14'
|
|
124
124
|
- !ruby/object:Gem::Dependency
|
|
125
125
|
name: standard
|
|
126
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -152,6 +152,7 @@ files:
|
|
|
152
152
|
- LICENSE.txt
|
|
153
153
|
- README.md
|
|
154
154
|
- Rakefile
|
|
155
|
+
- benchmarks/run.rb
|
|
155
156
|
- bin/console
|
|
156
157
|
- bin/ruby-ephem
|
|
157
158
|
- bin/setup
|
|
@@ -161,6 +162,8 @@ files:
|
|
|
161
162
|
- lib/ephem/core/calendar_calculations.rb
|
|
162
163
|
- lib/ephem/core/constants/bodies.rb
|
|
163
164
|
- lib/ephem/core/constants/time.rb
|
|
165
|
+
- lib/ephem/core/orientation.rb
|
|
166
|
+
- lib/ephem/core/rotation.rb
|
|
164
167
|
- lib/ephem/core/state.rb
|
|
165
168
|
- lib/ephem/core/vector.rb
|
|
166
169
|
- lib/ephem/download.rb
|
|
@@ -172,9 +175,16 @@ files:
|
|
|
172
175
|
- lib/ephem/io/record_data.rb
|
|
173
176
|
- lib/ephem/io/record_parser.rb
|
|
174
177
|
- lib/ephem/io/summary_manager.rb
|
|
178
|
+
- lib/ephem/pck.rb
|
|
175
179
|
- lib/ephem/segments/base_segment.rb
|
|
180
|
+
- lib/ephem/segments/chebyshev_type2.rb
|
|
181
|
+
- lib/ephem/segments/orientation_group.rb
|
|
182
|
+
- lib/ephem/segments/orientation_segment.rb
|
|
183
|
+
- lib/ephem/segments/orientation_source.rb
|
|
184
|
+
- lib/ephem/segments/position_group.rb
|
|
176
185
|
- lib/ephem/segments/registry.rb
|
|
177
186
|
- lib/ephem/segments/segment.rb
|
|
187
|
+
- lib/ephem/segments/segment_group.rb
|
|
178
188
|
- lib/ephem/spk.rb
|
|
179
189
|
- lib/ephem/version.rb
|
|
180
190
|
- lib/tasks/validate_accuracy.rake
|
|
@@ -199,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
199
209
|
- !ruby/object:Gem::Version
|
|
200
210
|
version: '0'
|
|
201
211
|
requirements: []
|
|
202
|
-
rubygems_version:
|
|
212
|
+
rubygems_version: 4.0.10
|
|
203
213
|
specification_version: 4
|
|
204
214
|
summary: Compute astronomical ephemerides from NASA/JPL DE and IMCCE INPOP
|
|
205
215
|
test_files: []
|