1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.rinex.observation;
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.Reader;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.function.BiFunction;
26 import java.util.function.Function;
27 import java.util.function.Predicate;
28
29 import org.hipparchus.exception.LocalizedCoreFormats;
30 import org.hipparchus.geometry.euclidean.threed.Vector3D;
31 import org.hipparchus.geometry.euclidean.twod.Vector2D;
32 import org.hipparchus.util.FastMath;
33 import org.orekit.annotation.DefaultDataContext;
34 import org.orekit.data.DataContext;
35 import org.orekit.data.DataSource;
36 import org.orekit.errors.OrekitException;
37 import org.orekit.errors.OrekitMessages;
38 import org.orekit.files.rinex.AppliedDCBS;
39 import org.orekit.files.rinex.AppliedPCVS;
40 import org.orekit.files.rinex.section.RinexLabels;
41 import org.orekit.files.rinex.utils.parsing.RinexUtils;
42 import org.orekit.gnss.ObservationTimeScale;
43 import org.orekit.gnss.ObservationType;
44 import org.orekit.gnss.PredefinedObservationType;
45 import org.orekit.gnss.SatInSystem;
46 import org.orekit.gnss.SatelliteSystem;
47 import org.orekit.time.AbsoluteDate;
48 import org.orekit.time.TimeScale;
49 import org.orekit.time.TimeScales;
50 import org.orekit.utils.units.Unit;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class RinexObservationParser {
74
75
76 public static final String DEFAULT_RINEX_2_NAMES = "^\\w{4}\\d{3}[0a-x](?:\\d{2})?\\.\\d{2}[oO]$";
77
78
79 public static final String DEFAULT_RINEX_3_NAMES = "^\\w{9}_\\w{1}_\\d{11}_\\d{2}\\w_\\d{2}\\w{1}_\\w{2}\\.rnx$";
80
81
82 private static final int MAX_SAT_PER_RINEX_2_LINE = 12;
83
84
85 private static final int MAX_OBS_PER_RINEX_2_LINE = 5;
86
87
88 private static final Unit PICO_SECOND = Unit.parse("ps");
89
90
91 private final TimeScales timeScales;
92
93
94
95
96 private final Function<? super String, ? extends ObservationType> typeBuilder;
97
98
99
100
101 private final BiFunction<SatelliteSystem, TimeScales, ? extends TimeScale> timeScaleBuilder;
102
103
104
105
106
107
108
109
110
111
112 @DefaultDataContext
113 public RinexObservationParser() {
114 this(PredefinedObservationType::valueOf,
115 (system, ts) -> system.getObservationTimeScale() == null ?
116 null :
117 system.getObservationTimeScale().getTimeScale(ts),
118 DataContext.getDefault().getTimeScales());
119 }
120
121
122
123
124
125
126
127
128 public RinexObservationParser(final Function<? super String, ? extends ObservationType> typeBuilder,
129 final BiFunction<SatelliteSystem, TimeScales, ? extends TimeScale> timeScaleBuilder,
130 final TimeScales timeScales) {
131 this.typeBuilder = typeBuilder;
132 this.timeScaleBuilder = timeScaleBuilder;
133 this.timeScales = timeScales;
134 }
135
136
137
138
139
140
141 public RinexObservation parse(final DataSource source) {
142
143 Iterable<LineParser> candidateParsers = Collections.singleton(LineParser.VERSION);
144
145
146 final ParseInfo parseInfo = new ParseInfo(source.getName());
147
148 try (Reader reader = source.getOpener().openReaderOnce();
149 BufferedReader br = new BufferedReader(reader)) {
150 ++parseInfo.lineNumber;
151 nextLine:
152 for (String line = br.readLine(); line != null; line = br.readLine()) {
153 for (final LineParser candidate : candidateParsers) {
154 if (candidate.canHandle.test(line)) {
155 try {
156 candidate.parsingMethod.parse(line, parseInfo);
157 ++parseInfo.lineNumber;
158 candidateParsers = candidate.allowedNextProvider.apply(parseInfo);
159 continue nextLine;
160 } catch (StringIndexOutOfBoundsException | NumberFormatException e) {
161 throw new OrekitException(e,
162 OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
163 parseInfo.lineNumber, source.getName(), line);
164 }
165 }
166 }
167
168
169 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
170 parseInfo.lineNumber, source.getName(), line);
171
172 }
173
174 } catch (IOException ioe) {
175 throw new OrekitException(ioe, LocalizedCoreFormats.SIMPLE_MESSAGE, ioe.getLocalizedMessage());
176 }
177
178 return parseInfo.file;
179
180 }
181
182
183
184
185 private class ParseInfo {
186
187
188 private final String name;
189
190
191
192
193 private final BiFunction<SatelliteSystem, TimeScales, ? extends TimeScale> timeScaleBuilder;
194
195
196 private final TimeScales timeScales;
197
198
199 private int lineNumber;
200
201
202 private final RinexObservation file;
203
204
205 private AbsoluteDate tObs;
206
207
208 private boolean tFirstFixed;
209
210
211 private boolean tLastFixed;
212
213
214 private double rcvrClkOffset;
215
216
217 private TimeScale timeScale;
218
219
220 private int nbTypes;
221
222
223 private int nbSatObs;
224
225
226 private int nbObsScaleFactor;
227
228
229 private int indexObsSat;
230
231
232 private int nextObsStartLineNumber;
233
234
235 private SatelliteSystem currentSystem;
236
237
238 private int phaseShiftNbSat;
239
240
241 private int nbGlonass;
242
243
244 private final List<SatInSystem> satPhaseShift;
245
246
247 private ObservationType phaseShiftTypeObs;
248
249
250 private double corrPhaseShift;
251
252
253 private boolean headerCompleted;
254
255
256 private boolean specialRecord;
257
258
259 private boolean cycleSlip;
260
261
262 private int eventFlag;
263
264
265 private final List<ObservationType> typesObsScaleFactor;
266
267
268 private final List<ObservationType> typesObs;
269
270
271 private final List<ObservationData> observations;
272
273
274 private final List<SatInSystem> satObs;
275
276
277 private SatInSystem currentSat;
278
279
280
281
282 ParseInfo(final String name) {
283
284 this.name = name;
285 this.timeScales = RinexObservationParser.this.timeScales;
286 this.timeScaleBuilder = RinexObservationParser.this.timeScaleBuilder;
287 this.file = new RinexObservation();
288 this.lineNumber = 0;
289 this.tObs = AbsoluteDate.PAST_INFINITY;
290 this.tFirstFixed = false;
291 this.tLastFixed = false;
292 this.timeScale = null;
293 this.nbTypes = -1;
294 this.nbSatObs = -1;
295 this.nbGlonass = -1;
296 this.phaseShiftNbSat = -1;
297 this.nbObsScaleFactor = -1;
298 this.nextObsStartLineNumber = -1;
299 this.typesObs = new ArrayList<>();
300 this.observations = new ArrayList<>();
301 this.satPhaseShift = new ArrayList<>();
302 this.typesObsScaleFactor = new ArrayList<>();
303 this.satObs = new ArrayList<>();
304 }
305
306
307
308
309 private void setTObs(final AbsoluteDate rawDate) {
310 final RinexObservationHeader header = file.getHeader();
311 if (header.getClockOffsetApplied()) {
312
313 tObs = rawDate;
314 } else {
315
316
317 if (FastMath.abs(rawDate.durationFrom(header.getTFirstObs())) < 1.0e-6 &&
318 !tFirstFixed) {
319
320 header.setTFirstObs(header.getTFirstObs().shiftedBy(-rcvrClkOffset));
321 tFirstFixed = true;
322 }
323 if (FastMath.abs(rawDate.durationFrom(header.getTLastObs())) < 1.0e-6 &&
324 !tLastFixed) {
325
326 header.setTLastObs(header.getTLastObs().shiftedBy(-rcvrClkOffset));
327 tLastFixed = true;
328 }
329 tObs = rawDate.shiftedBy(-rcvrClkOffset);
330 }
331 }
332
333
334
335
336
337
338 ObservationType buildType(final String type) {
339 return RinexObservationParser.this.typeBuilder.apply(type);
340 }
341
342 }
343
344
345 private enum LineParser {
346
347
348 VERSION(line -> RinexLabels.VERSION.matches(RinexUtils.getLabel(line)),
349 (line, parseInfo) -> RinexUtils.parseVersionFileTypeSatelliteSystem(line, parseInfo.name, parseInfo.file.getHeader(),
350 2.00, 2.10, 2.11, 2.12, 2.20,
351 3.00, 3.01, 3.02, 3.03, 3.04, 3.05,
352 4.00, 4.01, 4.02),
353 LineParser::headerNext),
354
355
356 PROGRAM(line -> RinexLabels.PROGRAM.matches(RinexUtils.getLabel(line)),
357 (line, parseInfo) -> RinexUtils.parseProgramRunByDate(line, parseInfo.lineNumber, parseInfo.name,
358 parseInfo.timeScales, parseInfo.file.getHeader()),
359 LineParser::headerNext),
360
361
362 COMMENT(line -> RinexLabels.COMMENT.matches(RinexUtils.getLabel(line)),
363 (line, parseInfo) -> RinexUtils.parseComment(parseInfo.lineNumber, line, parseInfo.file),
364 LineParser::commentNext),
365
366
367 MARKER_NAME(line -> RinexLabels.MARKER_NAME.matches(RinexUtils.getLabel(line)),
368 (line, parseInfo) -> parseInfo.file.getHeader().setMarkerName(RinexUtils.parseString(line, 0, RinexUtils.LABEL_INDEX)),
369 LineParser::headerNext),
370
371
372 MARKER_NUMBER(line -> RinexLabels.MARKER_NUMBER.matches(RinexUtils.getLabel(line)),
373 (line, parseInfo) -> parseInfo.file.getHeader().setMarkerNumber(RinexUtils.parseString(line, 0, 20)),
374 LineParser::headerNext),
375
376
377 MARKER_TYPE(line -> RinexLabels.MARKER_TYPE.matches(RinexUtils.getLabel(line)),
378 (line, parseInfo) -> parseInfo.file.getHeader().setMarkerType(RinexUtils.parseString(line, 0, 20)),
379 LineParser::headerNext),
380
381
382 OBSERVER_AGENCY(line -> RinexLabels.OBSERVER_AGENCY.matches(RinexUtils.getLabel(line)),
383 (line, parseInfo) -> {
384 parseInfo.file.getHeader().setObserverName(RinexUtils.parseString(line, 0, 20));
385 parseInfo.file.getHeader().setAgencyName(RinexUtils.parseString(line, 20, 40));
386 },
387 LineParser::headerNext),
388
389
390 REC_NB_TYPE_VERS(line -> RinexLabels.REC_NB_TYPE_VERS.matches(RinexUtils.getLabel(line)),
391 (line, parseInfo) -> {
392 parseInfo.file.getHeader().setReceiverNumber(RinexUtils.parseString(line, 0, 20));
393 parseInfo.file.getHeader().setReceiverType(RinexUtils.parseString(line, 20, 20));
394 parseInfo.file.getHeader().setReceiverVersion(RinexUtils.parseString(line, 40, 20));
395 },
396 LineParser::headerNext),
397
398
399 ANT_NB_TYPE(line -> RinexLabels.ANT_NB_TYPE.matches(RinexUtils.getLabel(line)),
400 (line, parseInfo) -> {
401 parseInfo.file.getHeader().setAntennaNumber(RinexUtils.parseString(line, 0, 20));
402 parseInfo.file.getHeader().setAntennaType(RinexUtils.parseString(line, 20, 20));
403 },
404 LineParser::headerNext),
405
406
407 APPROX_POSITION_XYZ(line -> RinexLabels.APPROX_POSITION_XYZ.matches(RinexUtils.getLabel(line)),
408 (line, parseInfo) -> parseInfo.file.getHeader().setApproxPos(new Vector3D(RinexUtils.parseDouble(line, 0, 14),
409 RinexUtils.parseDouble(line, 14, 14),
410 RinexUtils.parseDouble(line, 28, 14))),
411 LineParser::headerNext),
412
413
414 ANTENNA_DELTA_H_E_N(line -> RinexLabels.ANTENNA_DELTA_H_E_N.matches(RinexUtils.getLabel(line)),
415 (line, parseInfo) -> {
416 parseInfo.file.getHeader().setAntennaHeight(RinexUtils.parseDouble(line, 0, 14));
417 parseInfo.file.getHeader().setEccentricities(new Vector2D(RinexUtils.parseDouble(line, 14, 14),
418 RinexUtils.parseDouble(line, 28, 14)));
419 },
420 LineParser::headerNext),
421
422
423 ANTENNA_DELTA_X_Y_Z(line -> RinexLabels.ANTENNA_DELTA_X_Y_Z.matches(RinexUtils.getLabel(line)),
424 (line, parseInfo) -> parseInfo.file.getHeader().setAntennaReferencePoint(new Vector3D(RinexUtils.parseDouble(line, 0, 14),
425 RinexUtils.parseDouble(line, 14, 14),
426 RinexUtils.parseDouble(line, 28, 14))),
427 LineParser::headerNext),
428
429
430 ANTENNA_PHASE_CENTER(line -> RinexLabels.ANTENNA_PHASE_CENTER.matches(RinexUtils.getLabel(line)),
431 (line, parseInfo) -> {
432 parseInfo.file.getHeader().setPhaseCenterSystem(SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 0, 1)));
433 parseInfo.file.getHeader().setObservationCode(RinexUtils.parseString(line, 2, 3));
434 parseInfo.file.getHeader().setAntennaPhaseCenter(new Vector3D(RinexUtils.parseDouble(line, 5, 9),
435 RinexUtils.parseDouble(line, 14, 14),
436 RinexUtils.parseDouble(line, 28, 14)));
437 },
438 LineParser::headerNext),
439
440
441 ANTENNA_B_SIGHT_XYZ(line -> RinexLabels.ANTENNA_B_SIGHT_XYZ.matches(RinexUtils.getLabel(line)),
442 (line, parseInfo) -> parseInfo.file.getHeader().setAntennaBSight(new Vector3D(RinexUtils.parseDouble(line, 0, 14),
443 RinexUtils.parseDouble(line, 14, 14),
444 RinexUtils.parseDouble(line, 28, 14))),
445 LineParser::headerNext),
446
447
448 ANTENNA_ZERODIR_AZI(line -> RinexLabels.ANTENNA_ZERODIR_AZI.matches(RinexUtils.getLabel(line)),
449 (line, parseInfo) -> parseInfo.file.getHeader().setAntennaAzimuth(FastMath.toRadians(RinexUtils.parseDouble(line, 0, 14))),
450 LineParser::headerNext),
451
452
453 ANTENNA_ZERODIR_XYZ(line -> RinexLabels.ANTENNA_ZERODIR_XYZ.matches(RinexUtils.getLabel(line)),
454 (line, parseInfo) -> parseInfo.file.getHeader().setAntennaZeroDirection(new Vector3D(RinexUtils.parseDouble(line, 0, 14),
455 RinexUtils.parseDouble(line, 14, 14),
456 RinexUtils.parseDouble(line, 28, 14))),
457 LineParser::headerNext),
458
459
460 WAVELENGTH_FACT_L1_2(line -> RinexLabels.WAVELENGTH_FACT_L1_2.matches(RinexUtils.getLabel(line)),
461 (line, parseInfo) -> {
462
463 },
464 LineParser::headerNext),
465
466
467 OBS_SCALE_FACTOR(line -> RinexLabels.OBS_SCALE_FACTOR.matches(RinexUtils.getLabel(line)),
468 (line, parseInfo) -> {
469 final int scaleFactor = FastMath.max(1, RinexUtils.parseInt(line, 0, 6));
470 final int nbObsScaleFactor = RinexUtils.parseInt(line, 6, 6);
471 final List<ObservationType> types = new ArrayList<>(nbObsScaleFactor);
472 for (int i = 0; i < nbObsScaleFactor; i++) {
473 types.add(parseInfo.buildType(RinexUtils.parseString(line, 16 + (6 * i), 2)));
474 }
475 parseInfo.file.getHeader().addScaleFactorCorrection(parseInfo.file.getHeader().getSatelliteSystem(),
476 new ScaleFactorCorrection(scaleFactor, types));
477 },
478 LineParser::headerNext),
479
480
481 CENTER_OF_MASS_XYZ(line -> RinexLabels.CENTER_OF_MASS_XYZ.matches(RinexUtils.getLabel(line)),
482 (line, parseInfo) -> parseInfo.file.getHeader().setCenterMass(new Vector3D(RinexUtils.parseDouble(line, 0, 14),
483 RinexUtils.parseDouble(line, 14, 14),
484 RinexUtils.parseDouble(line, 28, 14))),
485 LineParser::headerNext),
486
487
488
489
490 DOI(line -> RinexLabels.DOI.matches(RinexUtils.getLabel(line)),
491 (line, parseInfo) -> parseInfo.file.getHeader().setDoi(RinexUtils.parseString(line, 0, RinexUtils.LABEL_INDEX)),
492 LineParser::headerNext),
493
494
495
496
497 LICENSE(line -> RinexLabels.LICENSE.matches(RinexUtils.getLabel(line)),
498 (line, parseInfo) -> parseInfo.file.getHeader().setLicense(RinexUtils.parseString(line, 0, RinexUtils.LABEL_INDEX)),
499 LineParser::headerNext),
500
501
502
503
504 STATION_INFORMATION(line -> RinexLabels.STATION_INFORMATION.matches(RinexUtils.getLabel(line)),
505 (line, parseInfo) -> parseInfo.file.getHeader().setStationInformation(RinexUtils.parseString(line, 0, RinexUtils.LABEL_INDEX)),
506 LineParser::headerNext),
507
508
509 SYS_NB_TYPES_OF_OBSERV(line -> RinexLabels.SYS_NB_TYPES_OF_OBSERV.matches(RinexUtils.getLabel(line)) ||
510 RinexLabels.NB_TYPES_OF_OBSERV.matches(RinexUtils.getLabel(line)),
511 (line, parseInfo) -> {
512 final double version = parseInfo.file.getHeader().getFormatVersion();
513 if (parseInfo.nbTypes < 0) {
514
515 if (version < 3) {
516
517 parseInfo.currentSystem = parseInfo.file.getHeader().getSatelliteSystem();
518 parseInfo.nbTypes = RinexUtils.parseInt(line, 0, 6);
519 } else {
520
521 parseInfo.currentSystem = SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 0, 1));
522 parseInfo.nbTypes = RinexUtils.parseInt(line, 3, 3);
523 if (parseInfo.currentSystem != parseInfo.file.getHeader().getSatelliteSystem() &&
524 parseInfo.file.getHeader().getSatelliteSystem() != SatelliteSystem.MIXED) {
525 throw new OrekitException(OrekitMessages.INCONSISTENT_SATELLITE_SYSTEM,
526 parseInfo.lineNumber, parseInfo.name,
527 parseInfo.file.getHeader().getSatelliteSystem(),
528 parseInfo.currentSystem);
529 }
530 }
531 }
532
533 final int firstIndex = version < 3 ? 10 : 7;
534 final int increment = version < 3 ? 6 : 4;
535 final int size = version < 3 ? 2 : 3;
536 for (int i = firstIndex;
537 (i + size) <= RinexUtils.LABEL_INDEX && parseInfo.typesObs.size() < parseInfo.nbTypes;
538 i += increment) {
539 final String type = RinexUtils.parseString(line, i, size);
540 try {
541 parseInfo.typesObs.add(parseInfo.buildType(type));
542 } catch (IllegalArgumentException iae) {
543 throw new OrekitException(iae, OrekitMessages.UNKNOWN_RINEX_FREQUENCY,
544 type, parseInfo.name, parseInfo.lineNumber);
545 }
546 }
547
548 if (parseInfo.typesObs.size() == parseInfo.nbTypes) {
549
550 parseInfo.file.getHeader().setTypeObs(parseInfo.currentSystem, parseInfo.typesObs);
551 parseInfo.typesObs.clear();
552 parseInfo.nbTypes = -1;
553 }
554
555 },
556 LineParser::headerNbTypesObs),
557
558
559 SIGNAL_STRENGTH_UNIT(line -> RinexLabels.SIGNAL_STRENGTH_UNIT.matches(RinexUtils.getLabel(line)),
560 (line, parseInfo) -> parseInfo.file.getHeader().setSignalStrengthUnit(RinexUtils.parseString(line, 0, 20)),
561 LineParser::headerNext),
562
563
564 INTERVAL(line -> RinexLabels.INTERVAL.matches(RinexUtils.getLabel(line)),
565 (line, parseInfo) -> parseInfo.file.getHeader().setInterval(RinexUtils.parseDouble(line, 0, 10)),
566 LineParser::headerNext),
567
568
569 TIME_OF_FIRST_OBS(line -> RinexLabels.TIME_OF_FIRST_OBS.matches(RinexUtils.getLabel(line)),
570 (line, parseInfo) -> {
571 try {
572
573 parseInfo.timeScale = ObservationTimeScale.
574 valueOf(RinexUtils.parseString(line, 48, 3)).
575 getTimeScale(parseInfo.timeScales);
576 } catch (IllegalArgumentException iae) {
577 if (parseInfo.file.getHeader().getSatelliteSystem() != SatelliteSystem.MIXED) {
578
579 parseInfo.timeScale = parseInfo.timeScaleBuilder.apply(parseInfo.file.getHeader().getSatelliteSystem(),
580 parseInfo.timeScales);
581 if (parseInfo.timeScale == null) {
582 throw new OrekitException(iae, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
583 parseInfo.lineNumber, parseInfo.name, line);
584 }
585 } else {
586
587 throw new OrekitException(iae, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
588 parseInfo.lineNumber, parseInfo.name, line);
589 }
590 }
591 parseInfo.file.getHeader().setTFirstObs(new AbsoluteDate(RinexUtils.parseInt(line, 0, 6),
592 RinexUtils.parseInt(line, 6, 6),
593 RinexUtils.parseInt(line, 12, 6),
594 RinexUtils.parseInt(line, 18, 6),
595 RinexUtils.parseInt(line, 24, 6),
596 RinexUtils.parseDouble(line, 30, 13),
597 parseInfo.timeScale));
598 },
599 LineParser::headerNext),
600
601
602 TIME_OF_LAST_OBS(line -> RinexLabels.TIME_OF_LAST_OBS.matches(RinexUtils.getLabel(line)),
603 (line, parseInfo) -> parseInfo.file.getHeader().setTLastObs(new AbsoluteDate(RinexUtils.parseInt(line, 0, 6),
604 RinexUtils.parseInt(line, 6, 6),
605 RinexUtils.parseInt(line, 12, 6),
606 RinexUtils.parseInt(line, 18, 6),
607 RinexUtils.parseInt(line, 24, 6),
608 RinexUtils.parseDouble(line, 30, 13),
609 parseInfo.timeScale)),
610 LineParser::headerNext),
611
612
613 RCV_CLOCK_OFFS_APPL(line -> RinexLabels.RCV_CLOCK_OFFS_APPL.matches(RinexUtils.getLabel(line)),
614 (line, parseInfo) -> parseInfo.file.getHeader().setClockOffsetApplied(RinexUtils.parseInt(line, 0, 6) > 0),
615 LineParser::headerNext),
616
617
618 SYS_DCBS_APPLIED(line -> RinexLabels.SYS_DCBS_APPLIED.matches(RinexUtils.getLabel(line)),
619 (line, parseInfo) -> parseInfo.file.getHeader().addAppliedDCBS(new AppliedDCBS(SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 0, 1)),
620 RinexUtils.parseString(line, 2, 17),
621 RinexUtils.parseString(line, 20, 40))),
622 LineParser::headerNext),
623
624
625 SYS_PCVS_APPLIED(line -> RinexLabels.SYS_PCVS_APPLIED.matches(RinexUtils.getLabel(line)),
626 (line, parseInfo) -> parseInfo.file.getHeader().addAppliedPCVS(new AppliedPCVS(SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 0, 1)),
627 RinexUtils.parseString(line, 2, 17),
628 RinexUtils.parseString(line, 20, 40))),
629 LineParser::headerNext),
630
631
632 SYS_SCALE_FACTOR(line -> RinexLabels.SYS_SCALE_FACTOR.matches(RinexUtils.getLabel(line)),
633 (line, parseInfo) -> {
634
635 int scaleFactor = 1;
636 if (parseInfo.nbObsScaleFactor < 0) {
637
638 parseInfo.currentSystem = SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 0, 1));
639 scaleFactor = RinexUtils.parseInt(line, 2, 4);
640 parseInfo.nbObsScaleFactor = RinexUtils.parseInt(line, 8, 2);
641 }
642
643 if (parseInfo.nbObsScaleFactor == 0) {
644 parseInfo.typesObsScaleFactor.addAll(parseInfo.file.getHeader().getTypeObs().get(parseInfo.currentSystem));
645 } else {
646 for (int i = 11; i < RinexUtils.LABEL_INDEX && parseInfo.typesObsScaleFactor.size() < parseInfo.nbObsScaleFactor; i += 4) {
647 parseInfo.typesObsScaleFactor.add(parseInfo.buildType(RinexUtils.parseString(line, i, 3)));
648 }
649 }
650
651 if (parseInfo.typesObsScaleFactor.size() >= parseInfo.nbObsScaleFactor) {
652
653 parseInfo.file.getHeader().addScaleFactorCorrection(parseInfo.currentSystem,
654 new ScaleFactorCorrection(scaleFactor,
655 new ArrayList<>(parseInfo.typesObsScaleFactor)));
656 parseInfo.nbObsScaleFactor = -1;
657 parseInfo.typesObsScaleFactor.clear();
658 }
659
660 },
661 LineParser::headerNext),
662
663
664 SYS_PHASE_SHIFT(line -> RinexLabels.SYS_PHASE_SHIFT.matches(RinexUtils.getLabel(line)),
665 (line, parseInfo) -> {
666
667 if (parseInfo.phaseShiftNbSat < 0) {
668
669 parseInfo.currentSystem = SatelliteSystem.parseSatelliteSystem(RinexUtils.parseString(line, 0, 1));
670 final String to = RinexUtils.parseString(line, 2, 3);
671 parseInfo.phaseShiftTypeObs = to.isEmpty() ? null : parseInfo.buildType(to.length() < 3 ? "L" + to : to);
672 parseInfo.corrPhaseShift = RinexUtils.parseDouble(line, 6, 8);
673 parseInfo.phaseShiftNbSat = RinexUtils.parseInt(line, 16, 2);
674 }
675
676 for (int i = 19; i + 3 < RinexUtils.LABEL_INDEX && parseInfo.satPhaseShift.size() < parseInfo.phaseShiftNbSat; i += 4) {
677 final String satSpec = line.charAt(i) == ' ' ?
678 parseInfo.currentSystem.getKey() + line.substring(i + 1, i + 3) :
679 line.substring(i, i + 3);
680 parseInfo.satPhaseShift.add(new SatInSystem(satSpec));
681 }
682
683 if (parseInfo.satPhaseShift.size() == parseInfo.phaseShiftNbSat) {
684
685 parseInfo.file.getHeader().addPhaseShiftCorrection(new PhaseShiftCorrection(parseInfo.currentSystem,
686 parseInfo.phaseShiftTypeObs,
687 parseInfo.corrPhaseShift,
688 new ArrayList<>(parseInfo.satPhaseShift)));
689 parseInfo.phaseShiftNbSat = -1;
690 parseInfo.satPhaseShift.clear();
691 }
692
693 },
694 LineParser::headerPhaseShift),
695
696
697 GLONASS_SLOT_FRQ_NB(line -> RinexLabels.GLONASS_SLOT_FRQ_NB.matches(RinexUtils.getLabel(line)),
698 (line, parseInfo) -> {
699
700 if (parseInfo.nbGlonass < 0) {
701
702 parseInfo.nbGlonass = RinexUtils.parseInt(line, 0, 3);
703 }
704
705 for (int i = 4;
706 i < RinexUtils.LABEL_INDEX && parseInfo.file.getHeader().getGlonassChannels().size() < parseInfo.nbGlonass;
707 i += 7) {
708 final int k = RinexUtils.parseInt(line, i + 4, 2);
709 parseInfo.file.getHeader().addGlonassChannel(new GlonassSatelliteChannel(new SatInSystem(line.substring(i, i + 3)), k));
710 }
711
712 },
713 LineParser::headerNext),
714
715
716 GLONASS_COD_PHS_BIS(line -> RinexLabels.GLONASS_COD_PHS_BIS.matches(RinexUtils.getLabel(line)),
717 (line, parseInfo) -> {
718
719
720 final String c1c = RinexUtils.parseString(line, 1, 3);
721 if (!c1c.isEmpty()) {
722 parseInfo.file.getHeader().setC1cCodePhaseBias(RinexUtils.parseDouble(line, 5, 8));
723 }
724
725
726 final String c1p = RinexUtils.parseString(line, 14, 3);
727 if (!c1p.isEmpty()) {
728 parseInfo.file.getHeader().setC1pCodePhaseBias(RinexUtils.parseDouble(line, 18, 8));
729 }
730
731
732 final String c2c = RinexUtils.parseString(line, 27, 3);
733 if (!c2c.isEmpty()) {
734 parseInfo.file.getHeader().setC2cCodePhaseBias(RinexUtils.parseDouble(line, 31, 8));
735 }
736
737
738 final String c2p = RinexUtils.parseString(line, 40, 3);
739 if (!c2p.isEmpty()) {
740 parseInfo.file.getHeader().setC2pCodePhaseBias(RinexUtils.parseDouble(line, 44, 8));
741 }
742
743 },
744 LineParser::headerNext),
745
746
747 LEAP_SECONDS(line -> RinexLabels.LEAP_SECONDS.matches(RinexUtils.getLabel(line)),
748 (line, parseInfo) -> {
749 parseInfo.file.getHeader().setLeapSeconds(RinexUtils.parseInt(line, 0, 6));
750 if (parseInfo.file.getHeader().getFormatVersion() >= 3.0) {
751 parseInfo.file.getHeader().setLeapSecondsFuture(RinexUtils.parseInt(line, 6, 6));
752 parseInfo.file.getHeader().setLeapSecondsWeekNum(RinexUtils.parseInt(line, 12, 6));
753 parseInfo.file.getHeader().setLeapSecondsDayNum(RinexUtils.parseInt(line, 18, 6));
754 }
755 },
756 LineParser::headerNext),
757
758
759 NB_OF_SATELLITES(line -> RinexLabels.NB_OF_SATELLITES.matches(RinexUtils.getLabel(line)),
760 (line, parseInfo) -> parseInfo.file.getHeader().setNbSat(RinexUtils.parseInt(line, 0, 6)),
761 LineParser::headerNext),
762
763
764 PRN_NB_OF_OBS(line -> RinexLabels.PRN_NB_OF_OBS.matches(RinexUtils.getLabel(line)),
765 (line, parseInfo) -> {
766 final String systemName = RinexUtils.parseString(line, 3, 1);
767 if (!systemName.isEmpty()) {
768 parseInfo.currentSat = new SatInSystem(line.substring(3, 6));
769 parseInfo.nbTypes = 0;
770 }
771 final List<ObservationType> types = parseInfo.file.getHeader().getTypeObs().get(parseInfo.currentSat.getSystem());
772
773 final int firstIndex = 6;
774 final int increment = 6;
775 final int size = 6;
776 for (int i = firstIndex;
777 (i + size) <= RinexUtils.LABEL_INDEX && parseInfo.nbTypes < types.size();
778 i += increment) {
779 final String nb = RinexUtils.parseString(line, i, size);
780 if (!nb.isEmpty()) {
781 parseInfo.file.getHeader().setNbObsPerSatellite(parseInfo.currentSat, types.get(parseInfo.nbTypes),
782 RinexUtils.parseInt(line, i, size));
783 }
784 ++parseInfo.nbTypes;
785 }
786
787 },
788 LineParser::headerNext),
789
790
791 END(line -> RinexLabels.END.matches(RinexUtils.getLabel(line)),
792 (line, parseInfo) -> {
793
794 parseInfo.headerCompleted = true;
795
796
797 final double version = parseInfo.file.getHeader().getFormatVersion();
798
799
800 if (version < 3) {
801 if (parseInfo.file.getHeader().getMarkerName() == null ||
802 parseInfo.file.getHeader().getObserverName() == null ||
803 parseInfo.file.getHeader().getReceiverNumber() == null ||
804 parseInfo.file.getHeader().getAntennaNumber() == null ||
805 parseInfo.file.getHeader().getTFirstObs() == null ||
806 version < 2.20 && parseInfo.file.getHeader().getApproxPos() == null ||
807 version < 2.20 && Double.isNaN(parseInfo.file.getHeader().getAntennaHeight()) ||
808 parseInfo.file.getHeader().getTypeObs().isEmpty()) {
809 throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, parseInfo.name);
810 }
811
812 } else {
813 if (parseInfo.file.getHeader().getMarkerName() == null ||
814 parseInfo.file.getHeader().getObserverName() == null ||
815 parseInfo.file.getHeader().getReceiverNumber() == null ||
816 parseInfo.file.getHeader().getAntennaNumber() == null ||
817 Double.isNaN(parseInfo.file.getHeader().getAntennaHeight()) &&
818 parseInfo.file.getHeader().getAntennaReferencePoint() == null ||
819 parseInfo.file.getHeader().getTFirstObs() == null ||
820 parseInfo.file.getHeader().getTypeObs().isEmpty()) {
821 throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, parseInfo.name);
822 }
823 }
824 },
825 LineParser::headerEndNext),
826
827
828 RINEX_2_DATA_SAT_LIST(line -> true,
829 (line, parseInfo) -> {
830 for (int index = 32; parseInfo.satObs.size() < parseInfo.nbSatObs && index < 68; index += 3) {
831
832 final String satSpec =
833 line.charAt(index) == ' ' ?
834 parseInfo.file.getHeader().getSatelliteSystem().getKey() + line.substring(index + 1, index + 3) :
835 line.substring(index, index + 3);
836 final SatInSystem satellite = new SatInSystem(satSpec);
837 if (satellite.getSystem() != parseInfo.file.getHeader().getSatelliteSystem() &&
838 parseInfo.file.getHeader().getSatelliteSystem() != SatelliteSystem.MIXED) {
839 throw new OrekitException(OrekitMessages.INCONSISTENT_SATELLITE_SYSTEM,
840 parseInfo.lineNumber, parseInfo.name,
841 parseInfo.file.getHeader().getSatelliteSystem(),
842 satellite.getSystem());
843 }
844 parseInfo.satObs.add(satellite);
845
846
847 final int nbObservables = parseInfo.file.getHeader().getTypeObs().get(parseInfo.file.getHeader().getSatelliteSystem()).size();
848 final int nbLines = (nbObservables + MAX_OBS_PER_RINEX_2_LINE - 1) / MAX_OBS_PER_RINEX_2_LINE;
849 parseInfo.nextObsStartLineNumber += nbLines;
850 }
851 },
852 LineParser::first2),
853
854
855 RINEX_2_DATA_FIRST(line -> true,
856 (line, parseInfo) -> {
857
858
859 parseInfo.eventFlag = RinexUtils.parseInt(line, 28, 1);
860
861
862 parseInfo.nbSatObs = RinexUtils.parseInt(line, 29, 3);
863 final int nbLinesSat = (parseInfo.nbSatObs + MAX_SAT_PER_RINEX_2_LINE - 1) / MAX_SAT_PER_RINEX_2_LINE;
864
865 if (parseInfo.eventFlag < 2) {
866
867 parseInfo.specialRecord = false;
868 parseInfo.cycleSlip = false;
869 final int nbSat = parseInfo.file.getHeader().getNbSat();
870 if (nbSat != -1 && parseInfo.nbSatObs > nbSat) {
871
872 throw new OrekitException(OrekitMessages.INCONSISTENT_NUMBER_OF_SATS,
873 parseInfo.lineNumber, parseInfo.name,
874 parseInfo.nbSatObs, nbSat);
875 }
876 parseInfo.nextObsStartLineNumber = parseInfo.lineNumber + nbLinesSat;
877
878
879 parseInfo.rcvrClkOffset = RinexUtils.parseDouble(line, 68, 12);
880 if (Double.isNaN(parseInfo.rcvrClkOffset)) {
881 parseInfo.rcvrClkOffset = 0.0;
882 }
883
884 } else if (parseInfo.eventFlag < 6) {
885
886
887 parseInfo.specialRecord = true;
888 parseInfo.cycleSlip = false;
889 parseInfo.nextObsStartLineNumber = parseInfo.lineNumber + parseInfo.nbSatObs + 1;
890 } else if (parseInfo.eventFlag == 6) {
891
892 parseInfo.specialRecord = false;
893 parseInfo.cycleSlip = true;
894 parseInfo.nextObsStartLineNumber = parseInfo.lineNumber + nbLinesSat;
895 } else {
896
897 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
898 parseInfo.lineNumber, parseInfo.name, line);
899 }
900
901
902 parseInfo.satObs.clear();
903 if (!parseInfo.specialRecord) {
904
905
906 parseInfo.setTObs(new AbsoluteDate(RinexUtils.convert2DigitsYear(RinexUtils.parseInt(line, 1, 2)),
907 RinexUtils.parseInt(line, 4, 2),
908 RinexUtils.parseInt(line, 7, 2),
909 RinexUtils.parseInt(line, 10, 2),
910 RinexUtils.parseInt(line, 13, 2),
911 RinexUtils.parseDouble(line, 15, 11),
912 parseInfo.timeScale));
913
914
915 RINEX_2_DATA_SAT_LIST.parsingMethod.parse(line, parseInfo);
916
917 }
918
919
920 parseInfo.indexObsSat = 0;
921 parseInfo.observations.clear();
922
923 },
924 LineParser::first2),
925
926
927 RINEX_2_IGNORED_SPECIAL_RECORD(line -> true,
928 (line, parseInfo) -> {
929
930 },
931 LineParser::ignore2),
932
933
934 RINEX_2_OBSERVATION(line -> true,
935 (line, parseInfo) -> {
936 final List<ObservationType> types = parseInfo.file.getHeader().getTypeObs().get(parseInfo.file.getHeader().getSatelliteSystem());
937 for (int index = 0;
938 parseInfo.observations.size() < types.size() && index < 80;
939 index += 16) {
940 final ObservationData observationData;
941 if (parseInfo.cycleSlip) {
942
943 observationData = null;
944 } else {
945
946 final ObservationType type = types.get(parseInfo.observations.size());
947 final double scaling = getScaling(parseInfo, type, parseInfo.currentSystem);
948 observationData = new ObservationData(type,
949 scaling * RinexUtils.parseDouble(line, index, 14),
950 RinexUtils.parseInt(line, index + 14, 1),
951 RinexUtils.parseInt(line, index + 15, 1));
952 }
953 parseInfo.observations.add(observationData);
954 }
955
956 if (parseInfo.observations.size() == types.size()) {
957
958 if (!parseInfo.cycleSlip) {
959 parseInfo.file.addObservationDataSet(new ObservationDataSet(parseInfo.satObs.get(parseInfo.indexObsSat),
960 parseInfo.tObs,
961 parseInfo.eventFlag,
962 parseInfo.rcvrClkOffset,
963 new ArrayList<>(parseInfo.observations)));
964 }
965 parseInfo.indexObsSat++;
966 parseInfo.observations.clear();
967 }
968
969 },
970 LineParser::observation2),
971
972
973 RINEX_3_OBSERVATION(line -> true,
974 (line, parseInfo) -> {
975 final SatInSystem sat = new SatInSystem(line.substring(0, 3));
976 final List<ObservationType> types = parseInfo.file.getHeader().getTypeObs().get(sat.getSystem());
977 for (int index = 3;
978 parseInfo.observations.size() < types.size();
979 index += 16) {
980 final ObservationData observationData;
981 if (parseInfo.specialRecord || parseInfo.cycleSlip) {
982
983 observationData = null;
984 } else {
985
986 final ObservationType type = types.get(parseInfo.observations.size());
987 final double scaling = getScaling(parseInfo, type, sat.getSystem());
988 observationData = new ObservationData(type,
989 scaling * RinexUtils.parseDouble(line, index, 14),
990 RinexUtils.parseInt(line, index + 14, 1),
991 RinexUtils.parseInt(line, index + 15, 1));
992 }
993 parseInfo.observations.add(observationData);
994 }
995
996 if (!(parseInfo.specialRecord || parseInfo.cycleSlip)) {
997 parseInfo.file.addObservationDataSet(new ObservationDataSet(sat,
998 parseInfo.tObs,
999 parseInfo.eventFlag,
1000 parseInfo.rcvrClkOffset,
1001 new ArrayList<>(parseInfo.observations)));
1002 }
1003 parseInfo.observations.clear();
1004
1005 },
1006 LineParser::observation3),
1007
1008
1009 RINEX_3_DATA_FIRST(line -> line.startsWith(">"),
1010 (line, parseInfo) -> {
1011
1012
1013 parseInfo.eventFlag = RinexUtils.parseInt(line, 31, 1);
1014
1015
1016 parseInfo.nbSatObs = RinexUtils.parseInt(line, 32, 3);
1017
1018 if (parseInfo.eventFlag < 2) {
1019
1020 parseInfo.specialRecord = false;
1021 parseInfo.cycleSlip = false;
1022 final int nbSat = parseInfo.file.getHeader().getNbSat();
1023 if (nbSat != -1 && parseInfo.nbSatObs > nbSat) {
1024
1025 throw new OrekitException(OrekitMessages.INCONSISTENT_NUMBER_OF_SATS,
1026 parseInfo.lineNumber, parseInfo.name,
1027 parseInfo.nbSatObs, nbSat);
1028 }
1029 parseInfo.nextObsStartLineNumber = parseInfo.lineNumber + parseInfo.nbSatObs + 1;
1030
1031
1032 parseInfo.rcvrClkOffset = RinexUtils.parseDouble(line, 41, 15);
1033 if (Double.isNaN(parseInfo.rcvrClkOffset)) {
1034 parseInfo.rcvrClkOffset = 0.0;
1035 }
1036
1037 } else if (parseInfo.eventFlag < 6) {
1038
1039
1040 parseInfo.specialRecord = true;
1041 parseInfo.cycleSlip = false;
1042 parseInfo.nextObsStartLineNumber = parseInfo.lineNumber + parseInfo.nbSatObs + 1;
1043 } else if (parseInfo.eventFlag == 6) {
1044
1045 parseInfo.specialRecord = false;
1046 parseInfo.cycleSlip = true;
1047 parseInfo.nextObsStartLineNumber = parseInfo.lineNumber + parseInfo.nbSatObs + 1;
1048 } else {
1049
1050 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
1051 parseInfo.lineNumber, parseInfo.name, line);
1052 }
1053
1054
1055 parseInfo.satObs.clear();
1056 if (!parseInfo.specialRecord) {
1057
1058
1059 parseInfo.setTObs(new AbsoluteDate(RinexUtils.parseInt(line, 2, 4),
1060 RinexUtils.parseInt(line, 7, 2),
1061 RinexUtils.parseInt(line, 10, 2),
1062 RinexUtils.parseInt(line, 13, 2),
1063 RinexUtils.parseInt(line, 16, 2),
1064 RinexUtils.parseDouble(line, 18, 11) +
1065 PICO_SECOND.toSI(RinexUtils.parseInt(line, 57, 5)),
1066 parseInfo.timeScale));
1067
1068 }
1069
1070
1071 parseInfo.observations.clear();
1072
1073 },
1074 parseInfo -> Collections.singleton(RINEX_3_OBSERVATION));
1075
1076
1077
1078 private final Predicate<String> canHandle;
1079
1080
1081 private final ParsingMethod parsingMethod;
1082
1083
1084 private final Function<ParseInfo, Iterable<LineParser>> allowedNextProvider;
1085
1086
1087
1088
1089
1090
1091 LineParser(final Predicate<String> canHandle, final ParsingMethod parsingMethod,
1092 final Function<ParseInfo, Iterable<LineParser>> allowedNextProvider) {
1093 this.canHandle = canHandle;
1094 this.parsingMethod = parsingMethod;
1095 this.allowedNextProvider = allowedNextProvider;
1096 }
1097
1098
1099
1100
1101
1102 private static Iterable<LineParser> commentNext(final ParseInfo parseInfo) {
1103 return parseInfo.headerCompleted ? headerEndNext(parseInfo) : headerNext(parseInfo);
1104 }
1105
1106
1107
1108
1109
1110 private static Iterable<LineParser> headerNext(final ParseInfo parseInfo) {
1111 if (parseInfo.file.getHeader().getFormatVersion() < 3) {
1112
1113 return Arrays.asList(PROGRAM, COMMENT, MARKER_NAME, MARKER_NUMBER, MARKER_TYPE, OBSERVER_AGENCY,
1114 REC_NB_TYPE_VERS, ANT_NB_TYPE, APPROX_POSITION_XYZ, ANTENNA_DELTA_H_E_N,
1115 ANTENNA_DELTA_X_Y_Z, ANTENNA_B_SIGHT_XYZ, WAVELENGTH_FACT_L1_2, OBS_SCALE_FACTOR,
1116 CENTER_OF_MASS_XYZ, SYS_NB_TYPES_OF_OBSERV, INTERVAL, TIME_OF_FIRST_OBS, TIME_OF_LAST_OBS,
1117 RCV_CLOCK_OFFS_APPL, LEAP_SECONDS, NB_OF_SATELLITES, PRN_NB_OF_OBS, END);
1118 } else if (parseInfo.file.getHeader().getFormatVersion() < 4) {
1119
1120 return Arrays.asList(PROGRAM, COMMENT, MARKER_NAME, MARKER_NUMBER, MARKER_TYPE, OBSERVER_AGENCY,
1121 REC_NB_TYPE_VERS, ANT_NB_TYPE, APPROX_POSITION_XYZ, ANTENNA_DELTA_H_E_N,
1122 ANTENNA_DELTA_X_Y_Z, ANTENNA_PHASE_CENTER, ANTENNA_B_SIGHT_XYZ, ANTENNA_ZERODIR_AZI,
1123 ANTENNA_ZERODIR_XYZ, CENTER_OF_MASS_XYZ, SYS_NB_TYPES_OF_OBSERV, SIGNAL_STRENGTH_UNIT,
1124 INTERVAL, TIME_OF_FIRST_OBS, TIME_OF_LAST_OBS, RCV_CLOCK_OFFS_APPL,
1125 SYS_DCBS_APPLIED, SYS_PCVS_APPLIED, SYS_SCALE_FACTOR, SYS_PHASE_SHIFT,
1126 GLONASS_SLOT_FRQ_NB, GLONASS_COD_PHS_BIS, LEAP_SECONDS, NB_OF_SATELLITES,
1127 PRN_NB_OF_OBS, END);
1128 } else {
1129
1130 return Arrays.asList(PROGRAM, COMMENT, MARKER_NAME, MARKER_NUMBER, MARKER_TYPE, OBSERVER_AGENCY,
1131 REC_NB_TYPE_VERS, ANT_NB_TYPE, APPROX_POSITION_XYZ, ANTENNA_DELTA_H_E_N,
1132 ANTENNA_DELTA_X_Y_Z, ANTENNA_PHASE_CENTER, ANTENNA_B_SIGHT_XYZ, ANTENNA_ZERODIR_AZI,
1133 ANTENNA_ZERODIR_XYZ, CENTER_OF_MASS_XYZ, DOI, LICENSE, STATION_INFORMATION,
1134 SYS_NB_TYPES_OF_OBSERV, SIGNAL_STRENGTH_UNIT, INTERVAL, TIME_OF_FIRST_OBS, TIME_OF_LAST_OBS,
1135 RCV_CLOCK_OFFS_APPL, SYS_DCBS_APPLIED, SYS_PCVS_APPLIED, SYS_SCALE_FACTOR, SYS_PHASE_SHIFT,
1136 GLONASS_SLOT_FRQ_NB, GLONASS_COD_PHS_BIS, LEAP_SECONDS, NB_OF_SATELLITES,
1137 PRN_NB_OF_OBS, END);
1138 }
1139 }
1140
1141
1142
1143
1144
1145 private static Iterable<LineParser> headerEndNext(final ParseInfo parseInfo) {
1146 return Collections.singleton(parseInfo.file.getHeader().getFormatVersion() < 3 ?
1147 RINEX_2_DATA_FIRST : RINEX_3_DATA_FIRST);
1148 }
1149
1150
1151
1152
1153
1154 private static Iterable<LineParser> headerNbTypesObs(final ParseInfo parseInfo) {
1155 if (parseInfo.typesObs.size() < parseInfo.nbTypes) {
1156 return Arrays.asList(COMMENT, SYS_NB_TYPES_OF_OBSERV);
1157 } else {
1158 return headerNext(parseInfo);
1159 }
1160 }
1161
1162
1163
1164
1165
1166 private static Iterable<LineParser> headerPhaseShift(final ParseInfo parseInfo) {
1167 if (parseInfo.satPhaseShift.size() < parseInfo.phaseShiftNbSat) {
1168 return Arrays.asList(COMMENT, SYS_PHASE_SHIFT);
1169 } else {
1170 return headerNext(parseInfo);
1171 }
1172 }
1173
1174
1175
1176
1177
1178 private static Iterable<LineParser> first2(final ParseInfo parseInfo) {
1179 if (parseInfo.specialRecord) {
1180 return Collections.singleton(RINEX_2_IGNORED_SPECIAL_RECORD);
1181 } else if (parseInfo.satObs.size() < parseInfo.nbSatObs) {
1182 return Collections.singleton(RINEX_2_DATA_SAT_LIST);
1183 } else {
1184 return Collections.singleton(RINEX_2_OBSERVATION);
1185 }
1186 }
1187
1188
1189
1190
1191
1192 private static Iterable<LineParser> ignore2(final ParseInfo parseInfo) {
1193 if (parseInfo.lineNumber < parseInfo.nextObsStartLineNumber) {
1194 return Collections.singleton(RINEX_2_IGNORED_SPECIAL_RECORD);
1195 } else {
1196 return Arrays.asList(COMMENT, RINEX_2_DATA_FIRST);
1197 }
1198 }
1199
1200
1201
1202
1203
1204 private static Iterable<LineParser> observation2(final ParseInfo parseInfo) {
1205 if (parseInfo.lineNumber < parseInfo.nextObsStartLineNumber) {
1206 return Collections.singleton(RINEX_2_OBSERVATION);
1207 } else {
1208 return Arrays.asList(COMMENT, RINEX_2_DATA_FIRST);
1209 }
1210 }
1211
1212
1213
1214
1215
1216 private static Iterable<LineParser> observation3(final ParseInfo parseInfo) {
1217 if (parseInfo.lineNumber < parseInfo.nextObsStartLineNumber) {
1218 return Collections.singleton(RINEX_3_OBSERVATION);
1219 } else {
1220 return Arrays.asList(COMMENT, RINEX_3_DATA_FIRST);
1221 }
1222 }
1223
1224
1225
1226
1227
1228
1229
1230 private static double getScaling(final ParseInfo parseInfo, final ObservationType type,
1231 final SatelliteSystem system) {
1232
1233 for (final ScaleFactorCorrection scaleFactorCorrection :
1234 parseInfo.file.getHeader().getScaleFactorCorrections(system)) {
1235
1236 if (scaleFactorCorrection.getTypesObsScaled().contains(type)) {
1237 return 1.0 / scaleFactorCorrection.getCorrection();
1238 }
1239 }
1240
1241
1242 return 1.0;
1243
1244 }
1245
1246 }
1247
1248
1249 @FunctionalInterface
1250 private interface ParsingMethod {
1251
1252
1253
1254
1255 void parse(String line, ParseInfo parseInfo);
1256 }
1257
1258 }