Commit acd5a4d5 authored by Raphaël Fermé's avatar Raphaël Fermé
Browse files

First commit with AttitudeEphemerisFile interface

parent e4f44ab7
......@@ -26,6 +26,7 @@ import java.util.Map.Entry;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.general.AttitudeEphemerisFile;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.utils.TimeStampedAngularCoordinates;
......@@ -37,7 +38,7 @@ import org.orekit.utils.TimeStampedAngularCoordinates;
* @author Bryan Cazabonne
* @since 10.2
*/
public class AEMFile extends ADMFile {
public class AEMFile extends ADMFile implements AttitudeEphemerisFile {
/** List of ephemeris blocks. */
private List<AttitudeEphemeridesBlock> attitudeBlocks;
......@@ -78,11 +79,7 @@ public class AEMFile extends ADMFile {
}
/**
* Get the attitude loaded ephemeris for each satellite in the file.
* @return a map from the satellite's ID to the information about that satellite
* contained in the file.
*/
@Override
public Map<String, AemSatelliteEphemeris> getSatellites() {
final Map<String, List<AttitudeEphemeridesBlock>> satellites = new HashMap<>();
for (final AttitudeEphemeridesBlock ephemeridesBlock : attitudeBlocks) {
......@@ -93,16 +90,71 @@ public class AEMFile extends ADMFile {
final Map<String, AemSatelliteEphemeris> ret = new HashMap<>();
for (final Entry<String, List<AttitudeEphemeridesBlock>> entry : satellites.entrySet()) {
final String id = entry.getKey();
ret.put(id, new AemSatelliteEphemeris(entry.getValue()));
ret.put(id, new AemSatelliteEphemeris(id, entry.getValue()));
}
return ret;
}
/** AEM ephemeris blocks for a single satellite. */
public static class AemSatelliteEphemeris implements SatelliteAttitudeEphemeris {
/** ID of the satellite. */
private final String id;
/** The attitude ephemeris data for the satellite. */
private final List<AttitudeEphemeridesBlock> blocks;
/**
* Create a container for the set of ephemeris blocks in the file that pertain to
* a single satellite. The satellite's ID is set to ""
* @param blocks containing ephemeris data for the satellite.
* @deprecated in 10.3, replaced by {@link #AemSatelliteEphemeris(String, List)}
*/
@Deprecated
public AemSatelliteEphemeris(final List<AttitudeEphemeridesBlock> blocks) {
this("", blocks);
}
/**
* Create a container for the set of ephemeris blocks in the file that pertain to
* a single satellite.
* @param id of the satellite.
* @param blocks containing ephemeris data for the satellite.
* @since 10.3
*/
public AemSatelliteEphemeris(final String id, final List<AttitudeEphemeridesBlock> blocks) {
this.id = id;
this.blocks = blocks;
}
@Override
public String getId() {
return this.id;
}
@Override
public List<AttitudeEphemeridesBlock> getSegments() {
return Collections.unmodifiableList(blocks);
}
@Override
public AbsoluteDate getStart() {
return blocks.get(0).getStart();
}
@Override
public AbsoluteDate getStop() {
return blocks.get(blocks.size() - 1).getStop();
}
}
/**
* The Attitude Ephemerides Blocks class contain metadata
* and the list of attitude data lines.
*/
public class AttitudeEphemeridesBlock {
public class AttitudeEphemeridesBlock implements AttitudeEphemerisSegment {
/** Meta-data for the block. */
private ADMMetaData metaData;
......@@ -174,10 +226,7 @@ public class AEMFile extends ADMFile {
return attitudeDataLines;
}
/**
* Get an unmodifiable list of attitude data lines.
* @return a list of attitude data
*/
@Override
public List<TimeStampedAngularCoordinates> getAngularCoordinates() {
return Collections.unmodifiableList(this.attitudeDataLines);
}
......@@ -190,20 +239,13 @@ public class AEMFile extends ADMFile {
return metaData;
}
/**
* Get the name of the center of the coordinate system the ephemeris is provided in.
* This may be a natural origin, such as the center of the Earth, another satellite, etc.
* @return the name of the frame center
*/
@Override
public String getFrameCenterString() {
return this.getMetaData().getCenterName();
}
/**
* Get the reference frame A specifier as it appeared in the file.
* @return the frame name as it appeared in the file (A).
*/
@Override
public String getRefFrameAString() {
return refFrameAString;
}
......@@ -216,10 +258,7 @@ public class AEMFile extends ADMFile {
this.refFrameAString = frame;
}
/**
* Get the reference frame B specifier as it appeared in the file.
* @return the frame name as it appeared in the file (B).
*/
@Override
public String getRefFrameBString() {
return this.refFrameBString;
}
......@@ -248,10 +287,7 @@ public class AEMFile extends ADMFile {
this.rateFrameString = frame;
}
/**
* Get the rotation direction of the attitude.
* @return the rotation direction of the attitude
*/
@Override
public String getAttitudeDirection() {
return attitudeDir;
}
......@@ -264,10 +300,7 @@ public class AEMFile extends ADMFile {
this.attitudeDir = direction;
}
/**
* Get the format of the data lines in the message.
* @return the format of the data lines in the message
*/
@Override
public String getAttitudeType() {
return attitudeType;
}
......@@ -280,10 +313,7 @@ public class AEMFile extends ADMFile {
this.attitudeType = type;
}
/**
* Get the flag for the placement of the quaternion QC in the attitude data.
* @return true if QC is the first element in the attitude data
*/
@Override
public boolean isFirst() {
return isFirst;
}
......@@ -312,19 +342,12 @@ public class AEMFile extends ADMFile {
this.eulerRotSeq = eulerRotSeq;
}
/**
* Get the time scale for this data segment.
* @return the time scale identifier, as specified in the file, or
* {@code null} if the data file does not specify a time scale.
*/
@Override
public String getTimeScaleString() {
return metaData.getTimeSystem().toString();
}
/**
* Get the time scale for this data segment.
* @return the time scale for this data. Never {@code null}.
*/
@Override
public TimeScale getTimeScale() {
return metaData.getTimeScale();
}
......@@ -393,10 +416,7 @@ public class AEMFile extends ADMFile {
this.useableStopTime = useableStopTime;
}
/**
* Get the start date of this attitude data segment.
* @return attitude data segment start date.
*/
@Override
public AbsoluteDate getStart() {
// usable start time overrides start time if it is set
final AbsoluteDate start = this.getUseableStartTime();
......@@ -407,10 +427,7 @@ public class AEMFile extends ADMFile {
}
}
/**
* Get the end date of this attitude data segment.
* @return attitude data segment end date.
*/
@Override
public AbsoluteDate getStop() {
// useable stop time overrides stop time if it is set
final AbsoluteDate stop = this.getUseableStopTime();
......@@ -421,10 +438,7 @@ public class AEMFile extends ADMFile {
}
}
/**
* Get the interpolation method to be used.
* @return the interpolation method
*/
@Override
public String getInterpolationMethod() {
return interpolationMethod;
}
......@@ -453,6 +467,12 @@ public class AEMFile extends ADMFile {
this.interpolationDegree = interpolationDegree;
}
@Override
public int getInterpolationSamples() {
// From the standard it is not entirely clear how to interpret the degree.
return getInterpolationDegree() + 1;
}
/** Get the attitude data lines comment.
* @return the comment
*/
......@@ -467,10 +487,7 @@ public class AEMFile extends ADMFile {
this.attitudeDataLinesComment = new ArrayList<String>(ephemeridesDataLinesComment);
}
/**
* Get the rotation order for Euler angles.
* @return rotation order
*/
@Override
public RotationOrder getRotationOrder() {
return rotationOrder;
}
......@@ -485,47 +502,5 @@ public class AEMFile extends ADMFile {
}
/** AEM ephemeris blocks for a single satellite. */
public static class AemSatelliteEphemeris {
/** The attitude ephemeris data for the satellite. */
private final List<AttitudeEphemeridesBlock> blocks;
/**
* Create a container for the set of ephemeris blocks in the file that pertain to
* a single satellite.
* @param blocks containing ephemeris data for the satellite.
*/
public AemSatelliteEphemeris(final List<AttitudeEphemeridesBlock> blocks) {
this.blocks = blocks;
}
/**
* Get the segments of the attitude ephemeris.
* <p> Ephemeris segments are typically used to split an attitude ephemeris around
* discontinuous events, such as maneuvers.
* @return the segments contained in the attitude ephemeris file for this satellite.
*/
public List<AttitudeEphemeridesBlock> getSegments() {
return Collections.unmodifiableList(blocks);
}
/**
* Get the start date of the attitude ephemeris.
* @return attitude ephemeris start date.
*/
public AbsoluteDate getStart() {
return blocks.get(0).getStart();
}
/**
* Get the end date of the attitude ephemeris.
* @return attitude ephemeris end date.
*/
public AbsoluteDate getStop() {
return blocks.get(blocks.size() - 1).getStop();
}
}
}
/* Contributed in the public domain.
* 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.files.general;
import java.util.List;
import java.util.Map;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.utils.TimeStampedAngularCoordinates;
/**
* An interface for accessing the data stored in an attitude ephemeris file.
*
* <p> An {@link AttitudeEphemerisFile} consists of one or more satellites each with a unique ID
* within the file. The ephemeris for each satellite consists of one or more segments.
*
* <p> Some attitude ephemeris file formats may supply additional information that is not available
* via this interface. In those cases it is recommended that the parser return a subclass
* of this interface to provide access to the additional information.
*
* @author Raphaël Fermé
* @see SatelliteAttitudeEphemeris
* @see AttitudeEphemerisSegment
* @since 10.3
*/
public interface AttitudeEphemerisFile {
/**
* Get the loaded ephemeris for each satellite in the file.
*
* @return a map from the satellite's ID to the information about that satellite
* contained in the file.
*/
Map<String, ? extends SatelliteAttitudeEphemeris> getSatellites();
/**
* Contains the information about a single satellite from an {@link AttitudeEphemerisFile}.
*
* <p> A satellite ephemeris consists of one or more {@link AttitudeEphemerisSegment}.
* Segments are typically used to split up an ephemeris at discontinuous events, such
* as a maneuver.
*
* @author Raphaël Fermé
* @see AttitudeEphemerisFile
* @see AttitudephemerisSegment
* @since 10.3
*/
interface SatelliteAttitudeEphemeris {
/**
* Get the satellite ID. The satellite ID is unique only within the same ephemeris
* file.
*
* @return the satellite's ID, never {@code null}.
*/
String getId();
/**
* Get the segments of the attitude ephemeris.
*
* <p> Attitude ephemeris segments are typically used to split an ephemeris around
* discontinuous events, such as maneuvers.
*
* @return the segments contained in the attitude ephemeris file for this satellite.
*/
List<? extends AttitudeEphemerisSegment> getSegments();
/**
* Get the start date of the ephemeris.
*
* @return ephemeris start date.
*/
AbsoluteDate getStart();
/**
* Get the end date of the ephemeris.
*
* @return ephemeris end date.
*/
AbsoluteDate getStop();
}
/**
* A segment of an attitude ephemeris for a satellite.
*
* <p> Segments are typically used to split an ephemeris around discontinuous events
* such as maneuvers.
*
* @author Raphaël Fermé
* @see AttitudeEphemerisFile
* @see SatelliteAttitudeEphemeris
* @since 10.3
*/
interface AttitudeEphemerisSegment {
/**
* Get an unmodifiable list of attitude data lines.
*
* @return a list of attitude data
*/
List<? extends TimeStampedAngularCoordinates> getAngularCoordinates();
/**
* Get the name of the center of the coordinate system the ephemeris is provided
* in. This may be a natural origin, such as the center of the Earth, another
* satellite, etc.
*
* @return the name of the frame center
*/
String getFrameCenterString();
/**
* Get the reference frame A specifier as it appeared in the file.
*
* @return the frame name as it appeared in the file (A).
*/
String getRefFrameAString();
/**
* Get the reference frame B specifier as it appeared in the file.
*
* @return the frame name as it appeared in the file (B).
*/
String getRefFrameBString();
/**
* Get the rotation direction of the attitude.
*
* @return the rotation direction of the attitude
*/
String getAttitudeDirection();
/**
* Get the format of the data lines in the message.
*
* @return the format of the data lines in the message
*/
String getAttitudeType();
/**
* Get the flag for the placement of the quaternion QC in the attitude data.
*
* @return true if QC is the first element in the attitude data
*/
boolean isFirst();
/**
* Get the rotation order for Euler angles.
*
* @return rotation order
*/
RotationOrder getRotationOrder();
/**
* Get the time scale for this ephemeris segment.
*
* @return the time scale identifier, as specified in the ephemeris file, or
* {@code null} if the ephemeris file does not specify a time scale.
*/
String getTimeScaleString();
/**
* Get the time scale for this ephemeris segment.
*
* @return the time scale for this segment. Never {@code null}.
*/
TimeScale getTimeScale();
/**
* Get the start date of this ephemeris segment.
*
* @return ephemeris segment start date.
*/
AbsoluteDate getStart();
/**
* Get the end date of this ephemeris segment.
*
* @return ephemeris segment end date.
*/
AbsoluteDate getStop();
/**
* Get the interpolation method to be used.
*
* @return the interpolation method
*/
String getInterpolationMethod();
/**
* Get the number of samples to use in interpolation.
*
* @return the number of points to use for interpolation.
*/
int getInterpolationSamples();
}
}
......@@ -34,7 +34,7 @@ import org.orekit.utils.TimeStampedPVCoordinates;
* An interface for accessing the data stored in an ephemeris file and using the data to
* create a working {@link org.orekit.propagation.Propagator Propagator}.
*
* <p> An {@link EphemerisFile} consists of one or more satellites each an ID unique
* <p> An {@link EphemerisFile} consists of one or more satellites each with a unique ID
* within the file. The ephemeris for each satellite consists of one or more segments.
*
* <p> Some ephemeris file formats may supply additional information that is not available
......@@ -166,7 +166,7 @@ public interface EphemerisFile {
/**
* Get the name of the center of the coordinate system the ephemeris is provided
* in. This may be a natural origin, such as the center of the Earth, another
* in. This may be a natural origin, such as the center of the Earth, another
* satellite, etc.
*
* @return the name of the frame center
......
......@@ -18,14 +18,18 @@
* This package provides interfaces for orbit file representations and corresponding
* parsers.
*
* <p> {@link org.orekit.files.general.EphemerisFile} and {@link
* org.orekit.files.general.EphemerisFileParser} provide a standardized interface for
* accessing the date in ephemeris files. Each ephemeris file can have data for one ore
* more satellites and the ephemeris for each satellite can have one or more segments.
* Each ephemeris segment is interpolated independently so ephemeris segments are
* commonly used for discontinuous events, such as maneuvers. Each specific implementation
* provides access to additional information in the file by providing specialized return
* types with extra getters for the information unique to that file type.
* <p> {@link org.orekit.files.general.EphemerisFile EphemerisFile}, {@link
* org.orekit.files.general.EphemerisFileParser EphemerisFileParser} and {@link
* org.orekit.files.general.EphemerisFileWriter EphemerisFileWriter} for orbit ephemeris and
* {@link org.orekit.files.general.AttitudeEphemerisFile AttitudeEphemerisFile}, {@link
* org.orekit.files.general.AttitudeEphemerisFileParser AttitudeEphemerisFileParser} and {@link
* org.orekit.files.general.AttitudeEphemerisFileWriter AttitudeEphemerisFileWriter} for attitude
* ephemeris provide a standardized interface for accessing and writing the data in ephemeris files.
* Each ephemeris file can have data for one or more satellites and the ephemeris for each satellite
* can have one or more segments. Each ephemeris segment is interpolated independently so ephemeris
* segments are commonly used for discontinuous events, such as maneuvers. Each specific
* implementation provides access to additional information in the file by providing specialized
* return types with extra getters for the information unique to that file type.
*
* <p> For example to create a propagator from an OEM file one can use:
*
......
......@@ -19,7 +19,8 @@
*
* <p>The interfaces for ephemeris file parsers and writers are in the {@link org.orekit.files.general}
* package. Specifically, see {@link org.orekit.files.general.EphemerisFile
* EphemerisFile}. Each format is handled by a separate sub-package: {@link org.orekit.files.ccsds}, {@link
* EphemerisFile} and {@link org.orekit.files.general.AttitudeEphemerisFile
* AttitudeEphemerisFile}. Each format is handled by a separate sub-package: {@link org.orekit.files.ccsds}, {@link
* org.orekit.files.sp3}.</p>
*/
package org.orekit.files;
......@@ -172,8 +172,9 @@ public class AEMWriterTest {
generatedAemFile.getAttitudeBlocks().get(0).getMetaData().getObjectID());
}
@Deprecated
@Test
public void testMultisatelliteFile() throws IOException {
public void testMultisatelliteFileDeprecated() throws IOException {
final String id1 = "ID1";
final String id2 = "ID2";
AEMFile file = new StandInEphemerisFile();
......@@ -196,6 +197,30 @@ public class AEMWriterTest {
writer2.write(tempAEMFilePath, file);
}
@Test
public void testMultisatelliteFile() throws IOException {
final String id1 = "ID1";
final String id2 = "ID2";
AEMFile file = new StandInEphemerisFile();
file.getSatellites().put(id1, new StandInSatelliteEphemeris(id1, new ArrayList<>()));
file.getSatellites().put(id2, new StandInSatelliteEphemeris(id2, new ArrayList<>()));
String tempAEMFilePath = tempFolder.newFile("TestAEMMultisatellite-1.aem").toString();
AEMWriter writer1 = new AEMWriter();
try {
writer1.write(tempAEMFilePath, file);
fail("Should have thrown OrekitIllegalArgumentException due to multiple satellites");
} catch (OrekitIllegalArgumentException e) {