1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.sp3;
18
19 import java.io.BufferedReader;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.util.Locale;
26 import java.util.Scanner;
27
28 import org.hipparchus.exception.DummyLocalizable;
29 import org.hipparchus.geometry.euclidean.threed.Vector3D;
30 import org.hipparchus.util.FastMath;
31 import org.orekit.errors.OrekitException;
32 import org.orekit.errors.OrekitMessages;
33 import org.orekit.files.general.OrbitFile.TimeSystem;
34 import org.orekit.files.general.OrbitFileParser;
35 import org.orekit.files.general.SatelliteInformation;
36 import org.orekit.files.general.SatelliteTimeCoordinate;
37 import org.orekit.files.sp3.SP3File.SP3FileType;
38 import org.orekit.files.sp3.SP3File.SP3OrbitType;
39 import org.orekit.time.AbsoluteDate;
40 import org.orekit.time.TimeScale;
41 import org.orekit.time.TimeScalesFactory;
42 import org.orekit.utils.PVCoordinates;
43
44
45
46
47
48
49
50
51
52
53
54 public class SP3Parser implements OrbitFileParser {
55
56
57 public SP3File parse(final String fileName) throws OrekitException {
58
59 InputStream stream = null;
60
61 try {
62 stream = new FileInputStream(fileName);
63 return parse(stream);
64 } catch (FileNotFoundException e) {
65 throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, fileName);
66 } finally {
67 try {
68 if (stream != null) {
69 stream.close();
70 }
71 } catch (IOException e) {
72
73 }
74 }
75 }
76
77
78 public SP3File parse(final InputStream stream) throws OrekitException {
79 try {
80 return parseInternal(stream);
81 } catch (IOException e) {
82 throw new OrekitException(e, new DummyLocalizable(e.getMessage()));
83 }
84 }
85
86
87
88
89
90
91
92
93 private SP3File parseInternal(final InputStream stream)
94 throws OrekitException, IOException {
95
96 final BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
97
98
99 final ParseInfo pi = new ParseInfo();
100
101 String line = null;
102 int lineNumber = 1;
103 try {
104 while (lineNumber < 23) {
105 line = reader.readLine();
106 if (line == null) {
107 throw new OrekitException(OrekitMessages.SP3_UNEXPECTED_END_OF_FILE, lineNumber - 1);
108 } else {
109 parseHeaderLine(lineNumber++, line, pi);
110 }
111 }
112
113
114
115 boolean done = false;
116 do {
117 line = reader.readLine();
118 if (line == null || "EOF".equalsIgnoreCase(line.trim())) {
119 done = true;
120 } else if (line.length() > 0) {
121 parseContentLine(line, pi);
122 }
123 } while (!done);
124 } finally {
125 try {
126 reader.close();
127 } catch (IOException e1) {
128
129 }
130 }
131
132 return pi.file;
133 }
134
135
136
137
138
139
140
141 private void parseHeaderLine(final int lineNumber, final String line, final ParseInfo pi)
142 throws OrekitException {
143
144 final SP3File file = pi.file;
145
146 try (final Scanner s1 = new Scanner(line);
147 final Scanner s2 = s1.useDelimiter("\\s+");
148 final Scanner scanner = s2.useLocale(Locale.US)) {
149
150
151
152 switch (lineNumber) {
153
154
155 case 1: {
156 scanner.skip("#");
157 final String v = scanner.next();
158
159 final char version = v.substring(0, 1).toLowerCase().charAt(0);
160 if (version != 'a' && version != 'b' && version != 'c') {
161 throw new OrekitException(OrekitMessages.SP3_UNSUPPORTED_VERSION, version);
162 }
163
164 pi.hasVelocityEntries = "V".equals(v.substring(1, 2));
165
166 final int year = Integer.parseInt(v.substring(2));
167 final int month = scanner.nextInt();
168 final int day = scanner.nextInt();
169 final int hour = scanner.nextInt();
170 final int minute = scanner.nextInt();
171 final double second = scanner.nextDouble();
172
173 final AbsoluteDate epoch = new AbsoluteDate(year, month, day,
174 hour, minute, second,
175 TimeScalesFactory.getGPS());
176
177 file.setEpoch(epoch);
178
179 final int numEpochs = scanner.nextInt();
180 file.setNumberOfEpochs(numEpochs);
181
182
183 file.setDataUsed(scanner.next());
184
185 file.setCoordinateSystem(scanner.next());
186 file.setOrbitType(SP3OrbitType.parseType(scanner.next()));
187 file.setAgency(scanner.next());
188 break;
189 }
190
191
192 case 2: {
193 scanner.skip("##");
194
195
196 file.setGpsWeek(scanner.nextInt());
197
198 file.setSecondsOfWeek(scanner.nextDouble());
199
200 file.setEpochInterval(scanner.nextDouble());
201
202 file.setJulianDay(scanner.nextInt());
203
204 file.setDayFraction(scanner.nextDouble());
205 break;
206 }
207
208
209 case 3:
210 pi.maxSatellites = Integer.parseInt(line.substring(4, 6).trim());
211
212
213
214 case 4:
215 case 5:
216 case 6:
217 case 7: {
218 final int lineLength = line.length();
219 int count = file.getSatelliteCount();
220 int startIdx = 9;
221 while (count++ < pi.maxSatellites && (startIdx + 3) <= lineLength) {
222 final String satId = line.substring(startIdx, startIdx + 3).trim();
223 file.addSatellite(satId);
224 startIdx += 3;
225 }
226 break;
227 }
228
229
230 case 8:
231 case 9:
232 case 10:
233 case 11:
234 case 12: {
235 final int lineLength = line.length();
236 int satIdx = (lineNumber - 8) * 17;
237 int startIdx = 9;
238 while (satIdx < pi.maxSatellites && (startIdx + 3) <= lineLength) {
239 final SatelliteInformation satInfo = file.getSatellite(satIdx++);
240 final int exponent = Integer.parseInt(line.substring(startIdx, startIdx + 3).trim());
241
242
243 satInfo.setAccuracy((int) FastMath.pow(2d, exponent));
244 startIdx += 3;
245 }
246 break;
247 }
248
249 case 13: {
250 file.setType(getFileType(line.substring(3, 5).trim()));
251
252
253 final String tsStr = line.substring(9, 12).trim();
254 final TimeSystem ts;
255 if (tsStr.equalsIgnoreCase("ccc")) {
256 ts = TimeSystem.GPS;
257 } else {
258 ts = TimeSystem.valueOf(tsStr);
259 }
260 file.setTimeSystem(ts);
261
262 switch (ts) {
263 case GPS:
264 pi.timeScale = TimeScalesFactory.getGPS();
265 break;
266
267 case GAL:
268 pi.timeScale = TimeScalesFactory.getGST();
269 break;
270
271 case GLO:
272 pi.timeScale = TimeScalesFactory.getGLONASS();
273 break;
274
275 case QZS:
276 pi.timeScale = TimeScalesFactory.getQZSS();
277
278 case TAI:
279 pi.timeScale = TimeScalesFactory.getTAI();
280 break;
281
282 case UTC:
283 pi.timeScale = TimeScalesFactory.getUTC();
284 break;
285
286 default:
287 pi.timeScale = TimeScalesFactory.getGPS();
288 break;
289 }
290 break;
291 }
292
293 case 14:
294
295 break;
296
297
298
299 case 15: {
300
301
302
303
304
305
306
307
308
309
310
311 break;
312 }
313
314 case 16:
315 case 17:
316 case 18:
317
318 break;
319
320 case 19:
321 case 20:
322 case 21:
323 case 22:
324
325 break;
326 default:
327
328 break;
329 }
330
331
332
333 }
334
335 }
336
337
338
339
340
341 private void parseContentLine(final String line, final ParseInfo pi) {
342
343
344 final SP3File file = pi.file;
345
346 switch (line.charAt(0)) {
347 case '*': {
348 final int year = Integer.parseInt(line.substring(3, 7).trim());
349 final int month = Integer.parseInt(line.substring(8, 10).trim());
350 final int day = Integer.parseInt(line.substring(11, 13).trim());
351 final int hour = Integer.parseInt(line.substring(14, 16).trim());
352 final int minute = Integer.parseInt(line.substring(17, 19).trim());
353 final double second = Double.parseDouble(line.substring(20, 31).trim());
354
355 pi.latestEpoch = new AbsoluteDate(year, month, day,
356 hour, minute, second,
357 pi.timeScale);
358 break;
359 }
360
361 case 'P': {
362 final String satelliteId = line.substring(1, 4).trim();
363
364 if (!file.containsSatellite(satelliteId)) {
365 pi.latestPosition = null;
366 } else {
367 final double x = Double.parseDouble(line.substring(4, 18).trim());
368 final double y = Double.parseDouble(line.substring(18, 32).trim());
369 final double z = Double.parseDouble(line.substring(32, 46).trim());
370
371
372 pi.latestPosition = new Vector3D(x * 1000, y * 1000, z * 1000);
373
374
375 pi.latestClock = Double.parseDouble(line.substring(46, 60).trim());
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405 if (!pi.hasVelocityEntries) {
406 final SatelliteTimeCoordinate coord =
407 new SatelliteTimeCoordinate(pi.latestEpoch,
408 pi.latestPosition,
409 pi.latestClock);
410 file.addSatelliteCoordinate(satelliteId, coord);
411 }
412 }
413 break;
414 }
415
416 case 'V': {
417 final String satelliteId = line.substring(1, 4).trim();
418
419 if (file.containsSatellite(satelliteId)) {
420 final double xv = Double.parseDouble(line.substring(4, 18).trim());
421 final double yv = Double.parseDouble(line.substring(18, 32).trim());
422 final double zv = Double.parseDouble(line.substring(32, 46).trim());
423
424
425 final Vector3D velocity = new Vector3D(xv / 10d, yv / 10d, zv / 10d);
426
427 final double clockRateChange = Double.parseDouble(line.substring(46, 60).trim());
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446 final SatelliteTimeCoordinate coord =
447 new SatelliteTimeCoordinate(pi.latestEpoch,
448 new PVCoordinates(pi.latestPosition, velocity),
449 pi.latestClock,
450 clockRateChange);
451 file.addSatelliteCoordinate(satelliteId, coord);
452 }
453 break;
454 }
455
456 default:
457
458 break;
459 }
460 }
461
462
463
464
465
466 private SP3FileType getFileType(final String fileType) {
467 SP3FileType type = SP3FileType.UNDEFINED;
468 if ("G".equalsIgnoreCase(fileType)) {
469 type = SP3FileType.GPS;
470 } else if ("M".equalsIgnoreCase(fileType)) {
471 type = SP3FileType.MIXED;
472 } else if ("R".equalsIgnoreCase(fileType)) {
473 type = SP3FileType.GLONASS;
474 } else if ("L".equalsIgnoreCase(fileType)) {
475 type = SP3FileType.LEO;
476 } else if ("E".equalsIgnoreCase(fileType)) {
477 type = SP3FileType.GALILEO;
478 } else if ("C".equalsIgnoreCase(fileType)) {
479 type = SP3FileType.COMPASS;
480 } else if ("J".equalsIgnoreCase(fileType)) {
481 type = SP3FileType.QZSS;
482 }
483 return type;
484 }
485
486
487
488
489
490
491 private static class ParseInfo {
492
493
494 private SP3File file;
495
496
497 private AbsoluteDate latestEpoch;
498
499
500 private Vector3D latestPosition;
501
502
503 private double latestClock;
504
505
506 private boolean hasVelocityEntries;
507
508
509 private TimeScale timeScale;
510
511
512 private int maxSatellites;
513
514
515
516
517
518
519
520
521 protected ParseInfo() {
522 file = new SP3File();
523 latestEpoch = null;
524 latestPosition = null;
525 latestClock = 0.0d;
526 hasVelocityEntries = false;
527 timeScale = TimeScalesFactory.getGPS();
528 maxSatellites = 0;
529
530
531 }
532 }
533 }