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 2014. */
  102.     ITRF2014 {

  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_2014, conventions, simpleEOP);
  112.         }

  113.     },

  114.     /** International Terrestrial Reference Frame 2008. */
  115.     ITRF2008 {

  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_2008, conventions, simpleEOP);
  125.         }

  126.     },

  127.     /** International Terrestrial Reference Frame 2005. */
  128.     ITRF2005 {

  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_2005, conventions, simpleEOP);
  138.         }

  139.     },

  140.     /** International Terrestrial Reference Frame 2000. */
  141.     ITRF2000 {

  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_2000, conventions, simpleEOP);
  151.         }

  152.     },

  153.     /** International Terrestrial Reference Frame 1997. */
  154.     ITRF1997 {

  155.         /** {@inheritDoc} */
  156.         @Override
  157.         public String getName() {
  158.             return "ITRF-97";
  159.         }

  160.         /** {@inheritDoc} */
  161.         @Override
  162.         public Frame getFrame(final IERSConventions conventions,
  163.                               final boolean simpleEOP,
  164.                               final DataContext dataContext) {
  165.             if (conventions == null) {
  166.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  167.             }
  168.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1997, conventions, simpleEOP);
  169.         }

  170.     },

  171.     /** International Terrestrial Reference Frame 1996. */
  172.     ITRF1996 {

  173.         /** {@inheritDoc} */
  174.         @Override
  175.         public String getName() {
  176.             return "ITRF-96";
  177.         }

  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_1996, conventions, simpleEOP);
  187.         }

  188.     },

  189.     /** International Terrestrial Reference Frame 1994. */
  190.     ITRF1994 {

  191.         /** {@inheritDoc} */
  192.         @Override
  193.         public String getName() {
  194.             return "ITRF-94";
  195.         }

  196.         /** {@inheritDoc} */
  197.         @Override
  198.         public Frame getFrame(final IERSConventions conventions,
  199.                               final boolean simpleEOP,
  200.                               final DataContext dataContext) {
  201.             if (conventions == null) {
  202.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  203.             }
  204.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1994, conventions, simpleEOP);
  205.         }

  206.     },

  207.     /** International Terrestrial Reference Frame 1993. */
  208.     ITRF1993 {

  209.         /** {@inheritDoc} */
  210.         @Override
  211.         public String getName() {
  212.             return "ITRF-93";
  213.         }

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

  224.     },

  225.     /** International Terrestrial Reference Frame 1992. */
  226.     ITRF1992 {

  227.         /** {@inheritDoc} */
  228.         @Override
  229.         public String getName() {
  230.             return "ITRF-92";
  231.         }

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

  242.     },

  243.     /** International Terrestrial Reference Frame 1991. */
  244.     ITRF1991 {

  245.         /** {@inheritDoc} */
  246.         @Override
  247.         public String getName() {
  248.             return "ITRF-91";
  249.         }

  250.         /** {@inheritDoc} */
  251.         @Override
  252.         public Frame getFrame(final IERSConventions conventions,
  253.                               final boolean simpleEOP,
  254.                               final DataContext dataContext) {
  255.             if (conventions == null) {
  256.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  257.             }
  258.             return dataContext.getFrames().getITRF(ITRFVersion.ITRF_1991, conventions, simpleEOP);
  259.         }

  260.     },

  261.     /** International Terrestrial Reference Frame 1990. */
  262.     ITRF1990 {

  263.         /** {@inheritDoc} */
  264.         @Override
  265.         public String getName() {
  266.             return "ITRF-90";
  267.         }

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

  278.     },

  279.     /** International Terrestrial Reference Frame 1989. */
  280.     ITRF1989 {

  281.         /** {@inheritDoc} */
  282.         @Override
  283.         public String getName() {
  284.             return "ITRF-89";
  285.         }

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

  296.     },

  297.     /** International Terrestrial Reference Frame 1988. */
  298.     ITRF1988 {

  299.         /** {@inheritDoc} */
  300.         @Override
  301.         public String getName() {
  302.             return "ITRF-88";
  303.         }

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

  314.     },

  315.     /** Mars Centered Inertial. */
  316.     MCI {

  317.         /** {@inheritDoc} */
  318.         @Override
  319.         public Frame getFrame(final IERSConventions conventions,
  320.                               final boolean simpleEOP,
  321.                               final DataContext dataContext) {
  322.             return dataContext.getCelestialBodies().getMars().getInertiallyOrientedFrame();
  323.         }

  324.     },

  325.     /** True of Date, Rotating. */
  326.     TDR {

  327.         /** {@inheritDoc} */
  328.         @Override
  329.         public Frame getFrame(final IERSConventions conventions,
  330.                               final boolean simpleEOP,
  331.                               final DataContext dataContext) {
  332.             if (conventions == null) {
  333.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  334.             }
  335.             return dataContext.getFrames().getGTOD(conventions, simpleEOP);
  336.         }

  337.     },

  338.     /**
  339.      * True Equator Mean Equinox.
  340.      * TEME may be used only for OMMs based on NORAD
  341.      * Two Line Element sets, and in no other circumstances.
  342.      */
  343.     TEME {

  344.         /** {@inheritDoc} */
  345.         @Override
  346.         public Frame getFrame(final IERSConventions conventions,
  347.                               final boolean simpleEOP,
  348.                               final DataContext dataContext) {
  349.             return dataContext.getFrames().getTEME();
  350.         }

  351.     },

  352.     /** True of Date. */
  353.     TOD {

  354.         /** {@inheritDoc} */
  355.         @Override
  356.         public Frame getFrame(final IERSConventions conventions,
  357.                               final boolean simpleEOP,
  358.                               final DataContext dataContext) {
  359.             if (conventions == null) {
  360.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  361.             }
  362.             return dataContext.getFrames().getTOD(conventions, simpleEOP);
  363.         }

  364.     };

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

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

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

  371.     /**
  372.      * Get the frame corresponding to the CCSDS constant.
  373.      * @param conventions IERS conventions to use
  374.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  375.      * @param dataContext to use when creating the frame.
  376.      * @return frame corresponding to the CCSDS constant
  377.      * @since 10.1
  378.      */
  379.     public abstract Frame getFrame(IERSConventions conventions, boolean simpleEOP, DataContext dataContext);

  380.     /**
  381.      * Get the name of celestial body frame.
  382.      * @return the name of celestial body frame
  383.      * @since 11.1
  384.      */
  385.     public String getName() {
  386.         return name();
  387.     }

  388.     /** Parse a CCSDS frame.
  389.      * @param frameName name of the frame, as the value of a CCSDS key=value line
  390.      * @return CCSDS frame corresponding to the name
  391.      */
  392.     public static CelestialBodyFrame parse(final String frameName) {
  393.         String canonicalized = DASH.matcher(frameName).replaceAll("");
  394.         if (canonicalized.startsWith(ITRF_SUBSTRING) && canonicalized.length() > 4) {
  395.             final int year = Integer.parseInt(canonicalized.substring(4));
  396.             if (year > 87 && year < 100) {
  397.                 // convert two-digits specifications like ITRF97 into ITRF1997
  398.                 canonicalized = ITRF_SUBSTRING + (year + 1900);
  399.             }
  400.         }
  401.         return CelestialBodyFrame.valueOf(canonicalized);
  402.     }

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

  445.     /**
  446.      * Guesses names from ODM Table 5-3 and Annex A.
  447.      *
  448.      * <p> The goal of this method is to perform the opposite mapping of {@link
  449.      * #getFrame(IERSConventions, boolean, DataContext)}.
  450.      *
  451.      * @param frame a reference frame.
  452.      * @return the string to use in the OEM file to identify {@code frame}.
  453.      */
  454.     public static String guessFrame(final Frame frame) {
  455.         try {
  456.             return map(frame).name();
  457.         } catch (OrekitException oe) {
  458.             // we were unable to find a match
  459.             return frame.getName();
  460.         }
  461.     }

  462. }