CelestialBodyFrame.java

  1. /* Copyright 2002-2024 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 java.util.regex.Pattern;

  19. import org.orekit.bodies.CelestialBodyFactory;
  20. import org.orekit.data.DataContext;
  21. import org.orekit.errors.OrekitException;
  22. import org.orekit.errors.OrekitInternalError;
  23. import org.orekit.errors.OrekitMessages;
  24. import org.orekit.frames.Frame;
  25. import org.orekit.frames.ITRFVersion;
  26. import org.orekit.frames.VersionedITRF;
  27. import org.orekit.utils.IERSConventions;

  28. /** Frames used in CCSDS Orbit Data Messages.
  29.  * @author Steven Ports
  30.  * @since 6.1
  31.  */
  32. public enum CelestialBodyFrame {

  33.     /** Earth Mean Equator and Equinox of J2000. */
  34.     EME2000 {

  35.         /** {@inheritDoc} */
  36.         @Override
  37.         public Frame getFrame(final IERSConventions conventions,
  38.                               final boolean simpleEOP,
  39.                               final DataContext dataContext) {
  40.             return dataContext.getFrames().getEME2000();
  41.         }

  42.     },

  43.     /** Earth Mean Equator and Equinox of J2000. */
  44.     J2000 {

  45.         /** {@inheritDoc} */
  46.         @Override
  47.         public Frame getFrame(final IERSConventions conventions,
  48.                               final boolean simpleEOP,
  49.                               final DataContext dataContext) {
  50.             return dataContext.getFrames().getEME2000();
  51.         }

  52.     },

  53.     /** Geocentric Celestial Reference Frame. */
  54.     GCRF {

  55.         /** {@inheritDoc} */
  56.         @Override
  57.         public Frame getFrame(final IERSConventions conventions,
  58.                               final boolean simpleEOP,
  59.                               final DataContext dataContext) {
  60.             return dataContext.getFrames().getGCRF();
  61.         }

  62.     },

  63.     /** Greenwich Rotating Coordinates. */
  64.     GRC {

  65.         /** {@inheritDoc} */
  66.         @Override
  67.         public Frame getFrame(final IERSConventions conventions,
  68.                               final boolean simpleEOP,
  69.                               final DataContext dataContext) {
  70.             if (conventions == null) {
  71.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  72.             }
  73.             return dataContext.getFrames().getITRFEquinox(conventions, simpleEOP);
  74.         }

  75.     },

  76.     /** Greenwich True Of Date.
  77.      * @since 11.0
  78.      */
  79.     GTOD {

  80.         /** {@inheritDoc} */
  81.         @Override
  82.         public Frame getFrame(final IERSConventions conventions,
  83.                               final boolean simpleEOP,
  84.                               final DataContext dataContext) {
  85.             if (conventions == null) {
  86.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  87.             }
  88.             return dataContext.getFrames().getGTOD(conventions, simpleEOP);
  89.         }

  90.     },

  91.     /** International Celestial Reference Frame. */
  92.     ICRF {

  93.         /** {@inheritDoc} */
  94.         @Override
  95.         public Frame getFrame(final IERSConventions conventions,
  96.                               final boolean simpleEOP,
  97.                               final DataContext dataContext) {
  98.             return dataContext.getFrames().getICRF();
  99.         }

  100.     },

  101.     /** Latest International Terrestrial Reference Frame. */
  102.     ITRF {

  103.         /** {@inheritDoc} */
  104.         @Override
  105.         public Frame getFrame(final IERSConventions conventions,
  106.                               final boolean simpleEOP,
  107.                               final DataContext dataContext) {
  108.             return ITRF2020.getFrame(conventions, simpleEOP, dataContext);
  109.         }

  110.     },

  111.     /** International Terrestrial Reference Frame 2020. */
  112.     ITRF2020 {

  113.         /** {@inheritDoc} */
  114.         @Override
  115.         public Frame getFrame(final IERSConventions conventions,
  116.                               final boolean simpleEOP,
  117.                               final DataContext dataContext) {
  118.             if (conventions == null) {
  119.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  120.             }
  121.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_2020, conventions, simpleEOP);
  122.         }

  123.     },

  124.     /** International Terrestrial Reference Frame 2014. */
  125.     ITRF2014 {

  126.         /** {@inheritDoc} */
  127.         @Override
  128.         public Frame getFrame(final IERSConventions conventions,
  129.                               final boolean simpleEOP,
  130.                               final DataContext dataContext) {
  131.             if (conventions == null) {
  132.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  133.             }
  134.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_2014, conventions, simpleEOP);
  135.         }

  136.     },

  137.     /** International Terrestrial Reference Frame 2008. */
  138.     ITRF2008 {

  139.         /** {@inheritDoc} */
  140.         @Override
  141.         public Frame getFrame(final IERSConventions conventions,
  142.                               final boolean simpleEOP,
  143.                               final DataContext dataContext) {
  144.             if (conventions == null) {
  145.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  146.             }
  147.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_2008, conventions, simpleEOP);
  148.         }

  149.     },

  150.     /** International Terrestrial Reference Frame 2005. */
  151.     ITRF2005 {

  152.         /** {@inheritDoc} */
  153.         @Override
  154.         public Frame getFrame(final IERSConventions conventions,
  155.                               final boolean simpleEOP,
  156.                               final DataContext dataContext) {
  157.             if (conventions == null) {
  158.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  159.             }
  160.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_2005, conventions, simpleEOP);
  161.         }

  162.     },

  163.     /** International Terrestrial Reference Frame 2000. */
  164.     ITRF2000 {

  165.         /** {@inheritDoc} */
  166.         @Override
  167.         public Frame getFrame(final IERSConventions conventions,
  168.                               final boolean simpleEOP,
  169.                               final DataContext dataContext) {
  170.             if (conventions == null) {
  171.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  172.             }
  173.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_2000, conventions, simpleEOP);
  174.         }

  175.     },

  176.     /** International Terrestrial Reference Frame 1997. */
  177.     ITRF1997 {

  178.         /** {@inheritDoc} */
  179.         @Override
  180.         public Frame getFrame(final IERSConventions conventions,
  181.                               final boolean simpleEOP,
  182.                               final DataContext dataContext) {
  183.             if (conventions == null) {
  184.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  185.             }
  186.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1997, conventions, simpleEOP);
  187.         }

  188.     },

  189.     /** International Terrestrial Reference Frame 1996. */
  190.     ITRF1996 {

  191.         /** {@inheritDoc} */
  192.         @Override
  193.         public Frame getFrame(final IERSConventions conventions,
  194.                               final boolean simpleEOP,
  195.                               final DataContext dataContext) {
  196.             if (conventions == null) {
  197.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  198.             }
  199.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1996, conventions, simpleEOP);
  200.         }

  201.     },

  202.     /** International Terrestrial Reference Frame 1994. */
  203.     ITRF1994 {

  204.         /** {@inheritDoc} */
  205.         @Override
  206.         public Frame getFrame(final IERSConventions conventions,
  207.                               final boolean simpleEOP,
  208.                               final DataContext dataContext) {
  209.             if (conventions == null) {
  210.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  211.             }
  212.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1994, conventions, simpleEOP);
  213.         }

  214.     },

  215.     /** International Terrestrial Reference Frame 1993. */
  216.     ITRF1993 {

  217.         /** {@inheritDoc} */
  218.         @Override
  219.         public Frame getFrame(final IERSConventions conventions,
  220.                               final boolean simpleEOP,
  221.                               final DataContext dataContext) {
  222.             if (conventions == null) {
  223.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  224.             }
  225.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1993, conventions, simpleEOP);
  226.         }

  227.     },

  228.     /** International Terrestrial Reference Frame 1992. */
  229.     ITRF1992 {

  230.         /** {@inheritDoc} */
  231.         @Override
  232.         public Frame getFrame(final IERSConventions conventions,
  233.                               final boolean simpleEOP,
  234.                               final DataContext dataContext) {
  235.             if (conventions == null) {
  236.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  237.             }
  238.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1992, conventions, simpleEOP);
  239.         }

  240.     },

  241.     /** International Terrestrial Reference Frame 1991. */
  242.     ITRF1991 {

  243.         /** {@inheritDoc} */
  244.         @Override
  245.         public Frame getFrame(final IERSConventions conventions,
  246.                               final boolean simpleEOP,
  247.                               final DataContext dataContext) {
  248.             if (conventions == null) {
  249.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  250.             }
  251.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1991, conventions, simpleEOP);
  252.         }

  253.     },

  254.     /** International Terrestrial Reference Frame 1990. */
  255.     ITRF1990 {

  256.         /** {@inheritDoc} */
  257.         @Override
  258.         public Frame getFrame(final IERSConventions conventions,
  259.                               final boolean simpleEOP,
  260.                               final DataContext dataContext) {
  261.             if (conventions == null) {
  262.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  263.             }
  264.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1990, conventions, simpleEOP);
  265.         }

  266.     },

  267.     /** International Terrestrial Reference Frame 1989. */
  268.     ITRF1989 {

  269.         /** {@inheritDoc} */
  270.         @Override
  271.         public Frame getFrame(final IERSConventions conventions,
  272.                               final boolean simpleEOP,
  273.                               final DataContext dataContext) {
  274.             if (conventions == null) {
  275.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  276.             }
  277.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1989, conventions, simpleEOP);
  278.         }

  279.     },

  280.     /** International Terrestrial Reference Frame 1988. */
  281.     ITRF1988 {

  282.         /** {@inheritDoc} */
  283.         @Override
  284.         public Frame getFrame(final IERSConventions conventions,
  285.                               final boolean simpleEOP,
  286.                               final DataContext dataContext) {
  287.             if (conventions == null) {
  288.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  289.             }
  290.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1988, conventions, simpleEOP);
  291.         }

  292.     },

  293.     /** Mars Centered Inertial. */
  294.     MCI {

  295.         /** {@inheritDoc} */
  296.         @Override
  297.         public Frame getFrame(final IERSConventions conventions,
  298.                               final boolean simpleEOP,
  299.                               final DataContext dataContext) {
  300.             return dataContext.getCelestialBodies().getMars().getInertiallyOrientedFrame();
  301.         }

  302.     },

  303.     /** True of Date, Rotating. */
  304.     TDR {

  305.         /** {@inheritDoc} */
  306.         @Override
  307.         public Frame getFrame(final IERSConventions conventions,
  308.                               final boolean simpleEOP,
  309.                               final DataContext dataContext) {
  310.             if (conventions == null) {
  311.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  312.             }
  313.             return dataContext.getFrames().getGTOD(conventions, simpleEOP);
  314.         }

  315.     },

  316.     /**
  317.      * True Equator Mean Equinox.
  318.      * TEME may be used only for OMMs based on NORAD
  319.      * Two Line Element sets, and in no other circumstances.
  320.      */
  321.     TEME {

  322.         /** {@inheritDoc} */
  323.         @Override
  324.         public Frame getFrame(final IERSConventions conventions,
  325.                               final boolean simpleEOP,
  326.                               final DataContext dataContext) {
  327.             return dataContext.getFrames().getTEME();
  328.         }

  329.     },

  330.     /** True of Date. */
  331.     TOD {

  332.         /** {@inheritDoc} */
  333.         @Override
  334.         public Frame getFrame(final IERSConventions conventions,
  335.                               final boolean simpleEOP,
  336.                               final DataContext dataContext) {
  337.             if (conventions == null) {
  338.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  339.             }
  340.             return dataContext.getFrames().getTOD(conventions, simpleEOP);
  341.         }

  342.     };

  343.     /** Pattern for dash. */
  344.     private static final Pattern DASH = Pattern.compile("-");

  345.     /** Suffix of the name of the inertial frame attached to a planet. */
  346.     private static final String INERTIAL_FRAME_SUFFIX = "/inertial";

  347.     /** Substring common to all ITRF frames. */
  348.     private static final String ITRF_SUBSTRING = "ITRF";

  349.     /**
  350.      * Get the frame corresponding to the CCSDS constant.
  351.      * @param conventions IERS conventions to use
  352.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  353.      * @param dataContext to use when creating the frame.
  354.      * @return frame corresponding to the CCSDS constant
  355.      * @since 10.1
  356.      */
  357.     public abstract Frame getFrame(IERSConventions conventions, boolean simpleEOP, DataContext dataContext);

  358.     /**
  359.      * Get the name of celestial body frame.
  360.      * @return the name of celestial body frame
  361.      * @since 11.1
  362.      */
  363.     public String getName() {
  364.         return name();
  365.     }

  366.     /** Parse a CCSDS frame.
  367.      * @param frameName name of the frame, as the value of a CCSDS key=value line
  368.      * @return CCSDS frame corresponding to the name
  369.      */
  370.     public static CelestialBodyFrame parse(final String frameName) {
  371.         String canonicalized = DASH.matcher(frameName).replaceAll("");
  372.         if (canonicalized.startsWith(ITRF_SUBSTRING) && canonicalized.length() > 4) {
  373.             final int year = Integer.parseInt(canonicalized.substring(4));
  374.             if (year > 87 && year < 100) {
  375.                 // convert two-digits specifications like ITRF97 into ITRF1997
  376.                 canonicalized = ITRF_SUBSTRING + (year + 1900);
  377.             }
  378.         }
  379.         return CelestialBodyFrame.valueOf(canonicalized);
  380.     }

  381.     /**
  382.      * Map an Orekit frame to a CCSDS frame.
  383.      *
  384.      * <p> The goal of this method is to perform the opposite mapping of {@link
  385.      * #getFrame(IERSConventions, boolean, DataContext)}.
  386.      *
  387.      * @param frame a reference frame.
  388.      * @return the CCSDSFrame corresponding to the Orekit frame
  389.      */
  390.     public static CelestialBodyFrame map(final Frame frame) {
  391.         // Try to determine the CCSDS name from Annex A by examining the Orekit name.
  392.         final String name = frame.getName();
  393.         try {
  394.             // should handle J2000, GCRF, TEME, and some frames created by OEMParser.
  395.             return CelestialBodyFrame.valueOf(name);
  396.         } catch (IllegalArgumentException iae) {
  397.             if (frame instanceof ModifiedFrame) {
  398.                 return ((ModifiedFrame) frame).getRefFrame();
  399.             } else if ((CelestialBodyFactory.MARS + INERTIAL_FRAME_SUFFIX).equals(name)) {
  400.                 return MCI;
  401.             } else if ((CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER + INERTIAL_FRAME_SUFFIX).equals(name)) {
  402.                 return ICRF;
  403.             } else if (name.contains("GTOD")) {
  404.                 return GTOD;
  405.             } else if (name.contains("TOD")) { // check after GTOD
  406.                 return TOD;
  407.             } else if (name.contains("Equinox") && name.contains(ITRF_SUBSTRING)) {
  408.                 return GRC;
  409.             } else if (frame instanceof VersionedITRF) {
  410.                 try {
  411.                     final ITRFVersion itrfVersion = ((VersionedITRF) frame).getITRFVersion();
  412.                     return CelestialBodyFrame.valueOf(itrfVersion.name().replace("_", ""));
  413.                 } catch (IllegalArgumentException iae2) {
  414.                     // this should never happen
  415.                     throw new OrekitInternalError(iae2);
  416.                 }
  417.             } else if (name.contains("CIO") && name.contains(ITRF_SUBSTRING)) {
  418.                 return ITRF2014;
  419.             }
  420.             throw new OrekitException(iae, OrekitMessages.CCSDS_INVALID_FRAME, name);
  421.         }
  422.     }

  423.     /**
  424.      * Guesses names from ODM Table 5-3 and Annex A.
  425.      *
  426.      * <p> The goal of this method is to perform the opposite mapping of {@link
  427.      * #getFrame(IERSConventions, boolean, DataContext)}.
  428.      *
  429.      * @param frame a reference frame.
  430.      * @return the string to use in the OEM file to identify {@code frame}.
  431.      */
  432.     public static String guessFrame(final Frame frame) {
  433.         try {
  434.             return map(frame).name();
  435.         } catch (OrekitException oe) {
  436.             // we were unable to find a match
  437.             return frame.getName();
  438.         }
  439.     }

  440. }