1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ilrs;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.Reader;
22 import java.util.Optional;
23 import java.util.regex.Pattern;
24 import java.util.stream.Stream;
25
26 import org.hipparchus.exception.LocalizedCoreFormats;
27 import org.hipparchus.geometry.euclidean.threed.Vector3D;
28 import org.orekit.annotation.DefaultDataContext;
29 import org.orekit.data.DataContext;
30 import org.orekit.data.DataSource;
31 import org.orekit.errors.OrekitException;
32 import org.orekit.errors.OrekitMessages;
33 import org.orekit.files.general.EphemerisFileParser;
34 import org.orekit.frames.Frame;
35 import org.orekit.frames.Frames;
36 import org.orekit.time.AbsoluteDate;
37 import org.orekit.time.DateComponents;
38 import org.orekit.time.TimeScale;
39 import org.orekit.utils.CartesianDerivativesFilter;
40 import org.orekit.utils.Constants;
41 import org.orekit.utils.IERSConventions;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class CPFParser implements EphemerisFileParser<CPF> {
58
59
60 private static final String FILE_FORMAT = "CPF";
61
62
63 private static final double MS_TO_S = 1.0e-6;
64
65
66 private static final Pattern SEPARATOR = Pattern.compile("\\s+");
67
68
69 private static final int DEFAULT_INTERPOLATION_SAMPLE = 10;
70
71
72 private final double mu;
73
74
75 private final TimeScale timeScale;
76
77
78 private final Frames frames;
79
80
81 private final int interpolationSample;
82
83
84 private final IERSConventions iersConvention;
85
86
87
88
89
90
91 @DefaultDataContext
92 public CPFParser() {
93 this(Constants.EIGEN5C_EARTH_MU, DEFAULT_INTERPOLATION_SAMPLE,
94 IERSConventions.IERS_2010, DataContext.getDefault().getTimeScales().getUTC(),
95 DataContext.getDefault().getFrames());
96 }
97
98
99
100
101
102
103
104
105
106
107
108 public CPFParser(final double mu,
109 final int interpolationSamples,
110 final IERSConventions iersConventions,
111 final TimeScale utc,
112 final Frames frames) {
113 this.mu = mu;
114 this.interpolationSample = interpolationSamples;
115 this.iersConvention = iersConventions;
116 this.timeScale = utc;
117 this.frames = frames;
118 }
119
120
121 @Override
122 public CPF parse(final DataSource source) {
123
124 try (Reader reader = source.getOpener().openReaderOnce();
125 BufferedReader br = (reader == null) ? null : new BufferedReader(reader)) {
126
127 if (br == null) {
128 throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, source.getName());
129 }
130
131
132 final ParseInfo pi = new ParseInfo();
133
134 int lineNumber = 0;
135 Stream<LineParser> parsers = Stream.of(LineParser.H1);
136 for (String line = br.readLine(); line != null; line = br.readLine()) {
137 ++lineNumber;
138 final String l = line;
139 final Optional<LineParser> selected = parsers.filter(p -> p.canHandle(l)).findFirst();
140 if (selected.isPresent()) {
141 try {
142 selected.get().parse(line, pi);
143 } catch (StringIndexOutOfBoundsException | NumberFormatException e) {
144 throw new OrekitException(e,
145 OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
146 lineNumber, source.getName(), line);
147 }
148 parsers = selected.get().allowedNext();
149 }
150 if (pi.done) {
151 pi.file.setFilter(pi.hasVelocityEntries ?
152 CartesianDerivativesFilter.USE_PV :
153 CartesianDerivativesFilter.USE_P);
154
155 return pi.file;
156 }
157 }
158
159
160 throw new OrekitException(OrekitMessages.CPF_UNEXPECTED_END_OF_FILE, lineNumber);
161
162 } catch (IOException ioe) {
163 throw new OrekitException(ioe, LocalizedCoreFormats.SIMPLE_MESSAGE, ioe.getLocalizedMessage());
164 }
165
166 }
167
168
169
170
171
172
173 private class ParseInfo {
174
175
176 private CPF file;
177
178
179 private IERSConventions convention;
180
181
182 private Frames frames;
183
184
185 private Frame frame;
186
187
188 private TimeScale timeScale;
189
190
191 private boolean hasVelocityEntries;
192
193
194 private boolean done;
195
196
197
198
199 protected ParseInfo() {
200
201
202 file = new CPF();
203
204
205 this.timeScale = CPFParser.this.timeScale;
206
207
208 file.setMu(mu);
209 file.setInterpolationSample(interpolationSample);
210 file.setTimeScale(timeScale);
211
212
213 this.done = false;
214 this.hasVelocityEntries = false;
215
216
217 this.convention = CPFParser.this.iersConvention;
218 this.frames = CPFParser.this.frames;
219 frame = frames.getITRF(convention, false);
220
221 }
222
223 }
224
225
226 private enum LineParser {
227
228
229 H1("H1") {
230
231
232 @Override
233 public void parse(final String line, final ParseInfo pi) {
234
235
236 final String[] values = SEPARATOR.split(line);
237
238
239
240 int index = 1;
241
242
243 final String format = values[index++];
244
245
246 if (!FILE_FORMAT.equals(format)) {
247 throw new OrekitException(OrekitMessages.UNEXPECTED_FORMAT_FOR_ILRS_FILE, FILE_FORMAT, format);
248 }
249
250
251 pi.file.getHeader().setFormat(format);
252 pi.file.getHeader().setVersion(Integer.parseInt(values[index++]));
253 pi.file.getHeader().setSource(values[index++]);
254
255
256 final int year = Integer.parseInt(values[index++]);
257 final int month = Integer.parseInt(values[index++]);
258 final int day = Integer.parseInt(values[index++]);
259 pi.file.getHeader().setProductionEpoch(new DateComponents(year, month, day));
260
261
262 pi.file.getHeader().setProductionHour(Integer.parseInt(values[index++]));
263
264
265 pi.file.getHeader().setSequenceNumber(Integer.parseInt(values[index++]));
266
267
268 if (pi.file.getHeader().getVersion() == 2) {
269 pi.file.getHeader().setSubDailySequenceNumber(Integer.parseInt(values[index++]));
270 }
271
272
273 pi.file.getHeader().setName(values[index]);
274
275 }
276
277
278 @Override
279 public Stream<LineParser> allowedNext() {
280 return Stream.of(H2, ZERO);
281 }
282
283 },
284
285
286 H2("H2") {
287
288
289 @Override
290 public void parse(final String line, final ParseInfo pi) {
291
292
293 final String[] values = SEPARATOR.split(line);
294
295
296 pi.file.getHeader().setIlrsSatelliteId(values[1]);
297 pi.file.getHeader().setSic(values[2]);
298 pi.file.getHeader().setNoradId(values[3]);
299
300
301 final int yearS = Integer.parseInt(values[4]);
302 final int monthS = Integer.parseInt(values[5]);
303 final int dayS = Integer.parseInt(values[6]);
304 final int hourS = Integer.parseInt(values[7]);
305 final int minuteS = Integer.parseInt(values[8]);
306 final double secondS = Integer.parseInt(values[9]);
307
308 pi.file.getHeader().setStartEpoch(new AbsoluteDate(yearS, monthS, dayS,
309 hourS, minuteS, secondS,
310 pi.file.getTimeScale()));
311
312
313 final int yearE = Integer.parseInt(values[10]);
314 final int monthE = Integer.parseInt(values[11]);
315 final int dayE = Integer.parseInt(values[12]);
316 final int hourE = Integer.parseInt(values[13]);
317 final int minuteE = Integer.parseInt(values[14]);
318 final double secondE = Integer.parseInt(values[15]);
319
320 pi.file.getHeader().setEndEpoch(new AbsoluteDate(yearE, monthE, dayE,
321 hourE, minuteE, secondE,
322 pi.file.getTimeScale()));
323
324
325 pi.file.getHeader().setStep(Integer.parseInt(values[16]));
326
327
328 pi.file.getHeader().setIsCompatibleWithTIVs(Integer.parseInt(values[17]) == 1);
329
330
331 pi.file.getHeader().setTargetClass(Integer.parseInt(values[18]));
332
333
334 final int frameId = Integer.parseInt(values[19]);
335 switch (frameId) {
336 case 0:
337 pi.frame = pi.frames.getITRF(pi.convention, false);
338 break;
339 case 1:
340 pi.frame = pi.frames.getTOD(true);
341 break;
342 case 2:
343 pi.frame = pi.frames.getMOD(pi.convention);
344 break;
345 default:
346 pi.frame = pi.frames.getITRF(pi.convention, false);
347 break;
348 }
349 pi.file.getHeader().setRefFrame(pi.frame);
350 pi.file.getHeader().setRefFrameId(frameId);
351
352
353 pi.file.getHeader().setRotationalAngleType(Integer.parseInt(values[20]));
354 pi.file.getHeader().setIsCenterOfMassCorrectionApplied(Integer.parseInt(values[21]) == 1);
355 if (pi.file.getHeader().getVersion() == 2) {
356 pi.file.getHeader().setTargetLocation(Integer.parseInt(values[22]));
357 }
358
359 }
360
361
362 @Override
363 public Stream<LineParser> allowedNext() {
364 return Stream.of(H3, H4, H5, H9, ZERO);
365 }
366
367 },
368
369
370 H3("H3") {
371
372
373 @Override
374 public void parse(final String line, final ParseInfo pi) {
375
376 }
377
378
379 @Override
380 public Stream<LineParser> allowedNext() {
381 return Stream.of(H4, H5, H9, ZERO);
382 }
383
384 },
385
386
387 H4("H4") {
388
389
390 @Override
391 public void parse(final String line, final ParseInfo pi) {
392
393
394 final String[] values = SEPARATOR.split(line);
395
396
397 pi.file.getHeader().setPrf(Double.parseDouble(values[1]));
398
399
400 pi.file.getHeader().setTranspTransmitDelay(Double.parseDouble(values[2]) * MS_TO_S);
401 pi.file.getHeader().setTranspUtcOffset(Double.parseDouble(values[3]) * MS_TO_S);
402 pi.file.getHeader().setTranspOscDrift(Double.parseDouble(values[4]));
403 if (pi.file.getHeader().getVersion() == 2) {
404 pi.file.getHeader().setTranspClkRef(Double.parseDouble(values[5]));
405 }
406
407 }
408
409
410 @Override
411 public Stream<LineParser> allowedNext() {
412 return Stream.of(H5, H9, ZERO);
413 }
414
415 },
416
417
418 H5("H5") {
419
420
421 @Override
422 public void parse(final String line, final ParseInfo pi) {
423
424
425 final double offset = Double.parseDouble(SEPARATOR.split(line)[1]);
426 pi.file.getHeader().setCenterOfMassOffset(offset);
427
428 }
429
430
431 @Override
432 public Stream<LineParser> allowedNext() {
433 return Stream.of(H9, ZERO);
434 }
435
436 },
437
438
439 H9("H9") {
440
441
442 @Override
443 public void parse(final String line, final ParseInfo pi) {
444
445 }
446
447
448 @Override
449 public Stream<LineParser> allowedNext() {
450 return Stream.of(TEN, ZERO);
451 }
452
453 },
454
455
456 TEN("10") {
457
458
459 @Override
460 public void parse(final String line, final ParseInfo pi) {
461
462
463 final String[] values = SEPARATOR.split(line);
464
465
466 final int mjd = Integer.parseInt(values[2]);
467 final double secInDay = Double.parseDouble(values[3]);
468 final AbsoluteDate date = AbsoluteDate.createMJDDate(mjd, secInDay, pi.timeScale);
469
470
471 final int leap = Integer.parseInt(values[4]);
472
473
474 final double x = Double.parseDouble(values[5]);
475 final double y = Double.parseDouble(values[6]);
476 final double z = Double.parseDouble(values[7]);
477 final Vector3D position = new Vector3D(x, y, z);
478
479
480 final CPF.CPFCoordinate coordinate = new CPF.CPFCoordinate(date, position, leap);
481 pi.file.addSatelliteCoordinate(pi.file.getHeader().getIlrsSatelliteId(), coordinate);
482
483 }
484
485
486 @Override
487 public Stream<LineParser> allowedNext() {
488 return Stream.of(TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
489 }
490
491 },
492
493
494 TWENTY("20") {
495
496
497 @Override
498 public void parse(final String line, final ParseInfo pi) {
499
500 }
501
502
503 @Override
504 public Stream<LineParser> allowedNext() {
505 return Stream.of(TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
506 }
507
508 },
509
510
511 THIRTY("30") {
512
513
514 @Override
515 public void parse(final String line, final ParseInfo pi) {
516
517 }
518
519
520 @Override
521 public Stream<LineParser> allowedNext() {
522 return Stream.of(TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
523 }
524
525 },
526
527
528 FORTY("40") {
529
530
531 @Override
532 public void parse(final String line, final ParseInfo pi) {
533
534 }
535
536
537 @Override
538 public Stream<LineParser> allowedNext() {
539 return Stream.of(TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
540 }
541
542 },
543
544
545 FIFTY("50") {
546
547
548 @Override
549 public void parse(final String line, final ParseInfo pi) {
550
551 }
552
553
554 @Override
555 public Stream<LineParser> allowedNext() {
556 return Stream.of(TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
557 }
558
559 },
560
561
562 SIXTY("60") {
563
564
565 @Override
566 public void parse(final String line, final ParseInfo pi) {
567
568 }
569
570
571 @Override
572 public Stream<LineParser> allowedNext() {
573 return Stream.of(TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
574 }
575
576 },
577
578
579 SEVENTY("70") {
580
581
582 @Override
583 public void parse(final String line, final ParseInfo pi) {
584
585 }
586
587
588 @Override
589 public Stream<LineParser> allowedNext() {
590 return Stream.of(TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
591 }
592
593 },
594
595
596 ZERO("00") {
597
598
599 @Override
600 public void parse(final String line, final ParseInfo pi) {
601
602
603 final String comment = line.split(getIdentifier())[1].trim();
604 pi.file.getComments().add(comment);
605
606 }
607
608
609 @Override
610 public Stream<LineParser> allowedNext() {
611 return Stream.of(H1, H2, H3, H4, H5, H9,
612 TEN, TWENTY, THIRTY, FORTY, FIFTY, SIXTY, SEVENTY, ZERO, EOF);
613 }
614
615 },
616
617
618 EOF("99") {
619
620 @Override
621 public void parse(final String line, final ParseInfo pi) {
622 pi.done = true;
623 }
624
625
626 @Override
627 public Stream<LineParser> allowedNext() {
628 return Stream.of(EOF);
629 }
630
631 };
632
633
634 private final Pattern pattern;
635
636
637 private final String identifier;
638
639
640
641
642 LineParser(final String identifier) {
643 this.identifier = identifier;
644 pattern = Pattern.compile(identifier);
645 }
646
647
648
649
650
651 public String getIdentifier() {
652 return identifier;
653 }
654
655
656
657
658
659 public abstract void parse(String line, ParseInfo pi);
660
661
662
663
664 public abstract Stream<LineParser> allowedNext();
665
666
667
668
669
670 public boolean canHandle(final String line) {
671 return pattern.matcher(SEPARATOR.split(line)[0]).matches();
672 }
673
674 }
675
676 }