1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
//
// GENERATED FILE
//
use super::*;
use crate::SpiceContext;
use f2rust_std::*;
/// PCK, read record from segment, type 20
///
/// Read a single PCK data record from a segment of type 20
/// (Chebyshev, derivative coefficients only).
///
/// # Required Reading
///
/// * [PCK](crate::required_reading::pck)
///
/// # Brief I/O
///
/// ```text
/// VARIABLE I/O DESCRIPTION
/// -------- --- --------------------------------------------------
/// HANDLE I File handle.
/// DESCR I Segment descriptor.
/// ET I Evaluation epoch.
/// RECORD O Data record.
/// ```
///
/// # Detailed Input
///
/// ```text
/// HANDLE,
/// DESCR are the file handle and segment descriptor for
/// a PCK segment of type 20.
///
/// ET is an epoch for which a data record from a specific
/// segment is required. ET is expressed as seconds past
/// J2000 TDB.
/// ```
///
/// # Detailed Output
///
/// ```text
/// RECORD is the record from the specified segment which, when
/// evaluated at epoch ET, will give Euler angles and
/// Euler angle rates representing the orientation and
/// angular velocity of the body-fixed reference frame
/// associated with the segment.
///
/// The structure of the record is as follows:
///
/// +--------------------------------------+
/// | record size (excluding this element) |
/// +--------------------------------------+
/// | Coverage interval midpoint |
/// +--------------------------------------+
/// | Coverage interval radius |
/// +--------------------------------------+
/// | Coeffs for ANGLE_1 rate |
/// +--------------------------------------+
/// | Coeffs for ANGLE_2 rate |
/// +--------------------------------------+
/// | Coeffs for ANGLE_3 rate |
/// +--------------------------------------+
/// | ANGLE_1 at interval midpoint |
/// +--------------------------------------+
/// | ANGLE_2 at interval midpoint |
/// +--------------------------------------+
/// | ANGLE_3 at interval midpoint |
/// +--------------------------------------+
///
/// In the above record
///
/// - Times are expressed as seconds past J2000 TDB.
/// - Angular components have units of radians.
/// - Rate coefficients have units of radians/s.
///
/// RECORD must be declared by the caller with size large
/// enough to accommodate the largest record that can be
/// returned by this routine.
/// ```
///
/// # Exceptions
///
/// ```text
/// 1) If an issue is detected while looking up PCK data, an error is
/// signaled by a routine in the call tree of this routine.
/// ```
///
/// # Files
///
/// ```text
/// See argument HANDLE.
/// ```
///
/// # Particulars
///
/// ```text
/// See the PCK Required Reading file for a description of the
/// structure of a data type 20 (Chebyshev polynomials,
/// derivative coefficients only) segment.
/// ```
///
/// # Examples
///
/// ```text
/// The data returned by the PCKRnn routine is in its rawest form,
/// taken directly from the segment. As such, it will be meaningless
/// to a user unless he/she understands the structure of the data type
/// completely. Given that understanding, however, the PCKRxx
/// routines might be used to "dump" and check segment data for a
/// particular epoch.
///
///
/// C
/// C Get a segment applicable to a specified frame class ID
/// C and epoch.
/// C
/// CALL PCKSFS ( CLSSID, ET, HANDLE, DESCR, IDENT, FOUND )
///
/// C
/// C Look at parts of the descriptor.
/// C
/// CALL DAFUS ( DESCR, 2, 6, DCD, ICD )
/// REF = ICD( 2 )
/// TYPE = ICD( 3 )
///
/// IF ( TYPE .EQ. 20 ) THEN
/// CALL PCKR20 ( HANDLE, DESCR, ET, RECORD )
/// .
/// . Look at the RECORD data.
/// .
/// END IF
/// ```
///
/// # Author and Institution
///
/// ```text
/// N.J. Bachman (JPL)
/// J. Diaz del Rio (ODC Space)
/// I.M. Underwood (JPL)
/// ```
///
/// # Version
///
/// ```text
/// - SPICELIB Version 1.0.1, 12-AUG-2021 (JDR)
///
/// Edited the header to comply with NAIF standard.
///
/// - SPICELIB Version 1.0.0, 17-JAN-2014 (NJB) (IMU)
/// ```
pub fn pckr20(
ctx: &mut SpiceContext,
handle: i32,
descr: &[f64; 5],
et: f64,
record: &mut [f64],
) -> crate::Result<()> {
PCKR20(handle, descr, et, record, ctx.raw_context())?;
ctx.handle_errors()?;
Ok(())
}
//$Procedure PCKR20 ( PCK, read record from segment, type 20 )
pub fn PCKR20(
HANDLE: i32,
DESCR: &[f64],
ET: f64,
RECORD: &mut [f64],
ctx: &mut Context,
) -> f2rust_std::Result<()> {
let DESCR = DummyArray::new(DESCR, 1..=5);
let mut RECORD = DummyArrayMut::new(RECORD, 1..);
let mut DC = StackArray::<f64, 2>::new(1..=2);
let mut DSCALE: f64 = 0.0;
let mut INIT: f64 = 0.0;
let mut INITFR: f64 = 0.0;
let mut INITJD: f64 = 0.0;
let mut INTLEN: f64 = 0.0;
let mut INTRVL: f64 = 0.0;
let mut MID: f64 = 0.0;
let mut POS = StackArray::<f64, 3>::new(1..=3);
let mut RADIUS: f64 = 0.0;
let mut RECBEG: f64 = 0.0;
let mut TSCALE: f64 = 0.0;
let mut BEGIN: i32 = 0;
let mut END: i32 = 0;
let mut IC = StackArray::<i32, 6>::new(1..=6);
let mut LOC: i32 = 0;
let mut NREC: i32 = 0;
let mut NTERMS: i32 = 0;
let mut RECADR: i32 = 0;
let mut RECNO: i32 = 0;
let mut RECSIZ: i32 = 0;
let mut SIZE: i32 = 0;
//
// SPICELIB functions
//
//
// Local variables
//
//
// Standard SPICE error handling.
//
if RETURN(ctx) {
return Ok(());
}
CHKIN(b"PCKR20", ctx)?;
//
// Unpack the segment descriptor.
//
DAFUS(DESCR.as_slice(), 2, 6, DC.as_slice_mut(), IC.as_slice_mut());
BEGIN = IC[4];
END = IC[5];
//
// The segment is made up of a number of logical records, each
// having the same size, and covering the same length of time.
//
// We can determine which record to return using the input epoch,
// the integer and fractional parts of the initial time of the first
// record's coverage interval, and the length of the interval
// covered by each record. These constants are located at the end of
// the segment, along with the size of each logical record and the
// total number of records.
//
// For convenience, we'll fetch the segment's distance and time
// scales in the same call.
//
DAFGDA(HANDLE, (END - 6), END, RECORD.as_slice_mut(), ctx)?;
DSCALE = RECORD[1];
TSCALE = RECORD[2];
INITJD = RECORD[3];
INITFR = RECORD[4];
INTLEN = RECORD[5];
RECSIZ = (RECORD[6] as i32);
NREC = (RECORD[7] as i32);
//
// NTERMS is the number of rate coefficients per component,
// plus 1 (for the angle component).
//
NTERMS = (RECSIZ / 3);
//
// Convert the initial epoch and interval length to
// seconds past J2000 TDB.
//
INIT = (((INITJD - J2000()) + INITFR) * SPD());
INTRVL = (INTLEN * SPD());
//
// Locate the record containing the coefficients to use.
//
RECNO = ((((ET - INIT) / INTRVL) as i32) + 1);
RECNO = intrinsics::MAX0(&[1, intrinsics::MIN0(&[RECNO, NREC])]);
//
// Compute the midpoint and radius of the record at
// index RECNO. We want to compute the midpoint in such
// a way that we take advantage of interval lengths that
// are exactly representable, when we have them.
//
// RECBEG is the record start time, minus the fractional
// part of the segment start time, expressed as seconds
// past J2000. We'll account for the fractional part of the
// start time below when we compute MID.
//
RECBEG = (((INITJD - J2000()) + (((RECNO - 1) as f64) * INTLEN)) * SPD());
RADIUS = (INTRVL / 2.0);
MID = ((RECBEG + (INITFR * SPD())) + RADIUS);
//
// Compute the address of the desired record.
//
RECADR = (((RECNO - 1) * RECSIZ) + BEGIN);
//
// Along with the record, return the size, midpoint, and
// radius of the record.
//
RECORD[1] = (RECORD[6] + 2 as f64);
RECORD[2] = MID;
RECORD[3] = RADIUS;
DAFGDA(
HANDLE,
RECADR,
((RECADR + RECSIZ) - 1),
RECORD.subarray_mut(4),
ctx,
)?;
//
// We're going to re-arrange the record: the angle components
// will be transferred to the end of the record, and the record
// contents will be left-shifted to fill in the free elements.
//
for I in 1..=3 {
POS[I] = RECORD[(3 + (I * NTERMS))];
}
SIZE = (RECSIZ + 3);
//
// Remove the angle elements from the record.
//
for I in 1..=3 {
//
// LOC is the index of the element to delete. After the first
// removal, we must account for the resulting left shift when
// calculating the indices of subsequent elements to be removed.
//
LOC = ((3 + (I * NTERMS)) - (I - 1));
REMLAD(1, LOC, RECORD.as_slice_mut(), &mut SIZE, ctx)?;
//
// Note that SIZE is an in-out argument; on output it
// indicates the size of the array after removal of
// the indicated element(s).
//
}
//
// Convert the angles to radians.
//
VSCLIP(DSCALE, POS.as_slice_mut());
//
// Append the angles to the record. Since we inserted three
// elements at the start of the record and deleted three angle
// elements, the target index is the same as if we had copied the
// record directly to the output array.
//
MOVED(POS.as_slice(), 3, RECORD.subarray_mut((RECSIZ + 1)));
//
// Convert the angular rate Chebyshev coefficients to units of
// radians/s.
//
for I in 4..=RECSIZ {
RECORD[I] = (RECORD[I] * (DSCALE / TSCALE));
}
CHKOUT(b"PCKR20", ctx)?;
Ok(())
}