CelestialBodyFrame.java

  1. /* Copyright 2002-2021 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 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_1997, conventions, simpleEOP);
  164.         }

  165.     },

  166.     /** International Terrestrial Reference Frame 1996. */
  167.     ITRF1996 {

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

  178.     },

  179.     /** International Terrestrial Reference Frame 1994. */
  180.     ITRF1994 {

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

  191.     },

  192.     /** International Terrestrial Reference Frame 1993. */
  193.     ITRF1993 {

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

  204.     },

  205.     /** International Terrestrial Reference Frame 1992. */
  206.     ITRF1992 {

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

  217.     },

  218.     /** International Terrestrial Reference Frame 1991. */
  219.     ITRF1991 {

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

  230.     },

  231.     /** International Terrestrial Reference Frame 1990. */
  232.     ITRF1990 {

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

  243.     },

  244.     /** International Terrestrial Reference Frame 1989. */
  245.     ITRF1989 {

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

  256.     },

  257.     /** International Terrestrial Reference Frame 1988. */
  258.     ITRF1988 {

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

  269.     },

  270.     /** Mars Centered Inertial. */
  271.     MCI {

  272.         /** {@inheritDoc} */
  273.         @Override
  274.         public Frame getFrame(final IERSConventions conventions,
  275.                               final boolean simpleEOP,
  276.                               final DataContext dataContext) {
  277.             return dataContext.getCelestialBodies().getMars().getInertiallyOrientedFrame();
  278.         }

  279.     },

  280.     /** True of Date, Rotating. */
  281.     TDR {

  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().getGTOD(conventions, simpleEOP);
  291.         }

  292.     },

  293.     /**
  294.      * True Equator Mean Equinox.
  295.      * TEME may be used only for OMMs based on NORAD
  296.      * Two Line Element sets, and in no other circumstances.
  297.      */
  298.     TEME {

  299.         /** {@inheritDoc} */
  300.         @Override
  301.         public Frame getFrame(final IERSConventions conventions,
  302.                               final boolean simpleEOP,
  303.                               final DataContext dataContext) {
  304.             return dataContext.getFrames().getTEME();
  305.         }

  306.     },

  307.     /** True of Date. */
  308.     TOD {

  309.         /** {@inheritDoc} */
  310.         @Override
  311.         public Frame getFrame(final IERSConventions conventions,
  312.                               final boolean simpleEOP,
  313.                               final DataContext dataContext) {
  314.             if (conventions == null) {
  315.                 throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
  316.             }
  317.             return dataContext.getFrames().getTOD(conventions, simpleEOP);
  318.         }

  319.     };

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

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

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

  326.     /**
  327.      * Get the frame corresponding to the CCSDS constant.
  328.      * @param conventions IERS conventions to use
  329.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  330.      * @param dataContext to use when creating the frame.
  331.      * @return frame corresponding to the CCSDS constant
  332.      * @since 10.1
  333.      */
  334.     public abstract Frame getFrame(IERSConventions conventions, boolean simpleEOP, DataContext dataContext);

  335.     /** Parse a CCSDS frame.
  336.      * @param frameName name of the frame, as the value of a CCSDS key=value line
  337.      * @return CCSDS frame corresponding to the name
  338.      */
  339.     public static CelestialBodyFrame parse(final String frameName) {
  340.         String canonicalized = DASH.matcher(frameName).replaceAll("");
  341.         if (canonicalized.startsWith(ITRF_SUBSTRING) && canonicalized.length() > 4) {
  342.             final int year = Integer.parseInt(canonicalized.substring(4));
  343.             if (year > 87 && year < 100) {
  344.                 // convert two-digits specifications like ITRF97 into ITRF1997
  345.                 canonicalized = ITRF_SUBSTRING + (year + 1900);
  346.             }
  347.         }
  348.         return CelestialBodyFrame.valueOf(canonicalized);
  349.     }

  350.     /**
  351.      * Map an Orekit frame to a CCSDS frame.
  352.      *
  353.      * <p> The goal of this method is to perform the opposite mapping of {@link
  354.      * #getFrame(IERSConventions, boolean, DataContext)}.
  355.      *
  356.      * @param frame a reference frame.
  357.      * @return the CCSDSFrame corresponding to the Orekit frame
  358.      */
  359.     public static CelestialBodyFrame map(final Frame frame) {
  360.         // Try to determine the CCSDS name from Annex A by examining the Orekit name.
  361.         final String name = frame.getName();
  362.         try {
  363.             // should handle J2000, GCRF, TEME, and some frames created by OEMParser.
  364.             return CelestialBodyFrame.valueOf(name);
  365.         } catch (IllegalArgumentException iae) {
  366.             if (frame instanceof ModifiedFrame) {
  367.                 return ((ModifiedFrame) frame).getRefFrame();
  368.             } else if ((CelestialBodyFactory.MARS + INERTIAL_FRAME_SUFFIX).equals(name)) {
  369.                 return MCI;
  370.             } else if ((CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER + INERTIAL_FRAME_SUFFIX).equals(name)) {
  371.                 return ICRF;
  372.             } else if (name.contains("GTOD")) {
  373.                 return GTOD;
  374.             } else if (name.contains("TOD")) { // check after GTOD
  375.                 return TOD;
  376.             } else if (name.contains("Equinox") && name.contains(ITRF_SUBSTRING)) {
  377.                 return GRC;
  378.             } else if (frame instanceof VersionedITRF) {
  379.                 try {
  380.                     final ITRFVersion itrfVersion = ((VersionedITRF) frame).getITRFVersion();
  381.                     return CelestialBodyFrame.valueOf(itrfVersion.name().replace("_", ""));
  382.                 } catch (IllegalArgumentException iae2) {
  383.                     // this should never happen
  384.                     throw new OrekitInternalError(iae2);
  385.                 }
  386.             } else if (name.contains("CIO") && name.contains(ITRF_SUBSTRING)) {
  387.                 return ITRF2014;
  388.             }
  389.             throw new OrekitException(iae, OrekitMessages.CCSDS_INVALID_FRAME, name);
  390.         }
  391.     }

  392.     /**
  393.      * Guesses names from ODM Table 5-3 and Annex A.
  394.      *
  395.      * <p> The goal of this method is to perform the opposite mapping of {@link
  396.      * #getFrame(IERSConventions, boolean, DataContext)}.
  397.      *
  398.      * @param frame a reference frame.
  399.      * @return the string to use in the OEM file to identify {@code frame}.
  400.      */
  401.     public static String guessFrame(final Frame frame) {
  402.         try {
  403.             return map(frame).name();
  404.         } catch (OrekitException oe) {
  405.             // we were unable to find a match
  406.             return frame.getName();
  407.         }
  408.     }

  409. }