FrameFacade.java

  1. /* Copyright 2002-2025 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.files.ccsds.definitions;

  18. import org.hipparchus.geometry.euclidean.threed.Rotation;
  19. import org.orekit.data.DataContext;
  20. import org.orekit.errors.OrekitException;
  21. import org.orekit.errors.OrekitMessages;
  22. import org.orekit.frames.Frame;
  23. import org.orekit.frames.LOFType;
  24. import org.orekit.frames.Transform;
  25. import org.orekit.time.AbsoluteDate;
  26. import org.orekit.utils.IERSConventions;
  27. import org.orekit.utils.PVCoordinatesProvider;

  28. /** Facade in front of several frames types in CCSDS messages.
  29.  *
  30.  * @author Luc Maisonobe
  31.  * @author Vincent Cucchietti
  32.  * @since 11.0
  33.  */
  34. public class FrameFacade {

  35.     /** Reference to node in Orekit frames tree. */
  36.     private final Frame frame;

  37.     /** Reference to celestial body centered frame. */
  38.     private final CelestialBodyFrame celestialBodyFrame;

  39.     /** Reference to orbit-relative frame. */
  40.     private final OrbitRelativeFrame orbitRelativeFrame;

  41.     /** Reference to spacecraft body frame. */
  42.     private final SpacecraftBodyFrame spacecraftBodyFrame;

  43.     /** Name of the frame. */
  44.     private final String name;

  45.     /**
  46.      * Simple constructor.
  47.      * <p>
  48.      * At most one of {@code celestialBodyFrame}, {@code orbitRelativeFrame} or {@code spacecraftBodyFrame} may be non
  49.      * null. They may all be null if frame is unknown, in which case only the name will be available.
  50.      * </p>
  51.      *
  52.      * @param frame reference to node in Orekit frames tree (may be null)
  53.      * @param celestialBodyFrame reference to celestial body centered frame (may be null)
  54.      * @param orbitRelativeFrame reference to orbit-relative frame (may be null)
  55.      * @param spacecraftBodyFrame reference to spacecraft body frame (may be null)
  56.      * @param name name of the frame
  57.      */
  58.     public FrameFacade(final Frame frame,
  59.                        final CelestialBodyFrame celestialBodyFrame,
  60.                        final OrbitRelativeFrame orbitRelativeFrame,
  61.                        final SpacecraftBodyFrame spacecraftBodyFrame,
  62.                        final String name) {
  63.         this.frame = frame;
  64.         this.celestialBodyFrame = celestialBodyFrame;
  65.         this.orbitRelativeFrame = orbitRelativeFrame;
  66.         this.spacecraftBodyFrame = spacecraftBodyFrame;
  67.         this.name = name;
  68.     }

  69.     /**
  70.      * Get the associated frame tree node.
  71.      *
  72.      * @return associated frame tree node, or null if none exists
  73.      */
  74.     public Frame asFrame() {
  75.         return frame;
  76.     }

  77.     /**
  78.      * Get the associated {@link CelestialBodyFrame celestial body frame}.
  79.      *
  80.      * @return associated celestial body frame, or null if frame is associated to a
  81.      * {@link #asOrbitRelativeFrame() orbit}, a {@link #asSpacecraftBodyFrame spacecraft} or is not supported
  82.      */
  83.     public CelestialBodyFrame asCelestialBodyFrame() {
  84.         return celestialBodyFrame;
  85.     }

  86.     /**
  87.      * Get the associated {@link OrbitRelativeFrame orbit relative frame}.
  88.      *
  89.      * @return associated orbit relative frame, or null if frame is associated to a
  90.      * {@link #asCelestialBodyFrame() celestial body}, a {@link #asSpacecraftBodyFrame spacecraft} or is not supported
  91.      */
  92.     public OrbitRelativeFrame asOrbitRelativeFrame() {
  93.         return orbitRelativeFrame;
  94.     }

  95.     /**
  96.      * Get the associated {@link SpacecraftBodyFrame spacecraft body frame}.
  97.      *
  98.      * @return associated spacecraft body frame, or null if frame is associated to a
  99.      * {@link #asCelestialBodyFrame() celestial body}, an {@link #asOrbitRelativeFrame orbit} or is not supported
  100.      */
  101.     public SpacecraftBodyFrame asSpacecraftBodyFrame() {
  102.         return spacecraftBodyFrame;
  103.     }

  104.     /**
  105.      * Get the CCSDS name for the frame.
  106.      *
  107.      * @return CCSDS name
  108.      */
  109.     public String getName() {
  110.         return name;
  111.     }

  112.     /**
  113.      * Map an Orekit frame to a CCSDS frame facade.
  114.      *
  115.      * @param frame a reference frame.
  116.      * @return the CCSDS frame corresponding to the Orekit frame
  117.      */
  118.     public static FrameFacade map(final Frame frame) {
  119.         final CelestialBodyFrame cbf = CelestialBodyFrame.map(frame);
  120.         return new FrameFacade(frame, cbf, null, null, cbf.getName());
  121.     }

  122.     /**
  123.      * Simple constructor.
  124.      *
  125.      * @param name name of the frame
  126.      * @param conventions IERS conventions to use
  127.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  128.      * @param dataContext to use when creating the frame
  129.      * @param allowCelestial if true, {@link CelestialBodyFrame} are allowed
  130.      * @param allowOrbit if true, {@link OrbitRelativeFrame} are allowed
  131.      * @param allowSpacecraft if true, {@link SpacecraftBodyFrame} are allowed
  132.      * @return frame facade corresponding to the CCSDS name
  133.      */
  134.     public static FrameFacade parse(final String name,
  135.                                     final IERSConventions conventions,
  136.                                     final boolean simpleEOP,
  137.                                     final DataContext dataContext,
  138.                                     final boolean allowCelestial,
  139.                                     final boolean allowOrbit,
  140.                                     final boolean allowSpacecraft) {
  141.         try {
  142.             final CelestialBodyFrame cbf = CelestialBodyFrame.parse(name);
  143.             if (allowCelestial) {
  144.                 return new FrameFacade(cbf.getFrame(conventions, simpleEOP, dataContext),
  145.                                        cbf, null, null, cbf.getName());
  146.             }
  147.         } catch (IllegalArgumentException iaeC) {
  148.             try {
  149.                 final OrbitRelativeFrame orf = OrbitRelativeFrame.valueOf(name.replace(' ', '_'));
  150.                 if (allowOrbit) {
  151.                     return new FrameFacade(null, null, orf, null, orf.name());
  152.                 }
  153.             } catch (IllegalArgumentException iaeO) {
  154.                 try {
  155.                     final SpacecraftBodyFrame sbf = SpacecraftBodyFrame.parse(name.replace(' ', '_'));
  156.                     if (allowSpacecraft) {
  157.                         return new FrameFacade(null, null, null, sbf, sbf.toString());
  158.                     }
  159.                 } catch (OrekitException | IllegalArgumentException e) {
  160.                     // nothing to do here, use fallback below
  161.                 }
  162.             }
  163.         }

  164.         // we don't know any frame with this name, just store the name itself
  165.         return new FrameFacade(null, null, null, null, name);

  166.     }

  167.     /**
  168.      * Get the transform between {@link FrameFacade CCSDS frames}.
  169.      * <p>
  170.      * In case both input and output frames are {@link OrbitRelativeFrame orbit relative frame}, the returned transform
  171.      * will only be composed of a {@link Rotation rotation}. Only {@link LOFType commonly used orbit relative frames}
  172.      * will be recognized.
  173.      * <p>
  174.      * Note that if the input/output {@link FrameFacade CCSDS frame} is defined using a :
  175.      * <ul>
  176.      * <li><b>{@link CelestialBodyFrame celestial body frame}</b></li>
  177.      * <li><b>{@link SpacecraftBodyFrame spacecraft body frame}</b></li>
  178.      * </ul>
  179.      * then <b>an exception will be thrown</b> (currently not supported).
  180.      * <p>
  181.      * Note that the pivot frame provided <b>must be inertial</b> and <b>consistent</b> to what you are working with
  182.      * (i.e GCRF if around Earth for example).
  183.      *
  184.      * @param frameIn the input {@link FrameFacade CCSDS frame} to convert from
  185.      * @param frameOut the output {@link FrameFacade CCSDS frame} to convert to
  186.      * @param inertialPivotFrame <b>inertial</b> frame used as a pivot to create the transform
  187.      * @param date the date for the transform
  188.      * @param pv the position and velocity coordinates provider (required in case one of the frames is an
  189.      * {@link OrbitRelativeFrame orbit relative frame})
  190.      * @return the transform between {@link FrameFacade CCSDS frames}.
  191.      */
  192.     public static Transform getTransform(final FrameFacade frameIn, final FrameFacade frameOut,
  193.                                          final Frame inertialPivotFrame,
  194.                                          final AbsoluteDate date, final PVCoordinatesProvider pv) {

  195.         if (inertialPivotFrame.isPseudoInertial()) {
  196.             final Transform frameInToPivot = getTransformToPivot(frameIn, inertialPivotFrame, date, pv);

  197.             final Transform pivotToFrameOut = getTransformToPivot(frameOut, inertialPivotFrame, date, pv).getInverse();

  198.             return new Transform(date, frameInToPivot, pivotToFrameOut);
  199.         }
  200.         else {
  201.             throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, inertialPivotFrame.getName());
  202.         }

  203.     }

  204.     /**
  205.      * Get the transform between input {@link FrameFacade CCSDS frame} and an <b>inertial</b>
  206.      * {@link Frame Orekit frame}.
  207.      *
  208.      * @param frameIn the input {@link FrameFacade CCSDS frame} to convert from
  209.      * @param inertialPivotFrame <b>inertial</b> {@link Frame Orekit frame} to convert to
  210.      * @param date the date for the transform
  211.      * @param pv the position and velocity coordinates provider (required in case the input
  212.      * {@link FrameFacade CCSDS frame} is an {@link OrbitRelativeFrame orbit relative frame})
  213.      * @return the transform between input {@link FrameFacade CCSDS frame} and an inertial {@link Frame Orekit frame}
  214.      */
  215.     private static Transform getTransformToPivot(final FrameFacade frameIn, final Frame inertialPivotFrame,
  216.                                                  final AbsoluteDate date, final PVCoordinatesProvider pv) {
  217.         final Transform frameInToPivot;

  218.         // Orekit frame
  219.         if (frameIn.asFrame() != null) {
  220.             frameInToPivot = frameIn.asFrame().getTransformTo(inertialPivotFrame, date);
  221.         }

  222.         // Local orbital frame
  223.         else if (frameIn.asOrbitRelativeFrame() != null) {

  224.             final LOFType lofIn = frameIn.asOrbitRelativeFrame().getLofType();

  225.             if (lofIn != null) {
  226.                 frameInToPivot =
  227.                         lofIn.transformFromInertial(date, pv.getPVCoordinates(date, inertialPivotFrame)).getInverse();
  228.             }
  229.             else {
  230.                 throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.getName(),
  231.                                           inertialPivotFrame.getName());
  232.             }
  233.         }

  234.         //Celestial body frame
  235.         else if (frameIn.asCelestialBodyFrame() != null) {
  236.             throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.asCelestialBodyFrame().getName(),
  237.                                       inertialPivotFrame.getName());
  238.         }

  239.         // Spacecraft body frame
  240.         else {
  241.             throw new OrekitException(OrekitMessages.UNSUPPORTED_TRANSFORM, frameIn.getName(),
  242.                                       inertialPivotFrame.getName());
  243.         }

  244.         return frameInToPivot;
  245.     }

  246. }