Commit 43a4ad08 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Merge branch 'issue-474' into develop

parents ca583c19 88052146
Pipeline #1061 passed with stages
in 30 minutes and 44 seconds
......@@ -169,6 +169,7 @@ public enum OrekitMessages implements Localizable {
CCSDS_UNKNOWN_GM("the central body gravitational coefficient cannot be retrieved from the ODM"),
CCSDS_UNKNOWN_SPACECRAFT_MASS("there is no spacecraft mass associated with this ODM file"),
CCSDS_UNKNOWN_CONVENTIONS("no IERS conventions have been set before parsing"),
CCSDS_UNKNOWN_SPIN_AXIS("no spin axis direction has been set before parsing"),
CCSDS_INVALID_FRAME("frame {0} is not valid in this CCSDS file context"),
CCSDS_INCONSISTENT_TIME_SYSTEMS("inconsistent time systems: {0} ≠ {1}"),
CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED(
......
......@@ -16,6 +16,7 @@
*/
package org.orekit.files.ccsds.ndm;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.data.DataContext;
import org.orekit.files.ccsds.ndm.adm.aem.AemParser;
import org.orekit.files.ccsds.ndm.adm.apm.ApmParser;
......@@ -41,34 +42,40 @@ public abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
/** Reference date for Mission Elapsed Time or Mission Relative Time time systems. */
private final AbsoluteDate missionReferenceDate;
/** Spin axis in spacecraft body frame. */
private final Vector3D spinAxis;
/**
* Complete constructor.
* @param conventions IERS Conventions
* @param dataContext used to retrieve frames, time scales, etc.
* @param missionReferenceDate reference date for Mission Elapsed Time or Mission Relative Time time systems
* @param spinAxis spin axis in spacecraft body frame
*/
protected AbstractBuilder(final IERSConventions conventions, final DataContext dataContext,
final AbsoluteDate missionReferenceDate) {
final AbsoluteDate missionReferenceDate, final Vector3D spinAxis) {
this.conventions = conventions;
this.dataContext = dataContext;
this.missionReferenceDate = missionReferenceDate;
this.spinAxis = spinAxis;
}
/** Build an instance.
* @param newConventions IERS Conventions
* @param newDataContext used to retrieve frames, time scales, etc.
* @param newMissionReferenceDate reference date for Mission Elapsed Time or Mission Relative Time time systems
* @param newSpinAxis spin axis in spacecraft body frame
* @return new instance
*/
protected abstract T create(IERSConventions newConventions, DataContext newDataContext,
AbsoluteDate newMissionReferenceDate);
AbsoluteDate newMissionReferenceDate, Vector3D newSpinAxis);
/** Set up IERS conventions.
* @param newConventions IERS Conventions
* @return a new builder with updated configuration (the instance is not changed)
*/
public T withConventions(final IERSConventions newConventions) {
return create(newConventions, getDataContext(), getMissionReferenceDate());
return create(newConventions, getDataContext(), getMissionReferenceDate(), getSpinAxis());
}
/** Get the IERS conventions.
......@@ -83,7 +90,7 @@ public abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
* @return a new builder with updated configuration (the instance is not changed)
*/
public T withDataContext(final DataContext newDataContext) {
return create(getConventions(), newDataContext, getMissionReferenceDate());
return create(getConventions(), newDataContext, getMissionReferenceDate(), getSpinAxis());
}
/** Get the data context.
......@@ -104,7 +111,7 @@ public abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
* @return a new builder with updated configuration (the instance is not changed)
*/
public T withMissionReferenceDate(final AbsoluteDate newMissionReferenceDate) {
return create(getConventions(), getDataContext(), newMissionReferenceDate);
return create(getConventions(), getDataContext(), newMissionReferenceDate, getSpinAxis());
}
/** Get the mission reference date or Mission Elapsed Time or Mission Relative Time time systems.
......@@ -114,4 +121,23 @@ public abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
return missionReferenceDate;
}
/** Set up spin axis direction.
* <p>
* The spin axis is used only by {@link AemParser} and {@link ApmParser}.
* </p>
* @param newSpinAxis spin axis in spacecraft body frame
* @return a new builder with updated configuration (the instance is not changed)
*/
public T withSpinAxis(final Vector3D newSpinAxis) {
return create(getConventions(), getDataContext(), getMissionReferenceDate(), newSpinAxis);
}
/**
* Get spin axis in spacecraft body frame.
* @return spin axis
*/
public Vector3D getSpinAxis() {
return spinAxis;
}
}
......@@ -16,6 +16,7 @@
*/
package org.orekit.files.ccsds.ndm;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.annotation.DefaultDataContext;
import org.orekit.data.DataContext;
import org.orekit.files.ccsds.ndm.adm.aem.AemParser;
......@@ -95,7 +96,7 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @param dataContext data context used to retrieve frames, time scales, etc.
*/
public ParserBuilder(final DataContext dataContext) {
this(IERSConventions.IERS_2010, dataContext, null, true, Double.NaN,
this(IERSConventions.IERS_2010, dataContext, null, null, true, Double.NaN,
Double.NaN, 1, ParsedUnitsBehavior.CONVERT_COMPATIBLE);
}
......@@ -103,6 +104,7 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @param conventions IERS Conventions
* @param dataContext used to retrieve frames, time scales, etc.
* @param missionReferenceDate reference date for Mission Elapsed Time or Mission Relative Time time systems
* @param spinAxis spin axis in spacecraft body frame
* @param simpleEOP if true, tidal effects are ignored when interpolating EOP
* @param mu gravitational coefficient
* @param defaultMass default mass
......@@ -110,11 +112,11 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @param parsedUnitsBehavior behavior to adopt for handling parsed units
*/
private ParserBuilder(final IERSConventions conventions, final DataContext dataContext,
final AbsoluteDate missionReferenceDate, final boolean simpleEOP,
final double mu, final double defaultMass,
final AbsoluteDate missionReferenceDate, final Vector3D spinAxis,
final boolean simpleEOP, final double mu, final double defaultMass,
final int defaultInterpolationDegree,
final ParsedUnitsBehavior parsedUnitsBehavior) {
super(conventions, dataContext, missionReferenceDate);
super(conventions, dataContext, missionReferenceDate, spinAxis);
this.simpleEOP = simpleEOP;
this.mu = mu;
this.defaultMass = defaultMass;
......@@ -125,8 +127,8 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
/** {@inheritDoc} */
@Override
protected ParserBuilder create(final IERSConventions newConventions, final DataContext newDataContext,
final AbsoluteDate newMissionReferenceDate) {
return new ParserBuilder(newConventions, newDataContext, newMissionReferenceDate,
final AbsoluteDate newMissionReferenceDate, final Vector3D spinAxis) {
return new ParserBuilder(newConventions, newDataContext, newMissionReferenceDate, spinAxis,
simpleEOP, mu, defaultMass, defaultInterpolationDegree,
parsedUnitsBehavior);
}
......@@ -136,7 +138,8 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @return a new builder with updated configuration (the instance is not changed)
*/
public ParserBuilder withSimpleEOP(final boolean newSimpleEOP) {
return new ParserBuilder(getConventions(), getDataContext(), getMissionReferenceDate(),
return new ParserBuilder(getConventions(), getDataContext(),
getMissionReferenceDate(), getSpinAxis(),
newSimpleEOP, getMu(), getDefaultMass(),
getDefaultInterpolationDegree(), getParsedUnitsBehavior());
}
......@@ -153,7 +156,8 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @return a new builder with updated configuration (the instance is not changed)
*/
public ParserBuilder withMu(final double newMu) {
return new ParserBuilder(getConventions(), getDataContext(), getMissionReferenceDate(),
return new ParserBuilder(getConventions(), getDataContext(),
getMissionReferenceDate(), getSpinAxis(),
isSimpleEOP(), newMu, getDefaultMass(),
getDefaultInterpolationDegree(), getParsedUnitsBehavior());
}
......@@ -173,7 +177,8 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @return a new builder with updated configuration (the instance is not changed)
*/
public ParserBuilder withDefaultMass(final double newDefaultMass) {
return new ParserBuilder(getConventions(), getDataContext(), getMissionReferenceDate(),
return new ParserBuilder(getConventions(), getDataContext(),
getMissionReferenceDate(), getSpinAxis(),
isSimpleEOP(), getMu(), newDefaultMass,
getDefaultInterpolationDegree(), getParsedUnitsBehavior());
}
......@@ -194,7 +199,8 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @return a new builder with updated configuration (the instance is not changed)
*/
public ParserBuilder withDefaultInterpolationDegree(final int newDefaultInterpolationDegree) {
return new ParserBuilder(getConventions(), getDataContext(), getMissionReferenceDate(),
return new ParserBuilder(getConventions(), getDataContext(),
getMissionReferenceDate(), getSpinAxis(),
isSimpleEOP(), getMu(), getDefaultMass(),
newDefaultInterpolationDegree, getParsedUnitsBehavior());
}
......@@ -211,7 +217,8 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
* @return a new builder with updated configuration (the instance is not changed)
*/
public ParserBuilder withParsedUnitsBehavior(final ParsedUnitsBehavior newParsedUnitsBehavior) {
return new ParserBuilder(getConventions(), getDataContext(), getMissionReferenceDate(),
return new ParserBuilder(getConventions(), getDataContext(),
getMissionReferenceDate(), getSpinAxis(),
isSimpleEOP(), getMu(), getDefaultMass(),
getDefaultInterpolationDegree(), newParsedUnitsBehavior);
}
......@@ -259,7 +266,7 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
*/
public ApmParser buildApmParser() {
return new ApmParser(getConventions(), isSimpleEOP(), getDataContext(),
getMissionReferenceDate(), getParsedUnitsBehavior());
getMissionReferenceDate(), getSpinAxis(), getParsedUnitsBehavior());
}
/** Build a parser for {@link org.orekit.files.ccsds.ndm.adm.aem.AemFile Attitude Ephemeris Messages}.
......@@ -267,7 +274,7 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
*/
public AemParser buildAemParser() {
return new AemParser(getConventions(), isSimpleEOP(), getDataContext(), getMissionReferenceDate(),
getDefaultInterpolationDegree(), getParsedUnitsBehavior());
getDefaultInterpolationDegree(), getSpinAxis(), getParsedUnitsBehavior());
}
/** Build a parser for {@link org.orekit.files.ccsds.ndm.tdm.TdmFile Tracking Data Messages}.
......
......@@ -16,6 +16,7 @@
*/
package org.orekit.files.ccsds.ndm;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.annotation.DefaultDataContext;
import org.orekit.data.DataContext;
import org.orekit.files.ccsds.ndm.adm.aem.AemWriter;
......@@ -70,24 +71,25 @@ public class WriterBuilder extends AbstractBuilder<WriterBuilder> {
* @param dataContext data context used to retrieve frames, time scales, etc.
*/
public WriterBuilder(final DataContext dataContext) {
this(IERSConventions.IERS_2010, dataContext, null);
this(IERSConventions.IERS_2010, dataContext, null, null);
}
/** Complete constructor.
* @param conventions IERS Conventions
* @param dataContext used to retrieve frames, time scales, etc.
* @param missionReferenceDate reference date for Mission Elapsed Time or Mission Relative Time time systems
* @param spinAxis spin axis in spacecraft body frame
*/
private WriterBuilder(final IERSConventions conventions, final DataContext dataContext,
final AbsoluteDate missionReferenceDate) {
super(conventions, dataContext, missionReferenceDate);
final AbsoluteDate missionReferenceDate, final Vector3D spinAxis) {
super(conventions, dataContext, missionReferenceDate, spinAxis);
}
/** {@inheritDoc} */
@Override
protected WriterBuilder create(final IERSConventions newConventions, final DataContext newDataContext,
final AbsoluteDate newMissionReferenceDate) {
return new WriterBuilder(newConventions, newDataContext, newMissionReferenceDate);
final AbsoluteDate newMissionReferenceDate, final Vector3D newSpinAxis) {
return new WriterBuilder(newConventions, newDataContext, newMissionReferenceDate, newSpinAxis);
}
/** Build a writer for {@link org.orekit.files.ccsds.ndm.odm.opm.OpmFile Orbit Parameters Messages}.
......@@ -122,14 +124,14 @@ public class WriterBuilder extends AbstractBuilder<WriterBuilder> {
* @return a new writer
*/
public ApmWriter buildApmWriter() {
return new ApmWriter(getConventions(), getDataContext(), getMissionReferenceDate());
return new ApmWriter(getConventions(), getDataContext(), getMissionReferenceDate(), getSpinAxis());
}
/** Build a writer for {@link org.orekit.files.ccsds.ndm.adm.aem.AemFile Attitude Ephemeris Messages}.
* @return a new writer
*/
public AemWriter buildAemWriter() {
return new AemWriter(getConventions(), getDataContext(), getMissionReferenceDate());
return new AemWriter(getConventions(), getDataContext(), getMissionReferenceDate(), getSpinAxis());
}
/** Build a writer for {@link org.orekit.files.ccsds.ndm.tdm.TdmFile Tracking Data Messages}.
......
......@@ -19,6 +19,7 @@ package org.orekit.files.ccsds.ndm.adm;
import java.util.Map;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.data.DataContext;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
......@@ -62,6 +63,9 @@ public abstract class AdmParser<T extends NdmFile<?, ?>, P extends AbstractMessa
/** Reference date for Mission Elapsed Time or Mission Relative Time time systems. */
private final AbsoluteDate missionReferenceDate;
/** Spin axis in spacecraft body frame. */
private final Vector3D spinAxis;
/** Complete constructor.
* @param root root element for XML files
* @param formatVersionKey key for format version
......@@ -70,13 +74,17 @@ public abstract class AdmParser<T extends NdmFile<?, ?>, P extends AbstractMessa
* @param dataContext used to retrieve frames, time scales, etc.
* @param missionReferenceDate reference date for Mission Elapsed Time or Mission Relative Time time systems
* (may be null if time system is absolute)
* @param spinAxis spin axis in spacecraft body frame
* (may be null if attitude type is neither spin nor spin/nutation)
* @param parsedUnitsBehavior behavior to adopt for handling parsed units
*/
protected AdmParser(final String root, final String formatVersionKey, final IERSConventions conventions,
final boolean simpleEOP, final DataContext dataContext,
final AbsoluteDate missionReferenceDate, final ParsedUnitsBehavior parsedUnitsBehavior) {
final AbsoluteDate missionReferenceDate, final Vector3D spinAxis,
final ParsedUnitsBehavior parsedUnitsBehavior) {
super(root, formatVersionKey, conventions, simpleEOP, dataContext, parsedUnitsBehavior);
this.missionReferenceDate = missionReferenceDate;
this.spinAxis = spinAxis;
}
/** {@inheritDoc} */
......@@ -102,6 +110,14 @@ public abstract class AdmParser<T extends NdmFile<?, ?>, P extends AbstractMessa
return missionReferenceDate;
}
/**
* Get spin axis in spacecraft body frame.
* @return spin axis
*/
public Vector3D getSpinAxis() {
return spinAxis;
}
/** Process a CCSDS Euler angles sequence as a {@link RotationOrder}.
* @param sequence Euler angles sequence token
* @param consumer consumer of the rotation order
......
......@@ -48,8 +48,8 @@ public enum AttitudeType {
/** {@inheritDoc} */
@Override
public String[] createDataFields(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final TimeStampedAngularCoordinates coordinates) {
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final Vector3D spinAxis, final TimeStampedAngularCoordinates coordinates) {
// Initialize the array of attitude data
final double[] data = new double[4];
......@@ -77,8 +77,8 @@ public enum AttitudeType {
final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence,
final boolean isSpacecraftBodyRate,
final AbsoluteDate date,
final double...components) {
final Vector3D spinAxis,
final AbsoluteDate date, final double...components) {
Rotation rotation = isFirst ?
new Rotation(components[0], components[1], components[2], components[3], true) :
......@@ -102,8 +102,8 @@ public enum AttitudeType {
/** {@inheritDoc} */
@Override
public String[] createDataFields(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final TimeStampedAngularCoordinates coordinates) {
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final Vector3D spinAxis, final TimeStampedAngularCoordinates coordinates) {
// Initialize the array of attitude data
final double[] data = new double[8];
......@@ -138,8 +138,8 @@ public enum AttitudeType {
final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence,
final boolean isSpacecraftBodyRate,
final AbsoluteDate date,
final double...components) {
final Vector3D spinAxis,
final AbsoluteDate date, final double...components) {
FieldRotation<UnivariateDerivative1> rotation =
isFirst ?
new FieldRotation<>(new UnivariateDerivative1(components[0], components[4]),
......@@ -170,8 +170,8 @@ public enum AttitudeType {
/** {@inheritDoc} */
@Override
public String[] createDataFields(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final TimeStampedAngularCoordinates coordinates) {
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final Vector3D spinAxis, final TimeStampedAngularCoordinates coordinates) {
// Initialize the array of attitude data
final double[] data = new double[7];
......@@ -202,8 +202,8 @@ public enum AttitudeType {
final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence,
final boolean isSpacecraftBodyRate,
final AbsoluteDate date,
final double...components) {
final Vector3D spinAxis,
final AbsoluteDate date, final double...components) {
// Build the needed objects
final Rotation rotation = isFirst ?
new Rotation(components[0], components[1], components[2], components[3], true) :
......@@ -230,8 +230,8 @@ public enum AttitudeType {
/** {@inheritDoc} */
@Override
public String[] createDataFields(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final TimeStampedAngularCoordinates coordinates) {
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final Vector3D spinAxis, final TimeStampedAngularCoordinates coordinates) {
// Attitude
Rotation rotation = coordinates.getRotation();
......@@ -252,8 +252,8 @@ public enum AttitudeType {
final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence,
final boolean isSpacecraftBodyRate,
final AbsoluteDate date,
final double...components) {
final Vector3D spinAxis,
final AbsoluteDate date, final double...components) {
// Build the needed objects
Rotation rotation = new Rotation(eulerRotSequence, RotationConvention.FRAME_TRANSFORM,
......@@ -276,8 +276,8 @@ public enum AttitudeType {
/** {@inheritDoc} */
@Override
public String[] createDataFields(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final TimeStampedAngularCoordinates coordinates) {
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final Vector3D spinAxis, final TimeStampedAngularCoordinates coordinates) {
// Initialize the array of attitude data
final double[] data = new double[6];
......@@ -305,8 +305,8 @@ public enum AttitudeType {
final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence,
final boolean isSpacecraftBodyRate,
final AbsoluteDate date,
final double...components) {
final Vector3D spinAxis,
final AbsoluteDate date, final double...components) {
// Build the needed objects
final Rotation rotation = new Rotation(eulerRotSequence,
......@@ -328,19 +328,63 @@ public enum AttitudeType {
},
/** Spin. */
/** Spin.
* <p>
* CCSDS ADM standard is ambiguous about spin phase angle definition: it does not states what
* are the start and end points of this phase, it only specifies the phase angle is counted
* about the spin axis. This implementation arbitrarily assumes the following:
* </p>
* <ul>
* <li>the spin axis is known in spacecraft body frame, and given in an ICD, so it is
* registered in {@link org.orekit.files.ccsds.ndm.ParserBuilder#withSpinAxis(Vector3D)
* ParserBuilder.withSpinAxis(Vector3D)}</li>
* <li>the ADM file defines the spin axis in external frame</li>
* <li>{@code SPIN_DIR} is therefore ignored</li>
* <li>the attitude is the composition of two rotations:
* <ol>
* <li>the rotation with smallest angle that maps spin axis in external frame
* with angular coordinates {@code (SPIN_ALPHA, SPIN_DELTA)} to the spin
* axis in spacecraft frame</li>
* <li>a rotation about spin axis with angle {@code SPIN_ANGLE} and rate
* {@code SPIN_ANGLE_VEL}</li>
* </ol>
* </li>
* </ul>
*/
SPIN("SPIN", AngularDerivativesFilter.USE_RR,
Unit.DEGREE, Unit.DEGREE, Unit.DEGREE, Units.DEG_PER_S) {
/** {@inheritDoc} */
@Override
public String[] createDataFields(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final TimeStampedAngularCoordinates coordinates) {
// Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
// are optional in CCSDS AEM format. Support for this attitude type is not implemented
// yet in Orekit.
throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, name());
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final Vector3D spinAxis, final TimeStampedAngularCoordinates coordinates) {
// Initialize the array of attitude data
final double[] data = new double[4];
// compute spin as separate direction and rate
// the fixed spinAxis is used only to get the correct sign, the
// pointing direction will really be extracted from the coordinates
final Rotation rotation = coordinates.getRotation();
final Vector3D rate = coordinates.getRotationRate();
final boolean reverse = Vector3D.dotProduct(spinAxis, rate) < 0;
// Attitude
final Vector3D spinSpacecraft = reverse ? rate.negate() : rate;
final Vector3D spinExt = rotation.applyInverseTo(spinSpacecraft);
final Rotation phase = rotation.applyTo(new Rotation(spinSpacecraft, spinExt));
// Fill the array
data[0] = spinExt.getAlpha();
data[1] = spinExt.getDelta();
data[2] = Vector3D.dotProduct(spinSpacecraft, phase.getAxis(RotationConvention.FRAME_TRANSFORM)) < 0 ?
-phase.getAngle() : phase.getAngle();
data[3] = reverse ? -rate.getNorm() : rate.getNorm();
// Convert units and format
return EULER_ANGLE_RATE.formatData(data);
}
/** {@inheritDoc} */
......@@ -349,12 +393,21 @@ public enum AttitudeType {
final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence,
final boolean isSpacecraftBodyRate,
final AbsoluteDate date,
final double...components) {
// Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
// are optional in CCSDS AEM format. Support for this attitude type is not implemented
// yet in Orekit.
throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, name());
final Vector3D spinAxis,
final AbsoluteDate date, final double...components) {
// Build the needed objects
if (spinAxis == null) {
throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_SPIN_AXIS);
}
final Rotation rotation = new Rotation(spinAxis, components[2], RotationConvention.FRAME_TRANSFORM).
compose(new Rotation(new Vector3D(components[0], components[1]), spinAxis),
RotationConvention.VECTOR_OPERATOR);
final Vector3D rotationRate = new Vector3D(components[3] / spinAxis.getNorm(), spinAxis);
// Return
return new TimeStampedAngularCoordinates(date, rotation, rotationRate, Vector3D.ZERO);
}
},
......@@ -367,8 +420,8 @@ public enum AttitudeType {
/** {@inheritDoc} */
@Override
public String[] createDataFields(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final TimeStampedAngularCoordinates coordinates) {
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final Vector3D spinAxis, final TimeStampedAngularCoordinates coordinates) {
// Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
// are optional in CCSDS AEM format. Support for this attitude type is not implemented
// yet in Orekit.
......@@ -381,8 +434,8 @@ public enum AttitudeType {
final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence,
final boolean isSpacecraftBodyRate,
final AbsoluteDate date,
final double...components) {
final Vector3D spinAxis,
final AbsoluteDate date, final double...components) {
// Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
// are optional in CCSDS AEM format. Support for this attitude type is not implemented
// yet in Orekit.
......@@ -437,13 +490,14 @@ public enum AttitudeType {
* @param isExternal2SpacecraftBody true attitude is from external frame to spacecraft body frame
* @param eulerRotSequence sequance of Euler angles
* @param isSpacecraftBodyRate if true Euler rates are specified in spacecraft body frame
* @param spinAxis spin axis in spacecraft body frame
* @param attitude angular coordinates, using {@link Attitude Attitude} convention
* (i.e. from inertial frame to spacecraft frame)
* @return the attitude data in CCSDS units
*/
public abstract String[] createDataFields(boolean isFirst, boolean isExternal2SpacecraftBody,
RotationOrder eulerRotSequence, boolean isSpacecraftBodyRate,
TimeStampedAngularCoordinates attitude);
Vector3D spinAxis, TimeStampedAngularCoordinates attitude);
/**
* Get the angular coordinates corresponding to the attitude data.
......@@ -461,8 +515,7 @@ public enum AttitudeType {
*/
public TimeStampedAngularCoordinates parse(final boolean isFirst, final boolean isExternal2SpacecraftBody,
final RotationOrder eulerRotSequence, final boolean isSpacecraftBodyRate,
final ContextBinding context,
final String[] fields) {
final ContextBinding context, final String[] fields) {
// parse the text fields
final AbsoluteDate date = context.getTimeSystem().getConverter(context).parse(fields[0]);
......@@ -473,7 +526,7 @@ public enum AttitudeType {