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