1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.rugged.errors;
18
19 import java.io.BufferedReader;
20 import java.io.ByteArrayInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStreamReader;
26 import java.io.ObjectOutputStream;
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.NavigableMap;
35 import java.util.TreeMap;
36 import java.util.stream.Stream;
37
38 import org.hipparchus.analysis.differentiation.DerivativeStructure;
39 import org.hipparchus.exception.LocalizedCoreFormats;
40 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
41 import org.hipparchus.geometry.euclidean.threed.Rotation;
42 import org.hipparchus.geometry.euclidean.threed.Vector3D;
43 import org.hipparchus.util.FastMath;
44 import org.hipparchus.util.OpenIntToDoubleHashMap;
45 import org.hipparchus.util.Pair;
46 import org.orekit.bodies.GeodeticPoint;
47 import org.orekit.bodies.OneAxisEllipsoid;
48 import org.orekit.frames.Frame;
49 import org.orekit.frames.FramesFactory;
50 import org.orekit.frames.Predefined;
51 import org.orekit.frames.Transform;
52 import org.orekit.rugged.api.AlgorithmId;
53 import org.orekit.rugged.api.Rugged;
54 import org.orekit.rugged.api.RuggedBuilder;
55 import org.orekit.rugged.linesensor.LineDatation;
56 import org.orekit.rugged.linesensor.LineSensor;
57 import org.orekit.rugged.linesensor.SensorMeanPlaneCrossing;
58 import org.orekit.rugged.linesensor.SensorMeanPlaneCrossing.CrossingResult;
59 import org.orekit.rugged.linesensor.SensorPixel;
60 import org.orekit.rugged.los.TimeDependentLOS;
61 import org.orekit.rugged.raster.TileUpdater;
62 import org.orekit.rugged.raster.UpdatableTile;
63 import org.orekit.rugged.refraction.AtmosphericRefraction;
64 import org.orekit.rugged.refraction.MultiLayerModel;
65 import org.orekit.rugged.utils.DSGenerator;
66 import org.orekit.rugged.utils.ExtendedEllipsoid;
67 import org.orekit.rugged.utils.SpacecraftToObservedBody;
68 import org.orekit.time.AbsoluteDate;
69 import org.orekit.time.TimeScalesFactory;
70 import org.orekit.utils.ParameterDriver;
71
72
73
74
75
76
77
78 public class DumpReplayer {
79
80
81 private static final String COMMENT_START = "#";
82
83
84 private static final String LATITUDE = "latitude";
85
86
87 private static final String LONGITUDE = "longitude";
88
89
90 private static final String ELEVATION = "elevation";
91
92
93 private static final String AE = "ae";
94
95
96 private static final String F = "f";
97
98
99 private static final String FRAME = "frame";
100
101
102 private static final String DATE = "date";
103
104
105 private static final String POSITION = "position";
106
107
108 private static final String LOS = "los";
109
110
111 private static final String LIGHT_TIME = "lightTime";
112
113
114 private static final String ABERRATION = "aberration";
115
116
117 private static final String REFRACTION = "refraction";
118
119
120 private static final String MIN_DATE = "minDate";
121
122
123 private static final String MAX_DATE = "maxDate";
124
125
126 private static final String T_STEP = "tStep";
127
128
129 private static final String TOLERANCE = "tolerance";
130
131
132 private static final String INERTIAL_FRAME = "inertialFrame";
133
134
135 private static final String INDEX = "index";
136
137
138 private static final String BODY = "body";
139
140
141 private static final String R = "r";
142
143
144 private static final String OMEGA = "Ω";
145
146
147 private static final String OMEGA_DOT = "ΩDot";
148
149
150 private static final String SPACECRAFT = "spacecraft";
151
152
153 private static final String P = "p";
154
155
156 private static final String V = "v";
157
158
159 private static final String A = "a";
160
161
162 private static final String LAT_MIN = "latMin";
163
164
165 private static final String LAT_STEP = "latStep";
166
167
168 private static final String LAT_ROWS = "latRows";
169
170
171 private static final String LON_MIN = "lonMin";
172
173
174 private static final String LON_STEP = "lonStep";
175
176
177 private static final String LON_COLS = "lonCols";
178
179
180 private static final String LAT_INDEX = "latIndex";
181
182
183 private static final String LON_INDEX = "lonIndex";
184
185
186 private static final String SENSOR_NAME = "sensorName";
187
188
189 private static final String MIN_LINE = "minLine";
190
191
192 private static final String MAX_LINE = "maxLine";
193
194
195 private static final String LINE_NUMBER = "lineNumber";
196
197
198 private static final String NB_PIXELS = "nbPixels";
199
200
201 private static final String PIXEL_NUMBER = "pixelNumber";
202
203
204 private static final String MAX_EVAL = "maxEval";
205
206
207 private static final String ACCURACY = "accuracy";
208
209
210 private static final String NORMAL = "normal";
211
212
213 private static final String RATE = "rate";
214
215
216 private static final String CACHED_RESULTS = "cachedResults";
217
218
219 private static final String TARGET = "target";
220
221
222 private static final String TARGET_DIRECTION = "targetDirection";
223
224
225 private static final String NULL_RESULT = "NULL";
226
227
228 private double constantElevation;
229
230
231 private AlgorithmId algorithmId;
232
233
234 private OneAxisEllipsoid ellipsoid;
235
236
237 private final List<ParsedTile> tiles;
238
239
240 private final List<ParsedSensor> sensors;
241
242
243 private AbsoluteDate minDate;
244
245
246 private AbsoluteDate maxDate;
247
248
249 private double tStep;
250
251
252 private double tolerance;
253
254
255 private Frame inertialFrame;
256
257
258 private NavigableMap<Integer, Transform> bodyToInertial;
259
260
261 private NavigableMap<Integer, Transform> scToInertial;
262
263
264 private boolean lightTimeCorrection;
265
266
267 private boolean aberrationOfLightCorrection;
268
269
270 private boolean atmosphericRefraction;
271
272
273 private final List<DumpedCall> calls;
274
275
276
277 public DumpReplayer() {
278 tiles = new ArrayList<ParsedTile>();
279 sensors = new ArrayList<ParsedSensor>();
280 calls = new ArrayList<DumpedCall>();
281 }
282
283
284
285
286 public void parse(final File file) {
287 try {
288 final BufferedReader reader =
289 new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
290 int l = 0;
291 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
292 LineParser.parse(++l, file, line, this);
293 }
294 reader.close();
295 } catch (IOException ioe) {
296 throw new RuggedException(ioe, LocalizedCoreFormats.SIMPLE_MESSAGE, ioe.getLocalizedMessage());
297 }
298 }
299
300
301
302
303 public Rugged createRugged() {
304 try {
305 final RuggedBuilderhtml#RuggedBuilder">RuggedBuilder builder = new RuggedBuilder();
306
307 if (algorithmId == null) {
308 algorithmId = AlgorithmId.IGNORE_DEM_USE_ELLIPSOID;
309 }
310 builder.setAlgorithm(algorithmId);
311 if (algorithmId == AlgorithmId.CONSTANT_ELEVATION_OVER_ELLIPSOID) {
312 builder.setConstantElevation(constantElevation);
313 } else if (algorithmId != AlgorithmId.IGNORE_DEM_USE_ELLIPSOID) {
314 builder.setDigitalElevationModel(new TileUpdater() {
315
316
317 @Override
318 public void updateTile(final double latitude, final double longitude, final UpdatableTile tile) {
319 for (final ParsedTile parsedTile : tiles) {
320 if (parsedTile.isInterpolable(latitude, longitude)) {
321 parsedTile.updateTile(tile);
322 return;
323 }
324 }
325 throw new RuggedException(RuggedMessages.NO_DEM_DATA,
326 FastMath.toDegrees(latitude), FastMath.toDegrees(longitude));
327 }
328 }, 8);
329 }
330
331 builder.setEllipsoid(ellipsoid);
332
333 builder.setLightTimeCorrection(lightTimeCorrection);
334 builder.setAberrationOfLightCorrection(aberrationOfLightCorrection);
335 if (atmosphericRefraction) {
336 final ExtendedEllipsoid extendedEllipsoid = builder.getEllipsoid();
337 final AtmosphericRefraction atmosphericModel = new MultiLayerModel(extendedEllipsoid);
338
339 builder.setRefractionCorrection(atmosphericModel);
340 }
341
342
343
344 final int n = (int) FastMath.ceil(maxDate.durationFrom(minDate) / tStep);
345 final List<Transform> b2iList = new ArrayList<Transform>(n);
346 final List<Transform> s2iList = new ArrayList<Transform>(n);
347 for (int i = 0; i < n; ++i) {
348 if (bodyToInertial.containsKey(i)) {
349
350 b2iList.add(bodyToInertial.get(i));
351 s2iList.add(scToInertial.get(i));
352 } else {
353
354 final Map.Entry<Integer, Transform> lower = bodyToInertial.lowerEntry(i);
355 final Map.Entry<Integer, Transform> higher = bodyToInertial.higherEntry(i);
356 final int closest;
357 if (lower == null) {
358 closest = higher.getKey();
359 } else if (higher == null) {
360 closest = lower.getKey();
361 } else {
362 closest = (i - lower.getKey() <= higher.getKey() - i) ? lower.getKey() : higher.getKey();
363 }
364 b2iList.add(bodyToInertial.get(closest).shiftedBy((i - closest) * tStep));
365 s2iList.add(scToInertial.get(closest).shiftedBy((i - closest) * tStep));
366 }
367 }
368
369
370
371 final SpacecraftToObservedBody scToBody =
372 new SpacecraftToObservedBody(inertialFrame, ellipsoid.getBodyFrame(),
373 minDate, maxDate, tStep, tolerance,
374 b2iList, s2iList);
375 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
376 new ObjectOutputStream(bos).writeObject(scToBody);
377 final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
378 builder.setTrajectoryAndTimeSpan(bis);
379
380 final List<SensorMeanPlaneCrossing> planeCrossings = new ArrayList<SensorMeanPlaneCrossing>();
381 for (final ParsedSensor parsedSensor : sensors) {
382 final LineSensoreSensor.html#LineSensor">LineSensor sensor = new LineSensor(parsedSensor.name,
383 parsedSensor,
384 parsedSensor.position,
385 parsedSensor);
386 if (parsedSensor.meanPlane != null) {
387 planeCrossings.add(new SensorMeanPlaneCrossing(sensor, scToBody,
388 parsedSensor.meanPlane.minLine,
389 parsedSensor.meanPlane.maxLine,
390 lightTimeCorrection, aberrationOfLightCorrection,
391 parsedSensor.meanPlane.maxEval,
392 parsedSensor.meanPlane.accuracy,
393 parsedSensor.meanPlane.normal,
394 Arrays.stream(parsedSensor.meanPlane.cachedResults)));
395 }
396 builder.addLineSensor(sensor);
397 }
398
399 final Rugged rugged = builder.build();
400
401 final Method setPlaneCrossing = Rugged.class.getDeclaredMethod("setPlaneCrossing",
402 SensorMeanPlaneCrossing.class);
403 setPlaneCrossing.setAccessible(true);
404 for (final SensorMeanPlaneCrossing planeCrossing : planeCrossings) {
405 setPlaneCrossing.invoke(rugged, planeCrossing);
406 }
407
408 return rugged;
409
410 } catch (IOException ioe) {
411 throw new RuggedException(ioe, LocalizedCoreFormats.SIMPLE_MESSAGE, ioe.getLocalizedMessage());
412 } catch (SecurityException e) {
413
414 throw new RuggedInternalError(e);
415 } catch (NoSuchMethodException e) {
416
417 throw new RuggedInternalError(e);
418 } catch (IllegalArgumentException e) {
419
420 throw new RuggedInternalError(e);
421 } catch (IllegalAccessException e) {
422
423 throw new RuggedInternalError(e);
424 } catch (InvocationTargetException e) {
425
426 throw new RuggedInternalError(e);
427 }
428 }
429
430
431
432
433
434 private ParsedSensor getSensor(final String name) {
435 for (final ParsedSensor sensor : sensors) {
436 if (sensor.name.equals(name)) {
437 return sensor;
438 }
439 }
440 final ParsedSensor sensor = new ParsedSensor(name);
441 sensors.add(sensor);
442 return sensor;
443 }
444
445
446
447
448
449
450
451
452
453 public Result[] execute(final Rugged rugged) {
454 final Result[] results = new Result[calls.size()];
455 for (int i = 0; i < calls.size(); ++i) {
456 results[i] = new Result(calls.get(i).expected,
457 calls.get(i).execute(rugged));
458 }
459 return results;
460 }
461
462
463 public static class Result {
464
465
466 private final Object expected;
467
468
469 private final Object replayed;
470
471
472
473
474
475 private Result(final Object expected, final Object replayed) {
476 this.expected = expected;
477 this.replayed = replayed;
478 }
479
480
481
482
483 public Object getExpected() {
484 return expected;
485 }
486
487
488
489
490 public Object getReplayed() {
491 return replayed;
492 }
493
494 }
495
496
497 private enum LineParser {
498
499
500 ALGORITHM() {
501
502
503 @Override
504 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
505 try {
506 if (fields.length < 1) {
507 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
508 }
509 global.algorithmId = AlgorithmId.valueOf(fields[0]);
510 if (global.algorithmId == AlgorithmId.CONSTANT_ELEVATION_OVER_ELLIPSOID) {
511 if (fields.length < 3 || !fields[1].equals(ELEVATION)) {
512 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
513 }
514 global.constantElevation = Double.parseDouble(fields[2]);
515 }
516 } catch (IllegalArgumentException iae) {
517 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
518 }
519 }
520
521 },
522
523
524 ELLIPSOID() {
525
526
527 @Override
528 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
529 if (fields.length < 6 || !fields[0].equals(AE) || !fields[2].equals(F) || !fields[4].equals(FRAME)) {
530 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
531 }
532 final double ae = Double.parseDouble(fields[1]);
533 final double f = Double.parseDouble(fields[3]);
534 final Frame bodyFrame;
535 try {
536 bodyFrame = FramesFactory.getFrame(Predefined.valueOf(fields[5]));
537 } catch (IllegalArgumentException iae) {
538 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
539 }
540 global.ellipsoid = new OneAxisEllipsoid(ae, f, bodyFrame);
541 }
542
543 },
544
545
546 DIRECT_LOCATION() {
547
548
549 @Override
550 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
551 if (fields.length < 16 ||
552 !fields[0].equals(DATE) ||
553 !fields[2].equals(POSITION) || !fields[6].equals(LOS) ||
554 !fields[10].equals(LIGHT_TIME) || !fields[12].equals(ABERRATION) ||
555 !fields[14].equals(REFRACTION)) {
556 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
557 }
558 final AbsoluteDate date = new AbsoluteDate(fields[1], TimeScalesFactory.getUTC());
559 final Vector3D position = new Vector3D(Double.parseDouble(fields[3]),
560 Double.parseDouble(fields[4]),
561 Double.parseDouble(fields[5]));
562 final Vector3D los = new Vector3D(Double.parseDouble(fields[7]),
563 Double.parseDouble(fields[8]),
564 Double.parseDouble(fields[9]));
565 if (global.calls.isEmpty()) {
566 global.lightTimeCorrection = Boolean.parseBoolean(fields[11]);
567 global.aberrationOfLightCorrection = Boolean.parseBoolean(fields[13]);
568 global.atmosphericRefraction = Boolean.parseBoolean(fields[15]);
569 } else {
570 if (global.lightTimeCorrection != Boolean.parseBoolean(fields[11])) {
571 throw new RuggedException(RuggedMessages.LIGHT_TIME_CORRECTION_REDEFINED,
572 l, file.getAbsolutePath(), line);
573 }
574 if (global.aberrationOfLightCorrection != Boolean.parseBoolean(fields[13])) {
575 throw new RuggedException(RuggedMessages.ABERRATION_OF_LIGHT_CORRECTION_REDEFINED,
576 l, file.getAbsolutePath(), line);
577 }
578 if (global.atmosphericRefraction != Boolean.parseBoolean(fields[15])) {
579 throw new RuggedException(RuggedMessages.ATMOSPHERIC_REFRACTION_REDEFINED,
580 l, file.getAbsolutePath(), line);
581 }
582 }
583 global.calls.add(new DumpedCall() {
584
585
586 @Override
587 public Object execute(final Rugged rugged) {
588 return rugged.directLocation(date, position, los);
589 }
590
591 });
592 }
593 },
594
595
596 DIRECT_LOCATION_RESULT() {
597
598
599 @Override
600 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
601 if (fields.length == 1) {
602 if (fields[0].equals(NULL_RESULT)) {
603 final GeodeticPoint gp = null;
604 final DumpedCall last = global.calls.get(global.calls.size() - 1);
605 last.expected = gp;
606 } else {
607 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
608 }
609 } else if (fields.length < 6 || !fields[0].equals(LATITUDE) ||
610 !fields[2].equals(LONGITUDE) || !fields[4].equals(ELEVATION)) {
611 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
612 } else {
613 final GeodeticPoint gp = new GeodeticPoint(Double.parseDouble(fields[1]),
614 Double.parseDouble(fields[3]),
615 Double.parseDouble(fields[5]));
616 final DumpedCall last = global.calls.get(global.calls.size() - 1);
617 last.expected = gp;
618 }
619 }
620
621 },
622
623
624 SPAN() {
625
626
627 @Override
628 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
629 if (fields.length < 10 ||
630 !fields[0].equals(MIN_DATE) || !fields[2].equals(MAX_DATE) || !fields[4].equals(T_STEP) ||
631 !fields[6].equals(TOLERANCE) || !fields[8].equals(INERTIAL_FRAME)) {
632 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
633 }
634 global.minDate = new AbsoluteDate(fields[1], TimeScalesFactory.getUTC());
635 global.maxDate = new AbsoluteDate(fields[3], TimeScalesFactory.getUTC());
636 global.tStep = Double.parseDouble(fields[5]);
637 global.tolerance = Double.parseDouble(fields[7]);
638 global.bodyToInertial = new TreeMap<Integer, Transform>();
639 global.scToInertial = new TreeMap<Integer, Transform>();
640 try {
641 global.inertialFrame = FramesFactory.getFrame(Predefined.valueOf(fields[9]));
642 } catch (IllegalArgumentException iae) {
643 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
644 }
645 }
646 },
647
648
649 TRANSFORM() {
650
651
652 @Override
653 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
654 if (fields.length < 42 ||
655 !fields[0].equals(INDEX) ||
656 !fields[2].equals(BODY) ||
657 !fields[3].equals(R) || !fields[8].equals(OMEGA) || !fields[12].equals(OMEGA_DOT) ||
658 !fields[16].equals(SPACECRAFT) ||
659 !fields[17].equals(P) || !fields[21].equals(V) || !fields[25].equals(A) ||
660 !fields[29].equals(R) || !fields[34].equals(OMEGA) || !fields[38].equals(OMEGA_DOT)) {
661 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
662 }
663 final int i = Integer.parseInt(fields[1]);
664 final AbsoluteDate date = global.minDate.shiftedBy(i * global.tStep);
665 global.bodyToInertial.put(i,
666 new Transform(date,
667 new Rotation(Double.parseDouble(fields[4]),
668 Double.parseDouble(fields[5]),
669 Double.parseDouble(fields[6]),
670 Double.parseDouble(fields[7]),
671 false),
672 new Vector3D(Double.parseDouble(fields[9]),
673 Double.parseDouble(fields[10]),
674 Double.parseDouble(fields[11])),
675 new Vector3D(Double.parseDouble(fields[13]),
676 Double.parseDouble(fields[14]),
677 Double.parseDouble(fields[15]))));
678 global.scToInertial.put(i,
679 new Transform(date,
680 new Transform(date,
681 new Vector3D(Double.parseDouble(fields[18]),
682 Double.parseDouble(fields[19]),
683 Double.parseDouble(fields[20])),
684 new Vector3D(Double.parseDouble(fields[22]),
685 Double.parseDouble(fields[23]),
686 Double.parseDouble(fields[24])),
687 new Vector3D(Double.parseDouble(fields[26]),
688 Double.parseDouble(fields[27]),
689 Double.parseDouble(fields[28]))),
690 new Transform(date,
691 new Rotation(Double.parseDouble(fields[30]),
692 Double.parseDouble(fields[31]),
693 Double.parseDouble(fields[32]),
694 Double.parseDouble(fields[33]),
695 false),
696 new Vector3D(Double.parseDouble(fields[35]),
697 Double.parseDouble(fields[36]),
698 Double.parseDouble(fields[37])),
699 new Vector3D(Double.parseDouble(fields[39]),
700 Double.parseDouble(fields[40]),
701 Double.parseDouble(fields[41])))));
702 }
703
704 },
705
706
707 DEM_TILE() {
708
709
710 @Override
711 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
712 if (fields.length < 13 ||
713 !fields[1].equals(LAT_MIN) || !fields[3].equals(LAT_STEP) || !fields[5].equals(LAT_ROWS) ||
714 !fields[7].equals(LON_MIN) || !fields[9].equals(LON_STEP) || !fields[11].equals(LON_COLS)) {
715 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
716 }
717 final String name = fields[0];
718 final double minLatitude = Double.parseDouble(fields[2]);
719 final double latitudeStep = Double.parseDouble(fields[4]);
720 final int latitudeRows = Integer.parseInt(fields[6]);
721 final double minLongitude = Double.parseDouble(fields[8]);
722 final double longitudeStep = Double.parseDouble(fields[10]);
723 final int longitudeColumns = Integer.parseInt(fields[12]);
724 for (final ParsedTile tile : global.tiles) {
725 if (tile.name.equals(name)) {
726 throw new RuggedException(RuggedMessages.TILE_ALREADY_DEFINED,
727 name, l, file.getAbsolutePath(), line);
728 }
729 }
730 global.tiles.add(new ParsedTile(name,
731 minLatitude, latitudeStep, latitudeRows,
732 minLongitude, longitudeStep, longitudeColumns));
733 }
734
735 },
736
737
738 DEM_CELL() {
739
740
741 @Override
742 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
743 if (fields.length < 7 ||
744 !fields[1].equals(LAT_INDEX) || !fields[3].equals(LON_INDEX) || !fields[5].equals(ELEVATION)) {
745 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
746 }
747 final String name = fields[0];
748 final int latIndex = Integer.parseInt(fields[2]);
749 final int lonIndex = Integer.parseInt(fields[4]);
750 final double elevation = Double.parseDouble(fields[6]);
751 for (final ParsedTile tile : global.tiles) {
752 if (tile.name.equals(name)) {
753 final int index = latIndex * tile.longitudeColumns + lonIndex;
754 tile.elevations.put(index, elevation);
755 return;
756 }
757 }
758 throw new RuggedException(RuggedMessages.UNKNOWN_TILE,
759 name, l, file.getAbsolutePath(), line);
760 }
761
762 },
763
764
765 INVERSE_LOCATION() {
766
767
768 @Override
769 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
770 if (fields.length < 18 ||
771 !fields[0].equals(SENSOR_NAME) ||
772 !fields[2].equals(LATITUDE) || !fields[4].equals(LONGITUDE) || !fields[6].equals(ELEVATION) ||
773 !fields[8].equals(MIN_LINE) || !fields[10].equals(MAX_LINE) ||
774 !fields[12].equals(LIGHT_TIME) || !fields[14].equals(ABERRATION) ||
775 !fields[16].equals(REFRACTION)) {
776 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
777 }
778 final String sensorName = fields[1];
779 final GeodeticPoint point = new GeodeticPoint(Double.parseDouble(fields[3]),
780 Double.parseDouble(fields[5]),
781 Double.parseDouble(fields[7]));
782 final int minLine = Integer.parseInt(fields[9]);
783 final int maxLine = Integer.parseInt(fields[11]);
784 if (global.calls.isEmpty()) {
785 global.lightTimeCorrection = Boolean.parseBoolean(fields[13]);
786 global.aberrationOfLightCorrection = Boolean.parseBoolean(fields[15]);
787 global.atmosphericRefraction = Boolean.parseBoolean(fields[17]);
788 } else {
789 if (global.lightTimeCorrection != Boolean.parseBoolean(fields[13])) {
790 throw new RuggedException(RuggedMessages.LIGHT_TIME_CORRECTION_REDEFINED,
791 l, file.getAbsolutePath(), line);
792 }
793 if (global.aberrationOfLightCorrection != Boolean.parseBoolean(fields[15])) {
794 throw new RuggedException(RuggedMessages.ABERRATION_OF_LIGHT_CORRECTION_REDEFINED,
795 l, file.getAbsolutePath(), line);
796 }
797 if (global.atmosphericRefraction != Boolean.parseBoolean(fields[17])) {
798 throw new RuggedException(RuggedMessages.ATMOSPHERIC_REFRACTION_REDEFINED,
799 l, file.getAbsolutePath(), line);
800 }
801 }
802 global.calls.add(new DumpedCall() {
803
804
805 @Override
806 public Object execute(final Rugged rugged) {
807 return rugged.inverseLocation(sensorName, point, minLine, maxLine);
808 }
809
810 });
811 }
812
813 },
814
815
816 INVERSE_LOCATION_RESULT() {
817
818
819 @Override
820 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
821 if (fields.length == 1) {
822 if (fields[0].equals(NULL_RESULT)) {
823 final SensorPixel sp = null;
824 final DumpedCall last = global.calls.get(global.calls.size() - 1);
825 last.expected = sp;
826 } else {
827 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
828 }
829 } else if (fields.length < 4 || !fields[0].equals(LINE_NUMBER) || !fields[2].equals(PIXEL_NUMBER)) {
830 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
831 } else {
832 final SensorPixelSensorPixel.html#SensorPixel">SensorPixel sp = new SensorPixel(Double.parseDouble(fields[1]),
833 Double.parseDouble(fields[3]));
834 final DumpedCall last = global.calls.get(global.calls.size() - 1);
835 last.expected = sp;
836 }
837 }
838
839 },
840
841
842 SENSOR() {
843
844
845 @Override
846 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
847 if (fields.length < 8 || !fields[0].equals(SENSOR_NAME) ||
848 !fields[2].equals(NB_PIXELS) || !fields[4].equals(POSITION)) {
849 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
850 }
851 final ParsedSensor sensor = global.getSensor(fields[1]);
852 sensor.setNbPixels(Integer.parseInt(fields[3]));
853 sensor.setPosition(new Vector3D(Double.parseDouble(fields[5]),
854 Double.parseDouble(fields[6]),
855 Double.parseDouble(fields[7])));
856 }
857
858 },
859
860
861 SENSOR_MEAN_PLANE() {
862
863
864 @Override
865 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
866 if (fields.length < 16 || !fields[0].equals(SENSOR_NAME) ||
867 !fields[2].equals(MIN_LINE) || !fields[4].equals(MAX_LINE) ||
868 !fields[6].equals(MAX_EVAL) || !fields[8].equals(ACCURACY) ||
869 !fields[10].equals(NORMAL) || !fields[14].equals(CACHED_RESULTS)) {
870 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
871 }
872 final String sensorName = fields[1];
873 final int minLine = Integer.parseInt(fields[3]);
874 final int maxLine = Integer.parseInt(fields[5]);
875 final int maxEval = Integer.parseInt(fields[7]);
876 final double accuracy = Double.parseDouble(fields[9]);
877 final Vector3D normal = new Vector3D(Double.parseDouble(fields[11]),
878 Double.parseDouble(fields[12]),
879 Double.parseDouble(fields[13]));
880 final int n = Integer.parseInt(fields[15]);
881 final CrossingResult[] cachedResults = new CrossingResult[n];
882 int base = 16;
883 for (int i = 0; i < n; ++i) {
884 if (fields.length < base + 15 || !fields[base].equals(LINE_NUMBER) ||
885 !fields[base + 2].equals(DATE) || !fields[base + 4].equals(TARGET) ||
886 !fields[base + 8].equals(TARGET_DIRECTION)) {
887 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
888 }
889 final double ln = Double.parseDouble(fields[base + 1]);
890 final AbsoluteDate date = new AbsoluteDate(fields[base + 3], TimeScalesFactory.getUTC());
891 final Vector3D target = new Vector3D(Double.parseDouble(fields[base + 5]),
892 Double.parseDouble(fields[base + 6]),
893 Double.parseDouble(fields[base + 7]));
894 final Vector3D targetDirection = new Vector3D(Double.parseDouble(fields[base + 9]),
895 Double.parseDouble(fields[base + 10]),
896 Double.parseDouble(fields[base + 11]));
897 final Vector3D targetDirectionDerivative = new Vector3D(Double.parseDouble(fields[base + 12]),
898 Double.parseDouble(fields[base + 13]),
899 Double.parseDouble(fields[base + 14]));
900 cachedResults[i] = new CrossingResult(date, ln, target, targetDirection, targetDirectionDerivative);
901 base += 15;
902 }
903 global.getSensor(sensorName).setMeanPlane(new ParsedMeanPlane(minLine, maxLine, maxEval, accuracy, normal, cachedResults));
904 }
905 },
906
907
908 SENSOR_LOS() {
909
910
911 @Override
912 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
913 if (fields.length < 10 || !fields[0].equals(SENSOR_NAME) ||
914 !fields[2].equals(DATE) || !fields[4].equals(PIXEL_NUMBER) ||
915 !fields[6].equals(LOS)) {
916 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
917 }
918 final String sensorName = fields[1];
919 final AbsoluteDate date = new AbsoluteDate(fields[3], TimeScalesFactory.getUTC());
920 final int pixelNumber = Integer.parseInt(fields[5]);
921 final Vector3D los = new Vector3D(Double.parseDouble(fields[7]),
922 Double.parseDouble(fields[8]),
923 Double.parseDouble(fields[9]));
924 global.getSensor(sensorName).setLOS(date, pixelNumber, los);
925 }
926 },
927
928
929 SENSOR_DATATION() {
930
931
932 @Override
933 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
934 if (fields.length < 6 || !fields[0].equals(SENSOR_NAME) ||
935 !fields[2].equals(LINE_NUMBER) || !fields[4].equals(DATE)) {
936 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
937 }
938 final String sensorName = fields[1];
939 final double lineNumber = Double.parseDouble(fields[3]);
940 final AbsoluteDate date = new AbsoluteDate(fields[5], TimeScalesFactory.getUTC());
941 global.getSensor(sensorName).setDatation(lineNumber, date);
942 }
943 },
944
945
946 SENSOR_RATE() {
947
948
949 @Override
950 public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
951 if (fields.length < 6 || !fields[0].equals(SENSOR_NAME) ||
952 !fields[2].equals(LINE_NUMBER) || !fields[4].equals(RATE)) {
953 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
954 }
955 final String sensorName = fields[1];
956 final double lineNumber = Double.parseDouble(fields[3]);
957 final double rate = Double.parseDouble(fields[5]);
958 global.getSensor(sensorName).setRate(lineNumber, rate);
959
960 }
961
962 };
963
964
965
966
967
968
969
970 public static void parse(final int l, final File file, final String line, final DumpReplayer global) {
971
972 final String trimmed = line.trim();
973 if (trimmed.length() == 0 || trimmed.startsWith(COMMENT_START)) {
974 return;
975 }
976
977 final int colon = line.indexOf(':');
978 if (colon > 0) {
979 final String parsedKey = line.substring(0, colon).trim().replaceAll(" ", "_").toUpperCase();
980 try {
981 final LineParser parser = LineParser.valueOf(parsedKey);
982 final String[] fields;
983 if (colon + 1 >= line.length()) {
984 fields = new String[0];
985 } else {
986 fields = line.substring(colon + 1).trim().split("\\s+");
987 }
988 parser.parse(l, file, line, fields, global);
989 } catch (IllegalArgumentException iae) {
990 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
991 }
992
993 } else {
994 throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
995 }
996
997 }
998
999
1000
1001
1002
1003
1004
1005
1006 public abstract void parse(int l, File file, String line, String[] fields, DumpReplayer global);
1007
1008 }
1009
1010
1011 private static class ParsedTile {
1012
1013
1014 private final String name;
1015
1016
1017 private final double minLatitude;
1018
1019
1020 private final double latitudeStep;
1021
1022
1023 private int latitudeRows;
1024
1025
1026 private final double minLongitude;
1027
1028
1029 private final double longitudeStep;
1030
1031
1032 private int longitudeColumns;
1033
1034
1035 private final OpenIntToDoubleHashMap elevations;
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 ParsedTile(final String name,
1047 final double minLatitude, final double latitudeStep, final int latitudeRows,
1048 final double minLongitude, final double longitudeStep, final int longitudeColumns) {
1049 this.name = name;
1050 this.minLatitude = minLatitude;
1051 this.latitudeStep = latitudeStep;
1052 this.minLongitude = minLongitude;
1053 this.longitudeStep = longitudeStep;
1054 this.latitudeRows = latitudeRows;
1055 this.longitudeColumns = longitudeColumns;
1056 this.elevations = new OpenIntToDoubleHashMap();
1057 }
1058
1059
1060
1061
1062
1063
1064 public boolean isInterpolable(final double latitude, final double longitude) {
1065 final int latitudeIndex = (int) FastMath.floor((latitude - minLatitude) / latitudeStep);
1066 final int longitudeIndex = (int) FastMath.floor((longitude - minLongitude) / longitudeStep);
1067 return (latitudeIndex >= 0) && (latitudeIndex <= latitudeRows - 2) &&
1068 (longitudeIndex >= 0) && (longitudeIndex <= longitudeColumns - 2);
1069 }
1070
1071
1072
1073
1074 public void updateTile(final UpdatableTile tile) {
1075
1076 tile.setGeometry(minLatitude, minLongitude,
1077 latitudeStep, longitudeStep,
1078 latitudeRows, longitudeColumns);
1079
1080 final OpenIntToDoubleHashMap.Iterator iterator = elevations.iterator();
1081 while (iterator.hasNext()) {
1082 iterator.advance();
1083 final int index = iterator.key();
1084 final int latitudeIndex = index / longitudeColumns;
1085 final int longitudeIndex = index % longitudeColumns;
1086 final double elevation = iterator.value();
1087 tile.setElevation(latitudeIndex, longitudeIndex, elevation);
1088 }
1089
1090 }
1091
1092 }
1093
1094
1095 private static class ParsedSensor implements LineDatation, TimeDependentLOS {
1096
1097
1098 private final String name;
1099
1100
1101 private int nbPixels;
1102
1103
1104 private Vector3D position;
1105
1106
1107 private ParsedMeanPlane meanPlane;
1108
1109
1110 private final Map<Integer, List<Pair<AbsoluteDate, Vector3D>>> losMap;
1111
1112
1113 private final List<Pair<Double, AbsoluteDate>> datation;
1114
1115
1116 private final List<Pair<Double, Double>> rates;
1117
1118
1119
1120
1121 ParsedSensor(final String name) {
1122 this.name = name;
1123 this.losMap = new HashMap<Integer, List<Pair<AbsoluteDate, Vector3D>>>();
1124 this.datation = new ArrayList<Pair<Double, AbsoluteDate>>();
1125 this.rates = new ArrayList<Pair<Double, Double>>();
1126 }
1127
1128
1129
1130
1131 public void setMeanPlane(final ParsedMeanPlane meanPlane) {
1132 this.meanPlane = meanPlane;
1133 }
1134
1135
1136
1137
1138 public void setPosition(final Vector3D position) {
1139 this.position = position;
1140 }
1141
1142
1143
1144
1145 public void setNbPixels(final int nbPixels) {
1146 this.nbPixels = nbPixels;
1147 }
1148
1149
1150 @Override
1151 public int getNbPixels() {
1152 return nbPixels;
1153 }
1154
1155
1156
1157
1158
1159
1160 public void setLOS(final AbsoluteDate date, final int pixelNumber, final Vector3D los) {
1161 List<Pair<AbsoluteDate, Vector3D>> list = losMap.get(pixelNumber);
1162 if (list == null) {
1163 list = new ArrayList<Pair<AbsoluteDate, Vector3D>>();
1164 losMap.put(pixelNumber, list);
1165 }
1166
1167 int index = 0;
1168 while (index < list.size()) {
1169 if (list.get(index).getFirst().compareTo(date) > 0) {
1170 break;
1171 }
1172 ++index;
1173 }
1174 list.add(index, new Pair<AbsoluteDate, Vector3D>(date, los));
1175 }
1176
1177
1178 @Override
1179 public Vector3D getLOS(final int index, final AbsoluteDate date) {
1180 final List<Pair<AbsoluteDate, Vector3D>> list = losMap.get(index);
1181 if (list == null) {
1182 throw new RuggedInternalError(null);
1183 }
1184
1185 if (list.size() < 2) {
1186 return list.get(0).getSecond();
1187 }
1188
1189
1190 int sup = 0;
1191 while (sup < list.size() - 1) {
1192 if (list.get(sup).getFirst().compareTo(date) >= 0) {
1193 break;
1194 }
1195 ++sup;
1196 }
1197 final int inf = (sup == 0) ? sup++ : (sup - 1);
1198
1199 final AbsoluteDate dInf = list.get(inf).getFirst();
1200 final Vector3D lInf = list.get(inf).getSecond();
1201 final AbsoluteDate dSup = list.get(sup).getFirst();
1202 final Vector3D lSup = list.get(sup).getSecond();
1203 final double alpha = date.durationFrom(dInf) / dSup.durationFrom(dInf);
1204 return new Vector3D(alpha, lSup, 1 - alpha, lInf);
1205
1206 }
1207
1208
1209 @Override
1210 public FieldVector3D<DerivativeStructure> getLOSDerivatives(final int index, final AbsoluteDate date,
1211 final DSGenerator generator) {
1212 final Vector3D los = getLOS(index, date);
1213 return new FieldVector3D<DerivativeStructure>(generator.constant(los.getX()),
1214 generator.constant(los.getY()),
1215 generator.constant(los.getZ()));
1216 }
1217
1218
1219
1220
1221
1222 public void setDatation(final double lineNumber, final AbsoluteDate date) {
1223
1224 int index = 0;
1225 while (index < datation.size()) {
1226 if (datation.get(index).getSecond().compareTo(date) > 0) {
1227 break;
1228 }
1229 ++index;
1230 }
1231 datation.add(index, new Pair<Double, AbsoluteDate>(lineNumber, date));
1232 }
1233
1234
1235 @Override
1236 public AbsoluteDate getDate(final double lineNumber) {
1237
1238 if (datation.size() < 2) {
1239 return datation.get(0).getSecond();
1240 }
1241
1242
1243 int sup = 0;
1244 while (sup < datation.size() - 1) {
1245 if (datation.get(sup).getFirst() >= lineNumber) {
1246 break;
1247 }
1248 ++sup;
1249 }
1250 final int inf = (sup == 0) ? sup++ : (sup - 1);
1251
1252 final double lInf = datation.get(inf).getFirst();
1253 final AbsoluteDate dInf = datation.get(inf).getSecond();
1254 final double lSup = datation.get(sup).getFirst();
1255 final AbsoluteDate dSup = datation.get(sup).getSecond();
1256 final double alpha = (lineNumber - lInf) / (lSup - lInf);
1257 return dInf.shiftedBy(alpha * dSup.durationFrom(dInf));
1258
1259 }
1260
1261
1262 @Override
1263 public double getLine(final AbsoluteDate date) {
1264
1265 if (datation.size() < 2) {
1266 return datation.get(0).getFirst();
1267 }
1268
1269
1270 int sup = 0;
1271 while (sup < datation.size() - 1) {
1272 if (datation.get(sup).getSecond().compareTo(date) >= 0) {
1273 break;
1274 }
1275 ++sup;
1276 }
1277 final int inf = (sup == 0) ? sup++ : (sup - 1);
1278
1279 final double lInf = datation.get(inf).getFirst();
1280 final AbsoluteDate dInf = datation.get(inf).getSecond();
1281 final double lSup = datation.get(sup).getFirst();
1282 final AbsoluteDate dSup = datation.get(sup).getSecond();
1283 final double alpha = date.durationFrom(dInf) / dSup.durationFrom(dInf);
1284 return alpha * lSup + (1 - alpha) * lInf;
1285
1286 }
1287
1288
1289
1290
1291
1292 public void setRate(final double lineNumber, final double rate) {
1293
1294 int index = 0;
1295 while (index < rates.size()) {
1296 if (rates.get(index).getFirst() > lineNumber) {
1297 break;
1298 }
1299 ++index;
1300 }
1301 rates.add(index, new Pair<Double, Double>(lineNumber, rate));
1302 }
1303
1304
1305 @Override
1306 public double getRate(final double lineNumber) {
1307
1308 if (rates.size() < 2) {
1309 return rates.get(0).getSecond();
1310 }
1311
1312
1313 int sup = 0;
1314 while (sup < rates.size() - 1) {
1315 if (rates.get(sup).getFirst() >= lineNumber) {
1316 break;
1317 }
1318 ++sup;
1319 }
1320 final int inf = (sup == 0) ? sup++ : (sup - 1);
1321
1322 final double lInf = rates.get(inf).getFirst();
1323 final double rInf = rates.get(inf).getSecond();
1324 final double lSup = rates.get(sup).getFirst();
1325 final double rSup = rates.get(sup).getSecond();
1326 final double alpha = (lineNumber - lInf) / (lSup - lInf);
1327 return alpha * rSup + (1 - alpha) * rInf;
1328
1329 }
1330
1331
1332 @Override
1333 public Stream<ParameterDriver> getParametersDrivers() {
1334 return Stream.<ParameterDriver>empty();
1335 }
1336
1337 }
1338
1339
1340 private static class ParsedMeanPlane {
1341
1342
1343 private final int minLine;
1344
1345
1346 private final int maxLine;
1347
1348
1349 private final int maxEval;
1350
1351
1352 private final double accuracy;
1353
1354
1355 private final Vector3D normal;
1356
1357
1358 private final CrossingResult[] cachedResults;
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368 ParsedMeanPlane(final int minLine, final int maxLine,
1369 final int maxEval, final double accuracy, final Vector3D normal,
1370 final CrossingResult[] cachedResults) {
1371 this.minLine = minLine;
1372 this.maxLine = maxLine;
1373 this.maxEval = maxEval;
1374 this.accuracy = accuracy;
1375 this.normal = normal;
1376 this.cachedResults = cachedResults.clone();
1377 }
1378
1379 }
1380
1381
1382 private abstract static class DumpedCall {
1383
1384
1385 private Object expected;
1386
1387
1388
1389
1390
1391 public abstract Object execute(Rugged rugged);
1392
1393 }
1394
1395 }