CelestialBodyFrame.java

  1. /* Copyright 2002-2022 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.     /** International Terrestrial Reference Frame 2020. */
  102.     ITRF2020 {

  103.         /** {@inheritDoc} */
  104.         @Override
  105.         public Frame getFrame(final IERSConventions conventions,
  106.                               final boolean simpleEOP,
  107.                               final DataContext dataContext) {
  108.             if (conventions == null) {
  109.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  110.             }
  111.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_2020, conventions, simpleEOP);
  112.         }

  113.     },

  114.     /** International Terrestrial Reference Frame 2014. */
  115.     ITRF2014 {

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

  126.     },

  127.     /** International Terrestrial Reference Frame 2008. */
  128.     ITRF2008 {

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

  139.     },

  140.     /** International Terrestrial Reference Frame 2005. */
  141.     ITRF2005 {

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

  152.     },

  153.     /** International Terrestrial Reference Frame 2000. */
  154.     ITRF2000 {

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

  165.     },

  166.     /** International Terrestrial Reference Frame 1997. */
  167.     ITRF1997 {

  168.         /** {@inheritDoc} */
  169.         @Override
  170.         public String getName() {
  171.             return "ITRF-97";
  172.         }

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

  183.     },

  184.     /** International Terrestrial Reference Frame 1996. */
  185.     ITRF1996 {

  186.         /** {@inheritDoc} */
  187.         @Override
  188.         public String getName() {
  189.             return "ITRF-96";
  190.         }

  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 String getName() {
  207.             return "ITRF-94";
  208.         }

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

  219.     },

  220.     /** International Terrestrial Reference Frame 1993. */
  221.     ITRF1993 {

  222.         /** {@inheritDoc} */
  223.         @Override
  224.         public String getName() {
  225.             return "ITRF-93";
  226.         }

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

  237.     },

  238.     /** International Terrestrial Reference Frame 1992. */
  239.     ITRF1992 {

  240.         /** {@inheritDoc} */
  241.         @Override
  242.         public String getName() {
  243.             return "ITRF-92";
  244.         }

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

  255.     },

  256.     /** International Terrestrial Reference Frame 1991. */
  257.     ITRF1991 {

  258.         /** {@inheritDoc} */
  259.         @Override
  260.         public String getName() {
  261.             return "ITRF-91";
  262.         }

  263.         /** {@inheritDoc} */
  264.         @Override
  265.         public Frame getFrame(final IERSConventions conventions,
  266.                               final boolean simpleEOP,
  267.                               final DataContext dataContext) {
  268.             if (conventions == null) {
  269.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  270.             }
  271.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1991, conventions, simpleEOP);
  272.         }

  273.     },

  274.     /** International Terrestrial Reference Frame 1990. */
  275.     ITRF1990 {

  276.         /** {@inheritDoc} */
  277.         @Override
  278.         public String getName() {
  279.             return "ITRF-90";
  280.         }

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

  291.     },

  292.     /** International Terrestrial Reference Frame 1989. */
  293.     ITRF1989 {

  294.         /** {@inheritDoc} */
  295.         @Override
  296.         public String getName() {
  297.             return "ITRF-89";
  298.         }

  299.         /** {@inheritDoc} */
  300.         @Override
  301.         public Frame getFrame(final IERSConventions conventions,
  302.                               final boolean simpleEOP,
  303.                               final DataContext dataContext) {
  304.             if (conventions == null) {
  305.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  306.             }
  307.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1989, conventions, simpleEOP);
  308.         }

  309.     },

  310.     /** International Terrestrial Reference Frame 1988. */
  311.     ITRF1988 {

  312.         /** {@inheritDoc} */
  313.         @Override
  314.         public String getName() {
  315.             return "ITRF-88";
  316.         }

  317.         /** {@inheritDoc} */
  318.         @Override
  319.         public Frame getFrame(final IERSConventions conventions,
  320.                               final boolean simpleEOP,
  321.                               final DataContext dataContext) {
  322.             if (conventions == null) {
  323.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  324.             }
  325.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1988, conventions, simpleEOP);
  326.         }

  327.     },

  328.     /** Mars Centered Inertial. */
  329.     MCI {

  330.         /** {@inheritDoc} */
  331.         @Override
  332.         public Frame getFrame(final IERSConventions conventions,
  333.                               final boolean simpleEOP,
  334.                               final DataContext dataContext) {
  335.             return dataContext.getCelestialBodies().getMars().getInertiallyOrientedFrame();
  336.         }

  337.     },

  338.     /** True of Date, Rotating. */
  339.     TDR {

  340.         /** {@inheritDoc} */
  341.         @Override
  342.         public Frame getFrame(final IERSConventions conventions,
  343.                               final boolean simpleEOP,
  344.                               final DataContext dataContext) {
  345.             if (conventions == null) {
  346.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  347.             }
  348.             return dataContext.getFrames().getGTOD(conventions, simpleEOP);
  349.         }

  350.     },

  351.     /**
  352.      * True Equator Mean Equinox.
  353.      * TEME may be used only for OMMs based on NORAD
  354.      * Two Line Element sets, and in no other circumstances.
  355.      */
  356.     TEME {

  357.         /** {@inheritDoc} */
  358.         @Override
  359.         public Frame getFrame(final IERSConventions conventions,
  360.                               final boolean simpleEOP,
  361.                               final DataContext dataContext) {
  362.             return dataContext.getFrames().getTEME();
  363.         }

  364.     },

  365.     /** True of Date. */
  366.     TOD {

  367.         /** {@inheritDoc} */
  368.         @Override
  369.         public Frame getFrame(final IERSConventions conventions,
  370.                               final boolean simpleEOP,
  371.                               final DataContext dataContext) {
  372.             if (conventions == null) {
  373.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  374.             }
  375.             return dataContext.getFrames().getTOD(conventions, simpleEOP);
  376.         }

  377.     };

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

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

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

  384.     /**
  385.      * Get the frame corresponding to the CCSDS constant.
  386.      * @param conventions IERS conventions to use
  387.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  388.      * @param dataContext to use when creating the frame.
  389.      * @return frame corresponding to the CCSDS constant
  390.      * @since 10.1
  391.      */
  392.     public abstract Frame getFrame(IERSConventions conventions, boolean simpleEOP, DataContext dataContext);

  393.     /**
  394.      * Get the name of celestial body frame.
  395.      * @return the name of celestial body frame
  396.      * @since 11.1
  397.      */
  398.     public String getName() {
  399.         return name();
  400.     }

  401.     /** Parse a CCSDS frame.
  402.      * @param frameName name of the frame, as the value of a CCSDS key=value line
  403.      * @return CCSDS frame corresponding to the name
  404.      */
  405.     public static CelestialBodyFrame parse(final String frameName) {
  406.         String canonicalized = DASH.matcher(frameName).replaceAll("");
  407.         if (canonicalized.startsWith(ITRF_SUBSTRING) && canonicalized.length() > 4) {
  408.             final int year = Integer.parseInt(canonicalized.substring(4));
  409.             if (year > 87 && year < 100) {
  410.                 // convert two-digits specifications like ITRF97 into ITRF1997
  411.                 canonicalized = ITRF_SUBSTRING + (year + 1900);
  412.             }
  413.         }
  414.         return CelestialBodyFrame.valueOf(canonicalized);
  415.     }

  416.     /**
  417.      * Map an Orekit frame to a CCSDS frame.
  418.      *
  419.      * <p> The goal of this method is to perform the opposite mapping of {@link
  420.      * #getFrame(IERSConventions, boolean, DataContext)}.
  421.      *
  422.      * @param frame a reference frame.
  423.      * @return the CCSDSFrame corresponding to the Orekit frame
  424.      */
  425.     public static CelestialBodyFrame map(final Frame frame) {
  426.         // Try to determine the CCSDS name from Annex A by examining the Orekit name.
  427.         final String name = frame.getName();
  428.         try {
  429.             // should handle J2000, GCRF, TEME, and some frames created by OEMParser.
  430.             return CelestialBodyFrame.valueOf(name);
  431.         } catch (IllegalArgumentException iae) {
  432.             if (frame instanceof ModifiedFrame) {
  433.                 return ((ModifiedFrame) frame).getRefFrame();
  434.             } else if ((CelestialBodyFactory.MARS + INERTIAL_FRAME_SUFFIX).equals(name)) {
  435.                 return MCI;
  436.             } else if ((CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER + INERTIAL_FRAME_SUFFIX).equals(name)) {
  437.                 return ICRF;
  438.             } else if (name.contains("GTOD")) {
  439.                 return GTOD;
  440.             } else if (name.contains("TOD")) { // check after GTOD
  441.                 return TOD;
  442.             } else if (name.contains("Equinox") && name.contains(ITRF_SUBSTRING)) {
  443.                 return GRC;
  444.             } else if (frame instanceof VersionedITRF) {
  445.                 try {
  446.                     final ITRFVersion itrfVersion = ((VersionedITRF) frame).getITRFVersion();
  447.                     return CelestialBodyFrame.valueOf(itrfVersion.name().replace("_", ""));
  448.                 } catch (IllegalArgumentException iae2) {
  449.                     // this should never happen
  450.                     throw new OrekitInternalError(iae2);
  451.                 }
  452.             } else if (name.contains("CIO") && name.contains(ITRF_SUBSTRING)) {
  453.                 return ITRF2014;
  454.             }
  455.             throw new OrekitException(iae, OrekitMessages.CCSDS_INVALID_FRAME, name);
  456.         }
  457.     }

  458.     /**
  459.      * Guesses names from ODM Table 5-3 and Annex A.
  460.      *
  461.      * <p> The goal of this method is to perform the opposite mapping of {@link
  462.      * #getFrame(IERSConventions, boolean, DataContext)}.
  463.      *
  464.      * @param frame a reference frame.
  465.      * @return the string to use in the OEM file to identify {@code frame}.
  466.      */
  467.     public static String guessFrame(final Frame frame) {
  468.         try {
  469.             return map(frame).name();
  470.         } catch (OrekitException oe) {
  471.             // we were unable to find a match
  472.             return frame.getName();
  473.         }
  474.     }

  475. }