DumpReplayer.java
- /* Copyright 2013-2022 CS GROUP
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.rugged.errors;
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.ObjectOutputStream;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.NavigableMap;
- import java.util.TreeMap;
- import java.util.regex.Pattern;
- import java.util.stream.Stream;
- import org.hipparchus.analysis.differentiation.Derivative;
- import org.hipparchus.exception.LocalizedCoreFormats;
- import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
- import org.hipparchus.geometry.euclidean.threed.Rotation;
- import org.hipparchus.geometry.euclidean.threed.Vector3D;
- import org.hipparchus.util.FastMath;
- import org.hipparchus.util.OpenIntToDoubleHashMap;
- import org.hipparchus.util.Pair;
- import org.orekit.bodies.GeodeticPoint;
- import org.orekit.bodies.OneAxisEllipsoid;
- import org.orekit.frames.Frame;
- import org.orekit.frames.FramesFactory;
- import org.orekit.frames.Predefined;
- import org.orekit.frames.Transform;
- import org.orekit.rugged.api.AlgorithmId;
- import org.orekit.rugged.api.Rugged;
- import org.orekit.rugged.api.RuggedBuilder;
- import org.orekit.rugged.linesensor.LineDatation;
- import org.orekit.rugged.linesensor.LineSensor;
- import org.orekit.rugged.linesensor.SensorMeanPlaneCrossing;
- import org.orekit.rugged.linesensor.SensorMeanPlaneCrossing.CrossingResult;
- import org.orekit.rugged.linesensor.SensorPixel;
- import org.orekit.rugged.los.TimeDependentLOS;
- import org.orekit.rugged.raster.TileUpdater;
- import org.orekit.rugged.raster.UpdatableTile;
- import org.orekit.rugged.refraction.AtmosphericRefraction;
- import org.orekit.rugged.refraction.MultiLayerModel;
- import org.orekit.rugged.utils.DerivativeGenerator;
- import org.orekit.rugged.utils.ExtendedEllipsoid;
- import org.orekit.rugged.utils.SpacecraftToObservedBody;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.TimeScalesFactory;
- import org.orekit.utils.ParameterDriver;
- /** Replayer for Rugged debug dumps.
- * @author Luc Maisonobe
- * @author Guylaine Prat
- * @see DumpManager
- * @see Dump
- */
- public class DumpReplayer {
- /** Comment start marker. */
- private static final String COMMENT_START = "#";
- /** Keyword for latitude fields. */
- private static final String LATITUDE = "latitude";
- /** Keyword for longitude fields. */
- private static final String LONGITUDE = "longitude";
- /** Keyword for elevation fields. */
- private static final String ELEVATION = "elevation";
- /** Keyword for ellipsoid equatorial radius fields. */
- private static final String AE = "ae";
- /** Keyword for ellipsoid flattening fields. */
- private static final String F = "f";
- /** Keyword for frame fields. */
- private static final String FRAME = "frame";
- /** Keyword for date fields. */
- private static final String DATE = "date";
- /** Keyword for sensor position fields. */
- private static final String POSITION = "position";
- /** Keyword for sensor line-of-sight fields. */
- private static final String LOS = "los";
- /** Keyword for light-time correction fields. */
- private static final String LIGHT_TIME = "lightTime";
- /** Keyword for aberration of light correction fields. */
- private static final String ABERRATION = "aberration";
- /** Keyword for atmospheric refraction correction fields. */
- private static final String REFRACTION = "refraction";
- /** Keyword for min date fields. */
- private static final String MIN_DATE = "minDate";
- /** Keyword for max date fields. */
- private static final String MAX_DATE = "maxDate";
- /** Keyword for time step fields. */
- private static final String T_STEP = "tStep";
- /** Keyword for overshoot tolerance fields. */
- private static final String TOLERANCE = "tolerance";
- /** Keyword for inertial frames fields. */
- private static final String INERTIAL_FRAME = "inertialFrame";
- /** Keyword for observation transform index fields. */
- private static final String INDEX = "index";
- /** Keyword for body meta-fields. */
- private static final String BODY = "body";
- /** Keyword for rotation fields. */
- private static final String R = "r";
- /** Keyword for rotation rate fields. */
- private static final String OMEGA = "Ω";
- /** Keyword for rotation acceleration fields. */
- private static final String OMEGA_DOT = "ΩDot";
- /** Keyword for spacecraft meta-fields. */
- private static final String SPACECRAFT = "spacecraft";
- /** Keyword for position fields. */
- private static final String P = "p";
- /** Keyword for velocity fields. */
- private static final String V = "v";
- /** Keyword for acceleration fields. */
- private static final String A = "a";
- /** Keyword for minimum latitude fields. */
- private static final String LAT_MIN = "latMin";
- /** Keyword for latitude step fields. */
- private static final String LAT_STEP = "latStep";
- /** Keyword for latitude rows fields. */
- private static final String LAT_ROWS = "latRows";
- /** Keyword for minimum longitude fields. */
- private static final String LON_MIN = "lonMin";
- /** Keyword for longitude step fields. */
- private static final String LON_STEP = "lonStep";
- /** Keyword for longitude columns fields. */
- private static final String LON_COLS = "lonCols";
- /** Keyword for latitude index fields. */
- private static final String LAT_INDEX = "latIndex";
- /** Keyword for longitude index fields. */
- private static final String LON_INDEX = "lonIndex";
- /** Keyword for sensor name. */
- private static final String SENSOR_NAME = "sensorName";
- /** Keyword for min line. */
- private static final String MIN_LINE = "minLine";
- /** Keyword for max line. */
- private static final String MAX_LINE = "maxLine";
- /** Keyword for line number. */
- private static final String LINE_NUMBER = "lineNumber";
- /** Keyword for number of pixels. */
- private static final String NB_PIXELS = "nbPixels";
- /** Keyword for pixel number. */
- private static final String PIXEL_NUMBER = "pixelNumber";
- /** Keyword for max number of evaluations. */
- private static final String MAX_EVAL = "maxEval";
- /** Keyword for accuracy. */
- private static final String ACCURACY = "accuracy";
- /** Keyword for normal. */
- private static final String NORMAL = "normal";
- /** Keyword for rate. */
- private static final String RATE = "rate";
- /** Keyword for cached results. */
- private static final String CACHED_RESULTS = "cachedResults";
- /** Keyword for target. */
- private static final String TARGET = "target";
- /** Keyword for target direction. */
- private static final String TARGET_DIRECTION = "targetDirection";
- /** Keyword for null result. */
- private static final String NULL_RESULT = "NULL";
- /** Pattern for delimiting regular expressions. */
- private static final Pattern SEPARATOR = Pattern.compile("\\s+");
- /** Empty pattern. */
- private static final Pattern PATTERN = Pattern.compile(" ");
- /** Constant elevation for constant elevation algorithm. */
- private double constantElevation;
- /** Algorithm identifier. */
- private AlgorithmId algorithmId;
- /** Ellipsoid. */
- private OneAxisEllipsoid ellipsoid;
- /** Tiles list. */
- private final List<ParsedTile> tiles;
- /** Sensors list. */
- private final List<ParsedSensor> sensors;
- /** Interpolator min date. */
- private AbsoluteDate minDate;
- /** Interpolator max date. */
- private AbsoluteDate maxDate;
- /** Interpolator step. */
- private double tStep;
- /** Interpolator overshoot tolerance. */
- private double tolerance;
- /** Inertial frame. */
- private Frame inertialFrame;
- /** Transforms sample from observed body frame to inertial frame. */
- private NavigableMap<Integer, Transform> bodyToInertial;
- /** Transforms sample from spacecraft frame to inertial frame. */
- private NavigableMap<Integer, Transform> scToInertial;
- /** Flag for light time correction. */
- private boolean lightTimeCorrection;
- /** Flag for aberration of light correction. */
- private boolean aberrationOfLightCorrection;
- /** Flag for atmospheric refraction. */
- private boolean atmosphericRefraction;
- /** Dumped calls. */
- private final List<DumpedCall> calls;
- /** Simple constructor.
- */
- public DumpReplayer() {
- tiles = new ArrayList<>();
- sensors = new ArrayList<>();
- calls = new ArrayList<>();
- }
- /** Parse a dump file.
- * @param file dump file to parse
- */
- public void parse(final File file) {
- try {
- final BufferedReader reader =
- new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
- int l = 0;
- for (String line = reader.readLine(); line != null; line = reader.readLine()) {
- LineParser.parse(++l, file, line, this);
- }
- reader.close();
- } catch (IOException ioe) {
- throw new RuggedException(ioe, LocalizedCoreFormats.SIMPLE_MESSAGE, ioe.getLocalizedMessage());
- }
- }
- /** Create a Rugged instance from parsed data.
- * @return rugged instance
- */
- public Rugged createRugged() {
- try {
- final RuggedBuilder builder = new RuggedBuilder();
- if (algorithmId == null) {
- algorithmId = AlgorithmId.IGNORE_DEM_USE_ELLIPSOID;
- }
- builder.setAlgorithm(algorithmId);
- if (algorithmId == AlgorithmId.CONSTANT_ELEVATION_OVER_ELLIPSOID) {
- builder.setConstantElevation(constantElevation);
- } else if (algorithmId != AlgorithmId.IGNORE_DEM_USE_ELLIPSOID) {
- builder.setDigitalElevationModel(new TileUpdater() {
- /** {@inheritDoc} */
- @Override
- public void updateTile(final double latitude, final double longitude, final UpdatableTile tile) {
- for (final ParsedTile parsedTile : tiles) {
- if (parsedTile.isInterpolable(latitude, longitude)) {
- parsedTile.updateTile(tile);
- return;
- }
- }
- throw new RuggedException(RuggedMessages.NO_DEM_DATA,
- FastMath.toDegrees(latitude), FastMath.toDegrees(longitude));
- }
- }, 8);
- }
- builder.setEllipsoid(ellipsoid);
- builder.setLightTimeCorrection(lightTimeCorrection);
- builder.setAberrationOfLightCorrection(aberrationOfLightCorrection);
- if (atmosphericRefraction) { // Use the default model with the default configuration values
- final ExtendedEllipsoid extendedEllipsoid = builder.getEllipsoid();
- final AtmosphericRefraction atmosphericModel = new MultiLayerModel(extendedEllipsoid);
- // Build Rugged with atmospheric refraction model
- builder.setRefractionCorrection(atmosphericModel);
- }
- // build missing transforms by extrapolating the parsed ones
- final int n = (int) FastMath.ceil(maxDate.durationFrom(minDate) / tStep);
- final List<Transform> b2iList = new ArrayList<>(n);
- final List<Transform> s2iList = new ArrayList<>(n);
- for (int i = 0; i < n; ++i) {
- if (bodyToInertial.containsKey(i)) {
- // the i-th transform was dumped
- b2iList.add(bodyToInertial.get(i));
- s2iList.add(scToInertial.get(i));
- } else {
- // the i-th transformed was not dumped, we have to extrapolate it
- final Map.Entry<Integer, Transform> lower = bodyToInertial.lowerEntry(i);
- final Map.Entry<Integer, Transform> higher = bodyToInertial.higherEntry(i);
- final int closest;
- if (lower == null) {
- closest = higher.getKey();
- } else if (higher == null) {
- closest = lower.getKey();
- } else {
- closest = (i - lower.getKey() <= higher.getKey() - i) ? lower.getKey() : higher.getKey();
- }
- b2iList.add(bodyToInertial.get(closest).shiftedBy((i - closest) * tStep));
- s2iList.add(scToInertial.get(closest).shiftedBy((i - closest) * tStep));
- }
- }
- // we use Rugged transforms reloading mechanism to ensure the spacecraft
- // to body transforms will be the same as the ones dumped
- final SpacecraftToObservedBody scToBody =
- new SpacecraftToObservedBody(inertialFrame, ellipsoid.getBodyFrame(),
- minDate, maxDate, tStep, tolerance,
- b2iList, s2iList);
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- new ObjectOutputStream(bos).writeObject(scToBody);
- final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
- builder.setTrajectoryAndTimeSpan(bis);
- final List<SensorMeanPlaneCrossing> planeCrossings = new ArrayList<>();
- for (final ParsedSensor parsedSensor : sensors) {
- final LineSensor sensor = new LineSensor(parsedSensor.name,
- parsedSensor,
- parsedSensor.position,
- parsedSensor);
- if (parsedSensor.meanPlane != null) {
- planeCrossings.add(new SensorMeanPlaneCrossing(sensor, scToBody,
- parsedSensor.meanPlane.minLine,
- parsedSensor.meanPlane.maxLine,
- lightTimeCorrection, aberrationOfLightCorrection,
- parsedSensor.meanPlane.maxEval,
- parsedSensor.meanPlane.accuracy,
- parsedSensor.meanPlane.normal,
- Arrays.stream(parsedSensor.meanPlane.cachedResults)));
- }
- builder.addLineSensor(sensor);
- }
- final Rugged rugged = builder.build();
- final Method setPlaneCrossing = Rugged.class.getDeclaredMethod("setPlaneCrossing",
- SensorMeanPlaneCrossing.class);
- setPlaneCrossing.setAccessible(true);
- for (final SensorMeanPlaneCrossing planeCrossing : planeCrossings) {
- setPlaneCrossing.invoke(rugged, planeCrossing);
- }
- return rugged;
- } catch (IOException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
- // this should never happen
- throw new RuggedInternalError(e);
- }
- }
- /** Get a sensor by name.
- * @param name sensor name
- * @return parsed sensor
- */
- private ParsedSensor getSensor(final String name) {
- for (final ParsedSensor sensor : sensors) {
- if (sensor.name.equals(name)) {
- return sensor;
- }
- }
- final ParsedSensor sensor = new ParsedSensor(name);
- sensors.add(sensor);
- return sensor;
- }
- /** Execute all dumped calls.
- * <p>
- * The dumped calls correspond to computation methods like direct or inverse
- * location.
- * </p>
- * @param rugged Rugged instance on which calls will be performed
- * @return results of all dumped calls
- */
- public Result[] execute(final Rugged rugged) {
- final Result[] results = new Result[calls.size()];
- for (int i = 0; i < calls.size(); ++i) {
- results[i] = new Result(calls.get(i).expected,
- calls.get(i).execute(rugged));
- }
- return results;
- }
- /** Container for replay results. */
- public static class Result {
- /** Expected result. */
- private final Object expected;
- /** Replayed result. */
- private final Object replayed;
- /** Simple constructor.
- * @param expected expected result
- * @param replayed replayed result
- */
- private Result(final Object expected, final Object replayed) {
- this.expected = expected;
- this.replayed = replayed;
- }
- /** Get the expected result.
- * @return expected result
- */
- public Object getExpected() {
- return expected;
- }
- /** Get the replayed result.
- * @return replayed result
- */
- public Object getReplayed() {
- return replayed;
- }
- }
- /** Line parsers. */
- private enum LineParser {
- /** Parser for algorithm dump lines. */
- ALGORITHM() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- try {
- if (fields.length < 1) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- global.algorithmId = AlgorithmId.valueOf(fields[0]);
- if (global.algorithmId == AlgorithmId.CONSTANT_ELEVATION_OVER_ELLIPSOID) {
- if (fields.length < 3 || !fields[1].equals(ELEVATION)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- global.constantElevation = Double.parseDouble(fields[2]);
- }
- } catch (IllegalArgumentException iae) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- }
- },
- /** Parser for ellipsoid dump lines. */
- ELLIPSOID() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 6 || !fields[0].equals(AE) || !fields[2].equals(F) || !fields[4].equals(FRAME)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final double ae = Double.parseDouble(fields[1]);
- final double f = Double.parseDouble(fields[3]);
- final Frame bodyFrame;
- try {
- bodyFrame = FramesFactory.getFrame(Predefined.valueOf(fields[5]));
- } catch (IllegalArgumentException iae) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- global.ellipsoid = new OneAxisEllipsoid(ae, f, bodyFrame);
- }
- },
- /** Parser for direct location calls dump lines. */
- DIRECT_LOCATION() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 16 ||
- !fields[0].equals(DATE) ||
- !fields[2].equals(POSITION) || !fields[6].equals(LOS) ||
- !fields[10].equals(LIGHT_TIME) || !fields[12].equals(ABERRATION) ||
- !fields[14].equals(REFRACTION)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final AbsoluteDate date = new AbsoluteDate(fields[1], TimeScalesFactory.getUTC());
- final Vector3D position = new Vector3D(Double.parseDouble(fields[3]),
- Double.parseDouble(fields[4]),
- Double.parseDouble(fields[5]));
- final Vector3D los = new Vector3D(Double.parseDouble(fields[7]),
- Double.parseDouble(fields[8]),
- Double.parseDouble(fields[9]));
- if (global.calls.isEmpty()) {
- global.lightTimeCorrection = Boolean.parseBoolean(fields[11]);
- global.aberrationOfLightCorrection = Boolean.parseBoolean(fields[13]);
- global.atmosphericRefraction = Boolean.parseBoolean(fields[15]);
- } else {
- if (global.lightTimeCorrection != Boolean.parseBoolean(fields[11])) {
- throw new RuggedException(RuggedMessages.LIGHT_TIME_CORRECTION_REDEFINED,
- l, file.getAbsolutePath(), line);
- }
- if (global.aberrationOfLightCorrection != Boolean.parseBoolean(fields[13])) {
- throw new RuggedException(RuggedMessages.ABERRATION_OF_LIGHT_CORRECTION_REDEFINED,
- l, file.getAbsolutePath(), line);
- }
- if (global.atmosphericRefraction != Boolean.parseBoolean(fields[15])) {
- throw new RuggedException(RuggedMessages.ATMOSPHERIC_REFRACTION_REDEFINED,
- l, file.getAbsolutePath(), line);
- }
- }
- global.calls.add(new DumpedCall() {
- /** {@inheritDoc} */
- @Override
- public Object execute(final Rugged rugged) {
- return rugged.directLocation(date, position, los);
- }
- });
- }
- },
- /** Parser for direct location result dump lines. */
- DIRECT_LOCATION_RESULT() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length == 1) {
- if (fields[0].equals(NULL_RESULT)) {
- final GeodeticPoint gp = null;
- final DumpedCall last = global.calls.get(global.calls.size() - 1);
- last.expected = gp;
- } else {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- } else if (fields.length < 6 || !fields[0].equals(LATITUDE) ||
- !fields[2].equals(LONGITUDE) || !fields[4].equals(ELEVATION)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- } else {
- final GeodeticPoint gp = new GeodeticPoint(Double.parseDouble(fields[1]),
- Double.parseDouble(fields[3]),
- Double.parseDouble(fields[5]));
- final DumpedCall last = global.calls.get(global.calls.size() - 1);
- last.expected = gp;
- }
- }
- },
- /** Parser for search span dump lines. */
- SPAN() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 10 ||
- !fields[0].equals(MIN_DATE) || !fields[2].equals(MAX_DATE) || !fields[4].equals(T_STEP) ||
- !fields[6].equals(TOLERANCE) || !fields[8].equals(INERTIAL_FRAME)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- global.minDate = new AbsoluteDate(fields[1], TimeScalesFactory.getUTC());
- global.maxDate = new AbsoluteDate(fields[3], TimeScalesFactory.getUTC());
- global.tStep = Double.parseDouble(fields[5]);
- global.tolerance = Double.parseDouble(fields[7]);
- global.bodyToInertial = new TreeMap<Integer, Transform>();
- global.scToInertial = new TreeMap<Integer, Transform>();
- try {
- global.inertialFrame = FramesFactory.getFrame(Predefined.valueOf(fields[9]));
- } catch (IllegalArgumentException iae) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- }
- },
- /** Parser for observation transforms dump lines. */
- TRANSFORM() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 42 ||
- !fields[0].equals(INDEX) ||
- !fields[2].equals(BODY) ||
- !fields[3].equals(R) || !fields[8].equals(OMEGA) || !fields[12].equals(OMEGA_DOT) ||
- !fields[16].equals(SPACECRAFT) ||
- !fields[17].equals(P) || !fields[21].equals(V) || !fields[25].equals(A) ||
- !fields[29].equals(R) || !fields[34].equals(OMEGA) || !fields[38].equals(OMEGA_DOT)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final int i = Integer.parseInt(fields[1]);
- final AbsoluteDate date = global.minDate.shiftedBy(i * global.tStep);
- global.bodyToInertial.put(i,
- new Transform(date,
- new Rotation(Double.parseDouble(fields[4]),
- Double.parseDouble(fields[5]),
- Double.parseDouble(fields[6]),
- Double.parseDouble(fields[7]),
- false),
- new Vector3D(Double.parseDouble(fields[9]),
- Double.parseDouble(fields[10]),
- Double.parseDouble(fields[11])),
- new Vector3D(Double.parseDouble(fields[13]),
- Double.parseDouble(fields[14]),
- Double.parseDouble(fields[15]))));
- global.scToInertial.put(i,
- new Transform(date,
- new Transform(date,
- new Vector3D(Double.parseDouble(fields[18]),
- Double.parseDouble(fields[19]),
- Double.parseDouble(fields[20])),
- new Vector3D(Double.parseDouble(fields[22]),
- Double.parseDouble(fields[23]),
- Double.parseDouble(fields[24])),
- new Vector3D(Double.parseDouble(fields[26]),
- Double.parseDouble(fields[27]),
- Double.parseDouble(fields[28]))),
- new Transform(date,
- new Rotation(Double.parseDouble(fields[30]),
- Double.parseDouble(fields[31]),
- Double.parseDouble(fields[32]),
- Double.parseDouble(fields[33]),
- false),
- new Vector3D(Double.parseDouble(fields[35]),
- Double.parseDouble(fields[36]),
- Double.parseDouble(fields[37])),
- new Vector3D(Double.parseDouble(fields[39]),
- Double.parseDouble(fields[40]),
- Double.parseDouble(fields[41])))));
- }
- },
- /** Parser for DEM tile global geometry dump lines. */
- DEM_TILE() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 13 ||
- !fields[1].equals(LAT_MIN) || !fields[3].equals(LAT_STEP) || !fields[5].equals(LAT_ROWS) ||
- !fields[7].equals(LON_MIN) || !fields[9].equals(LON_STEP) || !fields[11].equals(LON_COLS)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final String name = fields[0];
- final double minLatitude = Double.parseDouble(fields[2]);
- final double latitudeStep = Double.parseDouble(fields[4]);
- final int latitudeRows = Integer.parseInt(fields[6]);
- final double minLongitude = Double.parseDouble(fields[8]);
- final double longitudeStep = Double.parseDouble(fields[10]);
- final int longitudeColumns = Integer.parseInt(fields[12]);
- for (final ParsedTile tile : global.tiles) {
- if (tile.name.equals(name)) {
- throw new RuggedException(RuggedMessages.TILE_ALREADY_DEFINED,
- name, l, file.getAbsolutePath(), line);
- }
- }
- global.tiles.add(new ParsedTile(name,
- minLatitude, latitudeStep, latitudeRows,
- minLongitude, longitudeStep, longitudeColumns));
- }
- },
- /** Parser for DEM cells dump lines. */
- DEM_CELL() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 7 ||
- !fields[1].equals(LAT_INDEX) || !fields[3].equals(LON_INDEX) || !fields[5].equals(ELEVATION)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final String name = fields[0];
- final int latIndex = Integer.parseInt(fields[2]);
- final int lonIndex = Integer.parseInt(fields[4]);
- final double elevation = Double.parseDouble(fields[6]);
- for (final ParsedTile tile : global.tiles) {
- if (tile.name.equals(name)) {
- final int index = latIndex * tile.longitudeColumns + lonIndex;
- tile.elevations.put(index, elevation);
- return;
- }
- }
- throw new RuggedException(RuggedMessages.UNKNOWN_TILE,
- name, l, file.getAbsolutePath(), line);
- }
- },
- /** Parser for inverse location calls dump lines. */
- INVERSE_LOCATION() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 18 ||
- !fields[0].equals(SENSOR_NAME) ||
- !fields[2].equals(LATITUDE) || !fields[4].equals(LONGITUDE) || !fields[6].equals(ELEVATION) ||
- !fields[8].equals(MIN_LINE) || !fields[10].equals(MAX_LINE) ||
- !fields[12].equals(LIGHT_TIME) || !fields[14].equals(ABERRATION) ||
- !fields[16].equals(REFRACTION)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final String sensorName = fields[1];
- final GeodeticPoint point = new GeodeticPoint(Double.parseDouble(fields[3]),
- Double.parseDouble(fields[5]),
- Double.parseDouble(fields[7]));
- final int minLine = Integer.parseInt(fields[9]);
- final int maxLine = Integer.parseInt(fields[11]);
- if (global.calls.isEmpty()) {
- global.lightTimeCorrection = Boolean.parseBoolean(fields[13]);
- global.aberrationOfLightCorrection = Boolean.parseBoolean(fields[15]);
- global.atmosphericRefraction = Boolean.parseBoolean(fields[17]);
- } else {
- if (global.lightTimeCorrection != Boolean.parseBoolean(fields[13])) {
- throw new RuggedException(RuggedMessages.LIGHT_TIME_CORRECTION_REDEFINED,
- l, file.getAbsolutePath(), line);
- }
- if (global.aberrationOfLightCorrection != Boolean.parseBoolean(fields[15])) {
- throw new RuggedException(RuggedMessages.ABERRATION_OF_LIGHT_CORRECTION_REDEFINED,
- l, file.getAbsolutePath(), line);
- }
- if (global.atmosphericRefraction != Boolean.parseBoolean(fields[17])) {
- throw new RuggedException(RuggedMessages.ATMOSPHERIC_REFRACTION_REDEFINED,
- l, file.getAbsolutePath(), line);
- }
- }
- global.calls.add(new DumpedCall() {
- /** {@inheritDoc} */
- @Override
- public Object execute(final Rugged rugged) {
- return rugged.inverseLocation(sensorName, point, minLine, maxLine);
- }
- });
- }
- },
- /** Parser for inverse location result dump lines. */
- INVERSE_LOCATION_RESULT() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length == 1) {
- if (fields[0].equals(NULL_RESULT)) {
- final SensorPixel sp = null;
- final DumpedCall last = global.calls.get(global.calls.size() - 1);
- last.expected = sp;
- } else {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- } else if (fields.length < 4 || !fields[0].equals(LINE_NUMBER) || !fields[2].equals(PIXEL_NUMBER)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- } else {
- final SensorPixel sp = new SensorPixel(Double.parseDouble(fields[1]),
- Double.parseDouble(fields[3]));
- final DumpedCall last = global.calls.get(global.calls.size() - 1);
- last.expected = sp;
- }
- }
- },
- /** Parser for sensor dump lines. */
- SENSOR() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 8 || !fields[0].equals(SENSOR_NAME) ||
- !fields[2].equals(NB_PIXELS) || !fields[4].equals(POSITION)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final ParsedSensor sensor = global.getSensor(fields[1]);
- sensor.setNbPixels(Integer.parseInt(fields[3]));
- sensor.setPosition(new Vector3D(Double.parseDouble(fields[5]),
- Double.parseDouble(fields[6]),
- Double.parseDouble(fields[7])));
- }
- },
- /** Parser for sensor mean plane dump lines. */
- SENSOR_MEAN_PLANE() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 16 || !fields[0].equals(SENSOR_NAME) ||
- !fields[2].equals(MIN_LINE) || !fields[4].equals(MAX_LINE) ||
- !fields[6].equals(MAX_EVAL) || !fields[8].equals(ACCURACY) ||
- !fields[10].equals(NORMAL) || !fields[14].equals(CACHED_RESULTS)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final String sensorName = fields[1];
- final int minLine = Integer.parseInt(fields[3]);
- final int maxLine = Integer.parseInt(fields[5]);
- final int maxEval = Integer.parseInt(fields[7]);
- final double accuracy = Double.parseDouble(fields[9]);
- final Vector3D normal = new Vector3D(Double.parseDouble(fields[11]),
- Double.parseDouble(fields[12]),
- Double.parseDouble(fields[13]));
- final int n = Integer.parseInt(fields[15]);
- final CrossingResult[] cachedResults = new CrossingResult[n];
- int base = 16;
- for (int i = 0; i < n; ++i) {
- if (fields.length < base + 15 || !fields[base].equals(LINE_NUMBER) ||
- !fields[base + 2].equals(DATE) || !fields[base + 4].equals(TARGET) ||
- !fields[base + 8].equals(TARGET_DIRECTION)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final double ln = Double.parseDouble(fields[base + 1]);
- final AbsoluteDate date = new AbsoluteDate(fields[base + 3], TimeScalesFactory.getUTC());
- final Vector3D target = new Vector3D(Double.parseDouble(fields[base + 5]),
- Double.parseDouble(fields[base + 6]),
- Double.parseDouble(fields[base + 7]));
- final Vector3D targetDirection = new Vector3D(Double.parseDouble(fields[base + 9]),
- Double.parseDouble(fields[base + 10]),
- Double.parseDouble(fields[base + 11]));
- final Vector3D targetDirectionDerivative = new Vector3D(Double.parseDouble(fields[base + 12]),
- Double.parseDouble(fields[base + 13]),
- Double.parseDouble(fields[base + 14]));
- cachedResults[i] = new CrossingResult(date, ln, target, targetDirection, targetDirectionDerivative);
- base += 15;
- }
- global.getSensor(sensorName).setMeanPlane(new ParsedMeanPlane(minLine, maxLine, maxEval, accuracy, normal, cachedResults));
- }
- },
- /** Parser for sensor LOS dump lines. */
- SENSOR_LOS() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 10 || !fields[0].equals(SENSOR_NAME) ||
- !fields[2].equals(DATE) || !fields[4].equals(PIXEL_NUMBER) ||
- !fields[6].equals(LOS)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final String sensorName = fields[1];
- final AbsoluteDate date = new AbsoluteDate(fields[3], TimeScalesFactory.getUTC());
- final int pixelNumber = Integer.parseInt(fields[5]);
- final Vector3D los = new Vector3D(Double.parseDouble(fields[7]),
- Double.parseDouble(fields[8]),
- Double.parseDouble(fields[9]));
- global.getSensor(sensorName).setLOS(date, pixelNumber, los);
- }
- },
- /** Parser for sensor datation dump lines. */
- SENSOR_DATATION() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 6 || !fields[0].equals(SENSOR_NAME) ||
- !fields[2].equals(LINE_NUMBER) || !fields[4].equals(DATE)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final String sensorName = fields[1];
- final double lineNumber = Double.parseDouble(fields[3]);
- final AbsoluteDate date = new AbsoluteDate(fields[5], TimeScalesFactory.getUTC());
- global.getSensor(sensorName).setDatation(lineNumber, date);
- }
- },
- /** Parser for sensor rate dump lines. */
- SENSOR_RATE() {
- /** {@inheritDoc} */
- @Override
- public void parse(final int l, final File file, final String line, final String[] fields, final DumpReplayer global) {
- if (fields.length < 6 || !fields[0].equals(SENSOR_NAME) ||
- !fields[2].equals(LINE_NUMBER) || !fields[4].equals(RATE)) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- final String sensorName = fields[1];
- final double lineNumber = Double.parseDouble(fields[3]);
- final double rate = Double.parseDouble(fields[5]);
- global.getSensor(sensorName).setRate(lineNumber, rate);
- }
- };
- /** Parse a line.
- * @param l line number
- * @param file dump file
- * @param line line to parse
- * @param global global parser to store parsed data
- */
- public static void parse(final int l, final File file, final String line, final DumpReplayer global) {
- final String trimmed = line.trim();
- if (trimmed.length() == 0 || trimmed.startsWith(COMMENT_START)) {
- return;
- }
- final int colon = line.indexOf(':');
- if (colon > 0) {
- final String parsedKey = PATTERN.matcher(line.substring(0, colon).trim()).replaceAll("_").toUpperCase();
- try {
- final LineParser parser = LineParser.valueOf(parsedKey);
- final String[] fields;
- if (colon + 1 >= line.length()) {
- fields = new String[0];
- } else {
- fields = SEPARATOR.split(line.substring(colon + 1).trim());
- }
- parser.parse(l, file, line, fields, global);
- } catch (IllegalArgumentException iae) {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- } else {
- throw new RuggedException(RuggedMessages.CANNOT_PARSE_LINE, l, file, line);
- }
- }
- /** Parse a line.
- * @param l line number
- * @param file dump file
- * @param line complete line
- * @param fields data fields from the line
- * @param global global parser to store parsed data
- */
- public abstract void parse(int l, File file, String line, String[] fields, DumpReplayer global);
- }
- /** Local class for handling already parsed tile data. */
- private static class ParsedTile {
- /** Name of the tile. */
- private final String name;
- /** Minimum latitude. */
- private final double minLatitude;
- /** Step in latitude (size of one raster element). */
- private final double latitudeStep;
- /** Number of latitude rows. */
- private int latitudeRows;
- /** Minimum longitude. */
- private final double minLongitude;
- /** Step in longitude (size of one raster element). */
- private final double longitudeStep;
- /** Number of longitude columns. */
- private int longitudeColumns;
- /** Raster elevation data. */
- private final OpenIntToDoubleHashMap elevations;
- /** Simple constructor.
- * @param name of the tile
- * @param minLatitude minimum latitude
- * @param latitudeStep step in latitude (size of one raster element)
- * @param latitudeRows number of latitude rows
- * @param minLongitude minimum longitude
- * @param longitudeStep step in longitude (size of one raster element)
- * @param longitudeColumns number of longitude columns
- */
- ParsedTile(final String name,
- final double minLatitude, final double latitudeStep, final int latitudeRows,
- final double minLongitude, final double longitudeStep, final int longitudeColumns) {
- this.name = name;
- this.minLatitude = minLatitude;
- this.latitudeStep = latitudeStep;
- this.minLongitude = minLongitude;
- this.longitudeStep = longitudeStep;
- this.latitudeRows = latitudeRows;
- this.longitudeColumns = longitudeColumns;
- this.elevations = new OpenIntToDoubleHashMap();
- }
- /** Check if a point is in the interpolable region of the tile.
- * @param latitude point latitude
- * @param longitude point longitude
- * @return true if the point is in the interpolable region of the tile
- */
- public boolean isInterpolable(final double latitude, final double longitude) {
- final int latitudeIndex = (int) FastMath.floor((latitude - minLatitude) / latitudeStep);
- final int longitudeIndex = (int) FastMath.floor((longitude - minLongitude) / longitudeStep);
- return latitudeIndex >= 0 && latitudeIndex <= latitudeRows - 2 &&
- longitudeIndex >= 0 && longitudeIndex <= longitudeColumns - 2;
- }
- /** Update the tile according to the Digital Elevation Model.
- * @param tile to update
- */
- public void updateTile(final UpdatableTile tile) {
- tile.setGeometry(minLatitude, minLongitude,
- latitudeStep, longitudeStep,
- latitudeRows, longitudeColumns);
- final OpenIntToDoubleHashMap.Iterator iterator = elevations.iterator();
- while (iterator.hasNext()) {
- iterator.advance();
- final int index = iterator.key();
- final int latitudeIndex = index / longitudeColumns;
- final int longitudeIndex = index % longitudeColumns;
- final double elevation = iterator.value();
- tile.setElevation(latitudeIndex, longitudeIndex, elevation);
- }
- }
- }
- /** Local class for handling already parsed sensor data. */
- private static class ParsedSensor implements LineDatation, TimeDependentLOS {
- /** Name of the sensor. */
- private final String name;
- /** Number of pixels. */
- private int nbPixels;
- /** Position. */
- private Vector3D position;
- /** Mean plane crossing finder. */
- private ParsedMeanPlane meanPlane;
- /** LOS map. */
- private final Map<Integer, List<Pair<AbsoluteDate, Vector3D>>> losMap;
- /** Datation. */
- private final List<Pair<Double, AbsoluteDate>> datation;
- /** Rate. */
- private final List<Pair<Double, Double>> rates;
- /** simple constructor.
- * @param name name of the sensor
- */
- ParsedSensor(final String name) {
- this.name = name;
- this.losMap = new HashMap<Integer, List<Pair<AbsoluteDate, Vector3D>>>();
- this.datation = new ArrayList<Pair<Double, AbsoluteDate>>();
- this.rates = new ArrayList<Pair<Double, Double>>();
- }
- /** Set the mean place finder.
- * @param meanPlane mean plane finder
- */
- public void setMeanPlane(final ParsedMeanPlane meanPlane) {
- this.meanPlane = meanPlane;
- }
- /** Set the position.
- * @param position position
- */
- public void setPosition(final Vector3D position) {
- this.position = position;
- }
- /** Set the number of pixels.
- * @param nbPixels number of pixels
- */
- public void setNbPixels(final int nbPixels) {
- this.nbPixels = nbPixels;
- }
- /** {@inheritDoc} */
- @Override
- public int getNbPixels() {
- return nbPixels;
- }
- /** Set a los direction.
- * @param date date
- * @param pixelNumber number of the pixel
- * @param los los direction
- */
- public void setLOS(final AbsoluteDate date, final int pixelNumber, final Vector3D los) {
- List<Pair<AbsoluteDate, Vector3D>> list = losMap.get(pixelNumber);
- if (list == null) {
- list = new ArrayList<Pair<AbsoluteDate, Vector3D>>();
- losMap.put(pixelNumber, list);
- }
- // find insertion index to have LOS sorted chronologically
- int index = 0;
- while (index < list.size()) {
- if (list.get(index).getFirst().compareTo(date) > 0) {
- break;
- }
- ++index;
- }
- list.add(index, new Pair<AbsoluteDate, Vector3D>(date, los));
- }
- /** {@inheritDoc} */
- @Override
- public Vector3D getLOS(final int index, final AbsoluteDate date) {
- final List<Pair<AbsoluteDate, Vector3D>> list = losMap.get(index);
- if (list == null) {
- throw new RuggedInternalError(null);
- }
- if (list.size() < 2) {
- return list.get(0).getSecond();
- }
- // find entries bracketing the the date
- int sup = 0;
- while (sup < list.size() - 1) {
- if (list.get(sup).getFirst().compareTo(date) >= 0) {
- break;
- }
- ++sup;
- }
- final int inf = (sup == 0) ? sup++ : (sup - 1);
- final AbsoluteDate dInf = list.get(inf).getFirst();
- final Vector3D lInf = list.get(inf).getSecond();
- final AbsoluteDate dSup = list.get(sup).getFirst();
- final Vector3D lSup = list.get(sup).getSecond();
- final double alpha = date.durationFrom(dInf) / dSup.durationFrom(dInf);
- return new Vector3D(alpha, lSup, 1 - alpha, lInf);
- }
- /** {@inheritDoc} */
- @Override
- public <T extends Derivative<T>> FieldVector3D<T> getLOSDerivatives(final int index, final AbsoluteDate date,
- final DerivativeGenerator<T> generator) {
- final Vector3D los = getLOS(index, date);
- return new FieldVector3D<>(generator.constant(los.getX()),
- generator.constant(los.getY()),
- generator.constant(los.getZ()));
- }
- /** Set a datation pair.
- * @param lineNumber line number
- * @param date date
- */
- public void setDatation(final double lineNumber, final AbsoluteDate date) {
- // find insertion index to have datations sorted chronologically
- int index = 0;
- while (index < datation.size()) {
- if (datation.get(index).getSecond().compareTo(date) > 0) {
- break;
- }
- ++index;
- }
- datation.add(index, new Pair<Double, AbsoluteDate>(lineNumber, date));
- }
- /** {@inheritDoc} */
- @Override
- public AbsoluteDate getDate(final double lineNumber) {
- if (datation.size() < 2) {
- return datation.get(0).getSecond();
- }
- // find entries bracketing the line number
- int sup = 0;
- while (sup < datation.size() - 1) {
- if (datation.get(sup).getFirst() >= lineNumber) {
- break;
- }
- ++sup;
- }
- final int inf = (sup == 0) ? sup++ : (sup - 1);
- final double lInf = datation.get(inf).getFirst();
- final AbsoluteDate dInf = datation.get(inf).getSecond();
- final double lSup = datation.get(sup).getFirst();
- final AbsoluteDate dSup = datation.get(sup).getSecond();
- final double alpha = (lineNumber - lInf) / (lSup - lInf);
- return dInf.shiftedBy(alpha * dSup.durationFrom(dInf));
- }
- /** {@inheritDoc} */
- @Override
- public double getLine(final AbsoluteDate date) {
- if (datation.size() < 2) {
- return datation.get(0).getFirst();
- }
- // find entries bracketing the date
- int sup = 0;
- while (sup < datation.size() - 1) {
- if (datation.get(sup).getSecond().compareTo(date) >= 0) {
- break;
- }
- ++sup;
- }
- final int inf = (sup == 0) ? sup++ : (sup - 1);
- final double lInf = datation.get(inf).getFirst();
- final AbsoluteDate dInf = datation.get(inf).getSecond();
- final double lSup = datation.get(sup).getFirst();
- final AbsoluteDate dSup = datation.get(sup).getSecond();
- final double alpha = date.durationFrom(dInf) / dSup.durationFrom(dInf);
- return alpha * lSup + (1 - alpha) * lInf;
- }
- /** Set a rate.
- * @param lineNumber line number
- * @param rate lines rate
- */
- public void setRate(final double lineNumber, final double rate) {
- // find insertion index to have rates sorted by line numbers
- int index = 0;
- while (index < rates.size()) {
- if (rates.get(index).getFirst() > lineNumber) {
- break;
- }
- ++index;
- }
- rates.add(index, new Pair<Double, Double>(lineNumber, rate));
- }
- /** {@inheritDoc} */
- @Override
- public double getRate(final double lineNumber) {
- if (rates.size() < 2) {
- return rates.get(0).getSecond();
- }
- // find entries bracketing the line number
- int sup = 0;
- while (sup < rates.size() - 1) {
- if (rates.get(sup).getFirst() >= lineNumber) {
- break;
- }
- ++sup;
- }
- final int inf = (sup == 0) ? sup++ : (sup - 1);
- final double lInf = rates.get(inf).getFirst();
- final double rInf = rates.get(inf).getSecond();
- final double lSup = rates.get(sup).getFirst();
- final double rSup = rates.get(sup).getSecond();
- final double alpha = (lineNumber - lInf) / (lSup - lInf);
- return alpha * rSup + (1 - alpha) * rInf;
- }
- /** {@inheritDoc} */
- @Override
- public Stream<ParameterDriver> getParametersDrivers() {
- return Stream.<ParameterDriver>empty();
- }
- }
- /** Local class for handling already parsed mean plane data. */
- private static class ParsedMeanPlane {
- /** Min line. */
- private final int minLine;
- /** Max line. */
- private final int maxLine;
- /** Maximum number of evaluations. */
- private final int maxEval;
- /** Accuracy to use for finding crossing line number. */
- private final double accuracy;
- /** Mean plane normal. */
- private final Vector3D normal;
- /** Cached results. */
- private final CrossingResult[] cachedResults;
- /** simple constructor.
- * @param minLine min line
- * @param maxLine max line
- * @param maxEval maximum number of evaluations
- * @param accuracy accuracy to use for finding crossing line number
- * @param normal mean plane normal
- * @param cachedResults cached results
- */
- ParsedMeanPlane(final int minLine, final int maxLine,
- final int maxEval, final double accuracy, final Vector3D normal,
- final CrossingResult[] cachedResults) {
- this.minLine = minLine;
- this.maxLine = maxLine;
- this.maxEval = maxEval;
- this.accuracy = accuracy;
- this.normal = normal;
- this.cachedResults = cachedResults.clone();
- }
- }
- /** Local interface for dumped calls. */
- private abstract static class DumpedCall {
- /** Expected result. */
- private Object expected;
- /** Execute a call.
- * @param rugged Rugged instance on which called should be performed
- * @return result of the call
- */
- public abstract Object execute(Rugged rugged);
- }
- }