FrameFacade.java
/* Copyright 2002-2024 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.definitions;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.orekit.data.DataContext;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.frames.Frame;
import org.orekit.frames.LOFType;
import org.orekit.frames.Transform;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinatesProvider;
/** Facade in front of several frames types in CCSDS messages.
*
* @author Luc Maisonobe
* @author Vincent Cucchietti
* @since 11.0
*/
public class FrameFacade {
/** Reference to node in Orekit frames tree. */
private final Frame frame;
/** Reference to celestial body centered frame. */
private final CelestialBodyFrame celestialBodyFrame;
/** Reference to orbit-relative frame. */
private final OrbitRelativeFrame orbitRelativeFrame;
/** Reference to spacecraft body frame. */
private final SpacecraftBodyFrame spacecraftBodyFrame;
/** Name of the frame. */
private final String name;
/**
* Simple constructor.
* <p>
* At most one of {@code celestialBodyFrame}, {@code orbitRelativeFrame} or {@code spacecraftBodyFrame} may be non
* null. They may all be null if frame is unknown, in which case only the name will be available.
* </p>
*
* @param frame reference to node in Orekit frames tree (may be null)
* @param celestialBodyFrame reference to celestial body centered frame (may be null)
* @param orbitRelativeFrame reference to orbit-relative frame (may be null)
* @param spacecraftBodyFrame reference to spacecraft body frame (may be null)
* @param name name of the frame
*/
public FrameFacade(final Frame frame,
final CelestialBodyFrame celestialBodyFrame,
final OrbitRelativeFrame orbitRelativeFrame,
final SpacecraftBodyFrame spacecraftBodyFrame,
final String name) {
this.frame = frame;
this.celestialBodyFrame = celestialBodyFrame;
this.orbitRelativeFrame = orbitRelativeFrame;
this.spacecraftBodyFrame = spacecraftBodyFrame;
this.name = name;
}
/**
* Get the associated frame tree node.
*
* @return associated frame tree node, or null if none exists
*/
public Frame asFrame() {
return frame;
}
/**
* Get the associated {@link CelestialBodyFrame celestial body frame}.
*
* @return associated celestial body frame, or null if frame is associated to a
* {@link #asOrbitRelativeFrame() orbit}, a {@link #asSpacecraftBodyFrame spacecraft} or is not supported
*/
public CelestialBodyFrame asCelestialBodyFrame() {
return celestialBodyFrame;
}
/**
* Get the associated {@link OrbitRelativeFrame orbit relative frame}.
*
* @return associated orbit relative frame, or null if frame is associated to a
* {@link #asCelestialBodyFrame() celestial body}, a {@link #asSpacecraftBodyFrame spacecraft} or is not supported
*/
public OrbitRelativeFrame asOrbitRelativeFrame() {
return orbitRelativeFrame;
}
/**
* Get the associated {@link SpacecraftBodyFrame spacecraft body frame}.
*
* @return associated spacecraft body frame, or null if frame is associated to a
* {@link #asCelestialBodyFrame() celestial body}, an {@link #asOrbitRelativeFrame orbit} or is not supported
*/
public SpacecraftBodyFrame asSpacecraftBodyFrame() {
return spacecraftBodyFrame;
}
/**
* Get the CCSDS name for the frame.
*
* @return CCSDS name
*/
public String getName() {
return name;
}
/**
* Map an Orekit frame to a CCSDS frame facade.
*
* @param frame a reference frame.
* @return the CCSDS frame corresponding to the Orekit frame
*/
public static FrameFacade map(final Frame frame) {
final CelestialBodyFrame cbf = CelestialBodyFrame.map(frame);
return new FrameFacade(frame, cbf, null, null, cbf.getName());
}
/**
* Simple constructor.
*
* @param name name of the frame
* @param conventions IERS conventions to use
* @param simpleEOP if true, tidal effects are ignored when interpolating EOP
* @param dataContext to use when creating the frame
* @param allowCelestial if true, {@link CelestialBodyFrame} are allowed
* @param allowOrbit if true, {@link OrbitRelativeFrame} are allowed
* @param allowSpacecraft if true, {@link SpacecraftBodyFrame} are allowed
* @return frame facade corresponding to the CCSDS name
*/
public static FrameFacade parse(final String name,
final IERSConventions conventions,
final boolean simpleEOP,
final DataContext dataContext,
final boolean allowCelestial,
final boolean allowOrbit,
final boolean allowSpacecraft) {
try {
final CelestialBodyFrame cbf = CelestialBodyFrame.parse(name);
if (allowCelestial) {
return new FrameFacade(cbf.getFrame(conventions, simpleEOP, dataContext),
cbf, null, null, cbf.getName());
}
} catch (IllegalArgumentException iaeC) {
try {
final OrbitRelativeFrame orf = OrbitRelativeFrame.valueOf(name.replace(' ', '_'));
if (allowOrbit) {
return new FrameFacade(null, null, orf, null, orf.name());
}
} catch (IllegalArgumentException iaeO) {
try {
final SpacecraftBodyFrame sbf = SpacecraftBodyFrame.parse(name.replace(' ', '_'));
if (allowSpacecraft) {
return new FrameFacade(null, null, null, sbf, sbf.toString());
}
} catch (OrekitException | IllegalArgumentException e) {
// nothing to do here, use fallback below
}
}
}
// we don't know any frame with this name, just store the name itself
return new FrameFacade(null, null, null, null, name);
}
/**
* Get the transform between {@link FrameFacade CCSDS frames}.
* <p>
* In case both input and output frames are {@link OrbitRelativeFrame orbit relative frame}, the returned transform
* will only be composed of a {@link Rotation rotation}. Only {@link LOFType commonly used orbit relative frames}
* will be recognized.
* <p>
* Note that if the input/output {@link FrameFacade CCSDS frame} is defined using a :
* <ul>
* <li><b>{@link CelestialBodyFrame celestial body frame}</b></li>
* <li><b>{@link SpacecraftBodyFrame spacecraft body frame}</b></li>
* </ul>
* then <b>an exception will be thrown</b> (currently not supported).
* <p>
* Note that the pivot frame provided <b>must be inertial</b> and <b>consistent</b> to what you are working with
* (i.e GCRF if around Earth for example).
*
* @param frameIn the input {@link FrameFacade CCSDS frame} to convert from
* @param frameOut the output {@link FrameFacade CCSDS frame} to convert to
* @param inertialPivotFrame <b>inertial</b> frame used as a pivot to create the transform
* @param date the date for the transform
* @param pv the position and velocity coordinates provider (required in case one of the frames is an
* {@link OrbitRelativeFrame orbit relative frame})
* @return the transform between {@link FrameFacade CCSDS frames}.
*/
public static Transform getTransform(final FrameFacade frameIn, final FrameFacade frameOut,
final Frame inertialPivotFrame,
final AbsoluteDate date, final PVCoordinatesProvider pv) {
if (inertialPivotFrame.isPseudoInertial()) {
final Transform frameInToPivot = getTransformToPivot(frameIn, inertialPivotFrame, date, pv);
final Transform pivotToFrameOut = getTransformToPivot(frameOut, inertialPivotFrame, date, pv).getInverse();
return new Transform(date, frameInToPivot, pivotToFrameOut);
}
else {
throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, inertialPivotFrame.getName());
}
}
/**
* Get the transform between input {@link FrameFacade CCSDS frame} and an <b>inertial</b>
* {@link Frame Orekit frame}.
*
* @param frameIn the input {@link FrameFacade CCSDS frame} to convert from
* @param inertialPivotFrame <b>inertial</b> {@link Frame Orekit frame} to convert to
* @param date the date for the transform
* @param pv the position and velocity coordinates provider (required in case the input
* {@link FrameFacade CCSDS frame} is an {@link OrbitRelativeFrame orbit relative frame})
* @return the transform between input {@link FrameFacade CCSDS frame} and an inertial {@link Frame Orekit frame}
*/
private static Transform getTransformToPivot(final FrameFacade frameIn, final Frame inertialPivotFrame,
final AbsoluteDate date, final PVCoordinatesProvider pv) {
final Transform frameInToPivot;
// Orekit frame
if (frameIn.asFrame() != null) {
frameInToPivot = frameIn.asFrame().getTransformTo(inertialPivotFrame, date);
}
// Local orbital frame
else if (frameIn.asOrbitRelativeFrame() != null) {
final LOFType lofIn = frameIn.asOrbitRelativeFrame().getLofType();
if (lofIn != null) {
frameInToPivot =
lofIn.transformFromInertial(date, pv.getPVCoordinates(date, inertialPivotFrame)).getInverse();
}
else {
throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.getName(),
inertialPivotFrame.getName());
}
}
//Celestial body frame
else if (frameIn.asCelestialBodyFrame() != null) {
throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.asCelestialBodyFrame().getName(),
inertialPivotFrame.getName());
}
// Spacecraft body frame
else {
throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.getName(),
inertialPivotFrame.getName());
}
return frameInToPivot;
}
}