AttitudeEndoints.java
- /* Copyright 2002-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.files.ccsds.ndm.adm;
- import org.hipparchus.Field;
- import org.hipparchus.CalculusFieldElement;
- import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
- import org.hipparchus.geometry.euclidean.threed.Vector3D;
- import org.orekit.attitudes.Attitude;
- import org.orekit.attitudes.AttitudeBuilder;
- import org.orekit.attitudes.FieldAttitude;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.files.ccsds.definitions.FrameFacade;
- import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
- import org.orekit.frames.Frame;
- import org.orekit.utils.AngularCoordinates;
- import org.orekit.utils.FieldAngularCoordinates;
- import org.orekit.utils.FieldPVCoordinates;
- import org.orekit.utils.FieldPVCoordinatesProvider;
- import org.orekit.utils.PVCoordinates;
- import org.orekit.utils.PVCoordinatesProvider;
- import org.orekit.utils.TimeStampedAngularCoordinates;
- import org.orekit.utils.TimeStampedFieldAngularCoordinates;
- /** Endpoints for attitude definition.
- * <p>
- * This class provides a bridge between two different views of attitude definition.
- * In both views, there is an external frame, based on either celestial body or orbit-relative
- * and there is a spacecraft body frame.
- * <ul>
- * <li>CCSDS ADM view: frames are labeled as A and B but nothing tells which is which
- * and attitude can be defined in any direction</li>
- * <li>{@link Attitude Orekit attitude} view: attitude is always from external to
- * spacecraft body</li>
- * </ul>
- * @author Luc Maisonobe
- * @since 11.0
- */
- public class AttitudeEndoints implements AttitudeBuilder {
- /** Constant for A → B diraction. */
- public static final String A2B = "A2B";
- /** Constant for A ← B direction. */
- public static final String B2A = "B2A";
- /** Frame A. */
- private FrameFacade frameA;
- /** Frame B. */
- private FrameFacade frameB;
- /** Flag for frames direction. */
- private Boolean a2b;
- /** Complain if a field is null.
- * @param field field to check
- * @param key key associated with the field
- */
- private void checkNotNull(final Object field, final Enum<?> key) {
- if (field == null) {
- throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, key.name());
- }
- }
- /** Check external frame is properly initialized.
- * @param aKey key for frame A
- * @param bKey key for frame B
- */
- public void checkExternalFrame(final Enum<?> aKey, final Enum<?> bKey) {
- checkNotNull(frameA, aKey);
- checkNotNull(frameB, bKey);
- if (frameA.asSpacecraftBodyFrame() != null && frameB.asSpacecraftBodyFrame() != null) {
- // we cannot have two spacecraft body frames
- throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, frameB.getName());
- }
- }
- /** Check is mandatory entries <em>except external frame</em> have been initialized.
- * <p>
- * Either frame A or frame B must be initialized with a {@link
- * org.orekit.files.ccsds.definitions.SpacecraftBodyFrame spacecraft body frame}.
- * </p>
- * <p>
- * This method should throw an exception if some mandatory entry is missing
- * </p>
- * @param aKey key for frame A
- * @param bKey key for frame B
- * @param dirKey key for direction
- */
- public void checkMandatoryEntriesExceptExternalFrame(final Enum<?> aKey, final Enum<?> bKey,
- final Enum<?> dirKey) {
- if (frameA == null) {
- if (frameB == null || frameB.asSpacecraftBodyFrame() == null) {
- throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, aKey.name());
- }
- } else if (frameA.asSpacecraftBodyFrame() == null) {
- if (frameB == null) {
- throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, bKey.name());
- } else if (frameB.asSpacecraftBodyFrame() == null) {
- // at least one of the frame must be a spacecraft body frame
- throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, frameB.getName());
- }
- }
- checkNotNull(a2b, dirKey);
- }
- /** Set frame A.
- * @param frameA frame A
- */
- public void setFrameA(final FrameFacade frameA) {
- this.frameA = frameA;
- }
- /** Get frame A.
- * @return frame A
- */
- public FrameFacade getFrameA() {
- return frameA;
- }
- /** Set frame B.
- * @param frameB frame B
- */
- public void setFrameB(final FrameFacade frameB) {
- this.frameB = frameB;
- }
- /** Get frame B.
- * @return frame B
- */
- public FrameFacade getFrameB() {
- return frameB;
- }
- /** Set rotation direction.
- * @param a2b if true, rotation is from {@link #getFrameA() frame A}
- * to {@link #getFrameB() frame B}
- */
- public void setA2b(final boolean a2b) {
- this.a2b = a2b;
- }
- /** Check if rotation direction is from {@link #getFrameA() frame A} to {@link #getFrameB() frame B}.
- * @return true if rotation direction is from {@link #getFrameA() frame A} to {@link #getFrameB() frame B}
- */
- public boolean isA2b() {
- return a2b == null ? true : a2b;
- }
- /** Get the external frame.
- * @return external frame
- */
- public FrameFacade getExternalFrame() {
- return frameA.asSpacecraftBodyFrame() == null ? frameA : frameB;
- }
- /** Get the spacecraft body frame.
- * @return spacecraft body frame
- */
- public FrameFacade getSpacecraftBodyFrame() {
- return frameA.asSpacecraftBodyFrame() == null ? frameB : frameA;
- }
- /** Check if attitude is from external frame to spacecraft body frame.
- * <p>
- * {@link #checkMandatoryEntriesExceptExternalFrame(Enum, Enum, Enum)
- * Mandatory entries} must have been initialized properly to non-null
- * values before this method is called, otherwise {@code NullPointerException}
- * will be thrown.
- * </p>
- * @return true if attitude is from external frame to spacecraft body frame
- */
- public boolean isExternal2SpacecraftBody() {
- return a2b ^ frameB.asSpacecraftBodyFrame() == null;
- }
- /** Check if a endpoint is compatible with another one.
- * <p>
- * Endpoins are compatible if they refer o the same frame names,
- * in the same order and in the same direction.
- * </p>
- * @param other other endpoints to check against
- * @return true if both endpoints are compatible with each other
- */
- public boolean isCompatibleWith(final AttitudeEndoints other) {
- return frameA.getName().equals(other.frameA.getName()) &&
- frameB.getName().equals(other.frameB.getName()) &&
- a2b.equals(other.a2b);
- }
- /** {@inheritDoc} */
- @Override
- public Attitude build(final Frame frame, final PVCoordinatesProvider pvProv,
- final TimeStampedAngularCoordinates rawAttitude) {
- // attitude converted to Orekit conventions
- final TimeStampedAngularCoordinates att =
- isExternal2SpacecraftBody() ? rawAttitude : rawAttitude.revert();
- final FrameFacade external = getExternalFrame();
- final OrbitRelativeFrame orf = external.asOrbitRelativeFrame();
- if (orf != null) {
- // this is an orbit-relative attitude
- if (orf.getLofType() == null) {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_LOCAL_ORBITAL_FRAME, external.getName());
- }
- // construction of the local orbital frame, using PV from reference frame
- final PVCoordinates pv = pvProv.getPVCoordinates(rawAttitude.getDate(), frame);
- final AngularCoordinates frame2Lof =
- orf.isQuasiInertial() ?
- new AngularCoordinates(orf.getLofType().rotationFromInertial(pv), Vector3D.ZERO) :
- orf.getLofType().transformFromInertial(att.getDate(), pv).getAngular();
- // compose with APM
- return new Attitude(frame, att.addOffset(frame2Lof));
- } else {
- // this is an absolute attitude
- if (external.asFrame() == null) {
- // unknown frame
- throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, external.getName());
- }
- final Attitude attitude = new Attitude(external.asFrame(), att);
- return frame == null ? attitude : attitude.withReferenceFrame(frame);
- }
- }
- /** {@inheritDoc} */
- @Override
- public <T extends CalculusFieldElement<T>>
- FieldAttitude<T> build(final Frame frame, final FieldPVCoordinatesProvider<T> pvProv,
- final TimeStampedFieldAngularCoordinates<T> rawAttitude) {
- // attitude converted to Orekit conventions
- final TimeStampedFieldAngularCoordinates<T> att =
- isExternal2SpacecraftBody() ? rawAttitude : rawAttitude.revert();
- final FrameFacade external = getExternalFrame();
- final OrbitRelativeFrame orf = external.asOrbitRelativeFrame();
- if (orf != null) {
- // this is an orbit-relative attitude
- if (orf.getLofType() == null) {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_LOCAL_ORBITAL_FRAME, external.getName());
- }
- // construction of the local orbital frame, using PV from reference frame
- final FieldPVCoordinates<T> pv = pvProv.getPVCoordinates(rawAttitude.getDate(), frame);
- final Field<T> field = rawAttitude.getDate().getField();
- final FieldAngularCoordinates<T> referenceToLof =
- orf.isQuasiInertial() ?
- new FieldAngularCoordinates<>(orf.getLofType().rotationFromInertial(field, pv),
- FieldVector3D.getZero(field)) :
- orf.getLofType().transformFromInertial(att.getDate(), pv).getAngular();
- // compose with APM
- return new FieldAttitude<>(frame, att.addOffset(referenceToLof));
- } else {
- // this is an absolute attitude
- if (external.asFrame() == null) {
- // this should never happen as all CelestialBodyFrame have an Orekit mapping
- throw new OrekitException(OrekitMessages.CCSDS_INVALID_FRAME, external.getName());
- }
- final FieldAttitude<T> attitude = new FieldAttitude<>(external.asFrame(), att);
- return frame == null ? attitude : attitude.withReferenceFrame(frame);
- }
- }
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return frameA.getName() + (isA2b() ? " → " : " ← ") + frameB.getName();
- }
- }