LOFType.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.frames;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  21. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  22. import org.hipparchus.geometry.euclidean.threed.Rotation;
  23. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  24. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  25. import org.orekit.errors.OrekitException;
  26. import org.orekit.errors.OrekitMessages;
  27. import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
  28. import org.orekit.time.AbsoluteDate;
  29. import org.orekit.time.FieldAbsoluteDate;
  30. import org.orekit.utils.FieldPVCoordinates;
  31. import org.orekit.utils.PVCoordinates;

  32. /**
  33.  * Enumerate for different types of Local Orbital Frames.
  34.  *
  35.  * @author Luc Maisonobe
  36.  * @author Maxime Journot
  37.  * @author Vincent Cucchietti
  38.  */
  39. public enum LOFType implements LOF {

  40.     /** Constant for TNW frame
  41.      * (X axis aligned with velocity, Z axis aligned with orbital momentum).
  42.      * <p>
  43.      * The axes of this frame are parallel to the axes of the {@link #VNC}
  44.      * and {@link #NTW} frames:
  45.      * <ul>
  46.      *   <li>X<sub>TNW</sub> =  X<sub>VNC</sub> =  Y<sub>NTW</sub></li>
  47.      *   <li>Y<sub>TNW</sub> = -Z<sub>VNC</sub> = -X<sub>NTW</sub></li>
  48.      *   <li>Z<sub>TNW</sub> =  Y<sub>VNC</sub> =  Z<sub>NTW</sub></li>
  49.      * </ul>
  50.      *
  51.      * @see #VNC
  52.      * @see #NTW
  53.      */
  54.     TNW {
  55.         /** {@inheritDoc} */
  56.         @Override
  57.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  58.             return new Rotation(pv.getVelocity(), pv.getMomentum(),
  59.                                 Vector3D.PLUS_I, Vector3D.PLUS_K);
  60.         }

  61.         /** {@inheritDoc} */
  62.         @Override
  63.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  64.                                                                                          final FieldPVCoordinates<T> pv) {
  65.             return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(),
  66.                                        new FieldVector3D<>(field, Vector3D.PLUS_I),
  67.                                        new FieldVector3D<>(field, Vector3D.PLUS_K));
  68.         }

  69.         /** {@inheritDoc} */
  70.         @Override
  71.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  72.             return OrbitRelativeFrame.TNW;
  73.         }

  74.     },

  75.     /**
  76.      * Constant for TNW frame considered inertial (X axis aligned with velocity, Z axis aligned with orbital momentum).
  77.      * <p>
  78.      * The axes of this frame are parallel to the axes of the {@link #VNC} and {@link #NTW} frames:
  79.      * <ul>
  80.      *   <li>X<sub>TNW</sub> =  X<sub>VNC</sub> =  Y<sub>NTW</sub></li>
  81.      *   <li>Y<sub>TNW</sub> = -Z<sub>VNC</sub> = -X<sub>NTW</sub></li>
  82.      *   <li>Z<sub>TNW</sub> =  Y<sub>VNC</sub> =  Z<sub>NTW</sub></li>
  83.      * </ul>
  84.      *
  85.      * @see #VNC
  86.      * @see #NTW
  87.      */
  88.     TNW_INERTIAL {
  89.         /** {@inheritDoc} */
  90.         @Override
  91.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  92.             return TNW.rotationFromInertial(pv);
  93.         }

  94.         /** {@inheritDoc} */
  95.         @Override
  96.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  97.                                                                                          final FieldPVCoordinates<T> pv) {
  98.             return TNW.rotationFromInertial(field, pv);
  99.         }

  100.         /** {@inheritDoc} */
  101.         @Override
  102.         public boolean isQuasiInertial() {
  103.             return true;
  104.         }

  105.         /** {@inheritDoc} */
  106.         @Override
  107.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  108.             return OrbitRelativeFrame.TNW_INERTIAL;
  109.         }

  110.     },

  111.     /** Constant for QSW frame
  112.      * (X axis aligned with position, Z axis aligned with orbital momentum).
  113.      * <p>
  114.      * This frame is also known as the {@link #LVLH} frame, both constants are equivalent.
  115.      * </p>
  116.      * <p>
  117.      * The axes of these frames are parallel to the axes of the {@link #VVLH} frame:
  118.      * <ul>
  119.      *   <li>X<sub>QSW/LVLH</sub> = -Z<sub>VVLH</sub></li>
  120.      *   <li>Y<sub>QSW/LVLH</sub> =  X<sub>VVLH</sub></li>
  121.      *   <li>Z<sub>QSW/LVLH</sub> = -Y<sub>VVLH</sub></li>
  122.      * </ul>
  123.      *
  124.      * @see #LVLH
  125.      * @see #VVLH
  126.      */
  127.     QSW {
  128.         /** {@inheritDoc} */
  129.         @Override
  130.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  131.             return new Rotation(pv.getPosition(), pv.getMomentum(),
  132.                                 Vector3D.PLUS_I, Vector3D.PLUS_K);
  133.         }

  134.         /** {@inheritDoc} */
  135.         @Override
  136.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  137.                                                                                          final FieldPVCoordinates<T> pv) {
  138.             return new FieldRotation<>(pv.getPosition(), pv.getMomentum(),
  139.                                        new FieldVector3D<>(field, Vector3D.PLUS_I),
  140.                                        new FieldVector3D<>(field, Vector3D.PLUS_K));
  141.         }

  142.         /** {@inheritDoc} */
  143.         @Override
  144.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  145.             return OrbitRelativeFrame.QSW;
  146.         }

  147.     },

  148.     /**
  149.      * Constant for QSW frame considered inertial (X axis aligned with position, Z axis aligned with orbital momentum).
  150.      * <p>
  151.      * This frame is also known as the {@link #LVLH} frame, both constants are equivalent.
  152.      * </p>
  153.      * <p>
  154.      * The axes of these frames are parallel to the axes of the {@link #VVLH} frame:
  155.      * <ul>
  156.      *   <li>X<sub>QSW/LVLH</sub> = -Z<sub>VVLH</sub></li>
  157.      *   <li>Y<sub>QSW/LVLH</sub> =  X<sub>VVLH</sub></li>
  158.      *   <li>Z<sub>QSW/LVLH</sub> = -Y<sub>VVLH</sub></li>
  159.      * </ul>
  160.      *
  161.      * @see #LVLH
  162.      * @see #VVLH
  163.      */
  164.     QSW_INERTIAL {
  165.         /** {@inheritDoc} */
  166.         @Override
  167.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  168.             return QSW.rotationFromInertial(pv);
  169.         }

  170.         /** {@inheritDoc} */
  171.         @Override
  172.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  173.                                                                                          final FieldPVCoordinates<T> pv) {
  174.             return QSW.rotationFromInertial(field, pv);
  175.         }

  176.         /** {@inheritDoc} */
  177.         @Override
  178.         public boolean isQuasiInertial() {
  179.             return true;
  180.         }

  181.         /** {@inheritDoc} */
  182.         @Override
  183.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  184.             return OrbitRelativeFrame.RSW_INERTIAL;
  185.         }

  186.     },

  187.     /** Constant for Local Vertical, Local Horizontal frame
  188.      * (X axis aligned with position, Z axis aligned with orbital momentum).
  189.      * <p>
  190.      * BEWARE! Depending on the background (software used, textbook, community),
  191.      * different incompatible definitions for LVLH are used. This one is consistent
  192.      * with Vallado's book and with AGI's STK. However CCSDS standard, Wertz, and
  193.      * a.i. solutions' FreeFlyer use another definition (see {@link #LVLH_CCSDS}).
  194.      * </p>
  195.      * <p>
  196.      * This frame is also known as the {@link #QSW} frame, both constants are equivalent.
  197.      * </p>
  198.      * <p>
  199.      * The axes of these frames are parallel to the axes of the {@link #LVLH_CCSDS} frame:
  200.      * <ul>
  201.      *   <li>X<sub>LVLH/QSW</sub> = -Z<sub>LVLH_CCSDS</sub></li>
  202.      *   <li>Y<sub>LVLH/QSW</sub> =  X<sub>LVLH_CCSDS</sub></li>
  203.      *   <li>Z<sub>LVLH/QSW</sub> = -Y<sub>LVLH_CCSDS</sub></li>
  204.      * </ul>
  205.      *
  206.      * @see #QSW
  207.      * @see #VVLH
  208.      */
  209.     LVLH {
  210.         /** {@inheritDoc} */
  211.         @Override
  212.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  213.             return new Rotation(pv.getPosition(), pv.getMomentum(),
  214.                                 Vector3D.PLUS_I, Vector3D.PLUS_K);
  215.         }

  216.         /** {@inheritDoc} */
  217.         @Override
  218.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  219.                                                                                          final FieldPVCoordinates<T> pv) {
  220.             return new FieldRotation<>(pv.getPosition(), pv.getMomentum(),
  221.                                        new FieldVector3D<>(field, Vector3D.PLUS_I),
  222.                                        new FieldVector3D<>(field, Vector3D.PLUS_K));
  223.         }

  224.         /** {@inheritDoc} */
  225.         @Override
  226.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  227.             throw new OrekitException(OrekitMessages.CCSDS_DIFFERENT_LVLH_DEFINITION);
  228.         }

  229.     },

  230.     /**
  231.      * Constant for Local Vertical, Local Horizontal frame considered inertial (X axis aligned with position, Z axis
  232.      * aligned with orbital momentum).
  233.      * <p>
  234.      * BEWARE! Depending on the background (software used, textbook, community), different incompatible definitions for
  235.      * LVLH are used. This one is consistent with Vallado's book and with AGI's STK. However CCSDS standard, Wertz, and
  236.      * a.i. solutions' FreeFlyer use another definition (see {@link #LVLH_CCSDS}).
  237.      * </p>
  238.      * <p>
  239.      * This frame is also known as the {@link #QSW} frame, both constants are equivalent.
  240.      * </p>
  241.      * <p>
  242.      * The axes of these frames are parallel to the axes of the {@link #LVLH_CCSDS} frame:
  243.      * <ul>
  244.      *   <li>X<sub>LVLH/QSW</sub> = -Z<sub>LVLH_CCSDS</sub></li>
  245.      *   <li>Y<sub>LVLH/QSW</sub> =  X<sub>LVLH_CCSDS</sub></li>
  246.      *   <li>Z<sub>LVLH/QSW</sub> = -Y<sub>LVLH_CCSDS</sub></li>
  247.      * </ul>
  248.      *
  249.      * @see #QSW
  250.      * @see #VVLH
  251.      */
  252.     LVLH_INERTIAL {
  253.         /** {@inheritDoc} */
  254.         @Override
  255.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  256.             return LVLH.rotationFromInertial(pv);
  257.         }

  258.         /** {@inheritDoc} */
  259.         @Override
  260.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  261.                                                                                          final FieldPVCoordinates<T> pv) {
  262.             return LVLH.rotationFromInertial(field, pv);
  263.         }

  264.         /** {@inheritDoc} */
  265.         @Override
  266.         public boolean isQuasiInertial() {
  267.             return true;
  268.         }

  269.         /** {@inheritDoc} */
  270.         @Override
  271.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  272.             throw new OrekitException(OrekitMessages.CCSDS_DIFFERENT_LVLH_DEFINITION);
  273.         }

  274.     },

  275.     /** Constant for Local Vertical, Local Horizontal frame as defined by CCSDS
  276.      * (Z axis aligned with opposite of position, Y axis aligned with opposite of orbital momentum).
  277.      * <p>
  278.      * BEWARE! Depending on the background (software used, textbook, community),
  279.      * different incompatible definitions for LVLH are used. This one is consistent
  280.      * with CCSDS standard, Wertz, and a.i. solutions' FreeFlyer. However Vallado's
  281.      * book and with AGI's STK use another definition (see {@link #LVLH}).
  282.      * </p>
  283.      * <p>
  284.      * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames:
  285.      * <ul>
  286.      *   <li>X<sub>LVLH_CCSDS/VVLH</sub> =  Y<sub>QSW/LVLH</sub></li>
  287.      *   <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li>
  288.      *   <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li>
  289.      * </ul>
  290.      *
  291.      * @see #QSW
  292.      * @see #LVLH
  293.      * @since 11.0
  294.      */
  295.     LVLH_CCSDS {
  296.         /** {@inheritDoc} */
  297.         @Override
  298.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  299.             return new Rotation(pv.getPosition(), pv.getMomentum(),
  300.                                 Vector3D.MINUS_K, Vector3D.MINUS_J);
  301.         }

  302.         /** {@inheritDoc} */
  303.         @Override
  304.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  305.                                                                                          final FieldPVCoordinates<T> pv) {
  306.             return new FieldRotation<>(pv.getPosition(), pv.getMomentum(),
  307.                                        new FieldVector3D<>(field, Vector3D.MINUS_K),
  308.                                        new FieldVector3D<>(field, Vector3D.MINUS_J));
  309.         }

  310.         /** {@inheritDoc} */
  311.         @Override
  312.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  313.             return OrbitRelativeFrame.LVLH;
  314.         }

  315.     },

  316.     /**
  317.      * Constant for Local Vertical, Local Horizontal frame as defined by CCSDS considered inertial (Z axis aligned with
  318.      * opposite of position, Y axis aligned with opposite of orbital momentum).
  319.      * <p>
  320.      * BEWARE! Depending on the background (software used, textbook, community), different incompatible definitions for
  321.      * LVLH are used. This one is consistent with CCSDS standard, Wertz, and a.i. solutions' FreeFlyer. However
  322.      * Vallado's book and with AGI's STK use another definition (see {@link #LVLH}).
  323.      * </p>
  324.      * <p>
  325.      * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames:
  326.      * <ul>
  327.      *   <li>X<sub>LVLH_CCSDS/VVLH</sub> =  Y<sub>QSW/LVLH</sub></li>
  328.      *   <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li>
  329.      *   <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li>
  330.      * </ul>
  331.      *
  332.      * @see #QSW
  333.      * @see #LVLH
  334.      * @since 11.0
  335.      */
  336.     LVLH_CCSDS_INERTIAL {
  337.         /** {@inheritDoc} */
  338.         @Override
  339.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  340.             return LVLH_CCSDS.rotationFromInertial(pv);
  341.         }

  342.         /** {@inheritDoc} */
  343.         @Override
  344.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  345.                                                                                          final FieldPVCoordinates<T> pv) {
  346.             return LVLH_CCSDS.rotationFromInertial(field, pv);
  347.         }

  348.         /** {@inheritDoc} */
  349.         @Override
  350.         public boolean isQuasiInertial() {
  351.             return true;
  352.         }

  353.         /** {@inheritDoc} */
  354.         @Override
  355.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  356.             return OrbitRelativeFrame.LVLH_INERTIAL;
  357.         }

  358.     },

  359.     /** Constant for Vehicle Velocity, Local Horizontal frame
  360.      * (Z axis aligned with opposite of position, Y axis aligned with opposite of orbital momentum).
  361.      * <p>
  362.      * This is another name for {@link #LVLH_CCSDS}, kept here for compatibility with STK.
  363.      * </p>
  364.      * <p>
  365.      * Beware that the name is misleading: in the general case (i.e. not perfectly circular),
  366.      * none of the axes is perfectly aligned with velocity! The preferred name for this
  367.      * should be {@link #LVLH_CCSDS}.
  368.      * </p>
  369.      * <p>
  370.      * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames:
  371.      * <ul>
  372.      *   <li>X<sub>LVLH_CCSDS/VVLH</sub> =  Y<sub>QSW/LVLH</sub></li>
  373.      *   <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li>
  374.      *   <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li>
  375.      * </ul>
  376.      * @see #LVLH_CCSDS
  377.      */
  378.     VVLH {
  379.         /** {@inheritDoc} */
  380.         @Override
  381.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  382.             return LVLH_CCSDS.rotationFromInertial(pv);
  383.         }

  384.         /** {@inheritDoc} */
  385.         @Override
  386.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  387.                                                                                          final FieldPVCoordinates<T> pv) {
  388.             return LVLH_CCSDS.rotationFromInertial(field, pv);
  389.         }

  390.         /** {@inheritDoc} */
  391.         @Override
  392.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  393.             return OrbitRelativeFrame.LVLH;
  394.         }

  395.     },

  396.     /**
  397.      * Constant for Vehicle Velocity, Local Horizontal frame considered inertial (Z axis aligned with opposite of
  398.      * position, Y axis aligned with opposite of orbital momentum).
  399.      * <p>
  400.      * This is another name for {@link #LVLH_CCSDS}, kept here for compatibility with STK.
  401.      * </p>
  402.      * <p>
  403.      * Beware that the name is misleading: in the general case (i.e. not perfectly circular), none of the axes is
  404.      * perfectly aligned with velocity! The preferred name for this should be {@link #LVLH_CCSDS}.
  405.      * </p>
  406.      * <p>
  407.      * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames:
  408.      * <ul>
  409.      *   <li>X<sub>LVLH_CCSDS/VVLH</sub> =  Y<sub>QSW/LVLH</sub></li>
  410.      *   <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li>
  411.      *   <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li>
  412.      * </ul>
  413.      *
  414.      * @see #LVLH_CCSDS
  415.      */
  416.     VVLH_INERTIAL {
  417.         /** {@inheritDoc} */
  418.         @Override
  419.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  420.             return VVLH.rotationFromInertial(pv);
  421.         }

  422.         /** {@inheritDoc} */
  423.         @Override
  424.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  425.                                                                                          final FieldPVCoordinates<T> pv) {
  426.             return VVLH.rotationFromInertial(field, pv);
  427.         }

  428.         /** {@inheritDoc} */
  429.         @Override
  430.         public boolean isQuasiInertial() {
  431.             return true;
  432.         }

  433.         /** {@inheritDoc} */
  434.         @Override
  435.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  436.             return OrbitRelativeFrame.LVLH_INERTIAL;
  437.         }

  438.     },

  439.     /** Constant for Velocity - Normal - Co-normal frame
  440.      * (X axis aligned with velocity, Y axis aligned with orbital momentum).
  441.      * <p>
  442.      * The axes of this frame are parallel to the axes of the {@link #TNW}
  443.      * and {@link #NTW} frames:
  444.      * <ul>
  445.      *   <li>X<sub>VNC</sub> =  X<sub>TNW</sub> = Y<sub>NTW</sub></li>
  446.      *   <li>Y<sub>VNC</sub> =  Z<sub>TNW</sub> = Z<sub>NTW</sub></li>
  447.      *   <li>Z<sub>VNC</sub> = -Y<sub>TNW</sub> = X<sub>NTW</sub></li>
  448.      * </ul>
  449.      *
  450.      * @see #TNW
  451.      * @see #NTW
  452.      */
  453.     VNC {
  454.         /** {@inheritDoc} */
  455.         @Override
  456.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  457.             return new Rotation(pv.getVelocity(), pv.getMomentum(),
  458.                                 Vector3D.PLUS_I, Vector3D.PLUS_J);
  459.         }

  460.         /** {@inheritDoc} */
  461.         @Override
  462.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  463.                                                                                          final FieldPVCoordinates<T> pv) {
  464.             return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(),
  465.                                        new FieldVector3D<>(field, Vector3D.PLUS_I),
  466.                                        new FieldVector3D<>(field, Vector3D.PLUS_J));
  467.         }

  468.         /** {@inheritDoc} */
  469.         @Override
  470.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  471.             return OrbitRelativeFrame.VNC_ROTATING;
  472.         }

  473.     },

  474.     /**
  475.      * Constant for Velocity - Normal - Co-normal frame considered inertial (X axis aligned with velocity, Y axis
  476.      * aligned with orbital momentum).
  477.      * <p>
  478.      * The axes of this frame are parallel to the axes of the {@link #TNW} and {@link #NTW} frames:
  479.      * <ul>
  480.      *   <li>X<sub>VNC</sub> =  X<sub>TNW</sub> = Y<sub>NTW</sub></li>
  481.      *   <li>Y<sub>VNC</sub> =  Z<sub>TNW</sub> = Z<sub>NTW</sub></li>
  482.      *   <li>Z<sub>VNC</sub> = -Y<sub>TNW</sub> = X<sub>NTW</sub></li>
  483.      * </ul>
  484.      *
  485.      * @see #TNW
  486.      * @see #NTW
  487.      */
  488.     VNC_INERTIAL {
  489.         /** {@inheritDoc} */
  490.         @Override
  491.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  492.             return VNC.rotationFromInertial(pv);
  493.         }

  494.         /** {@inheritDoc} */
  495.         @Override
  496.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  497.                                                                                          final FieldPVCoordinates<T> pv) {
  498.             return VNC.rotationFromInertial(field, pv);
  499.         }

  500.         /** {@inheritDoc} */
  501.         @Override
  502.         public boolean isQuasiInertial() {
  503.             return true;
  504.         }

  505.         /** {@inheritDoc} */
  506.         @Override
  507.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  508.             return OrbitRelativeFrame.VNC_INERTIAL;
  509.         }

  510.     },

  511.     /**
  512.      * Constant for Equinoctial Coordinate System (X axis aligned with ascending node, Z axis aligned with orbital
  513.      * momentum).
  514.      *
  515.      * @since 11.0
  516.      */
  517.     EQW {
  518.         /** {@inheritDoc} */
  519.         @Override
  520.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  521.             final Vector3D m = pv.getMomentum();
  522.             return new Rotation(new Vector3D(-m.getY(), m.getX(), 0), m,
  523.                                 Vector3D.PLUS_I, Vector3D.PLUS_J);
  524.         }

  525.         /** {@inheritDoc} */
  526.         @Override
  527.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  528.                                                                                          final FieldPVCoordinates<T> pv) {
  529.             final FieldVector3D<T> m = pv.getMomentum();
  530.             return new FieldRotation<>(new FieldVector3D<>(m.getY().negate(), m.getX(), field.getZero()),
  531.                                        m,
  532.                                        new FieldVector3D<>(field, Vector3D.PLUS_I),
  533.                                        new FieldVector3D<>(field, Vector3D.PLUS_J));
  534.         }

  535.         /** {@inheritDoc} */
  536.         @Override
  537.         public boolean isQuasiInertial() {
  538.             return true;
  539.         }

  540.         /** {@inheritDoc} */
  541.         @Override
  542.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  543.             return OrbitRelativeFrame.EQW_INERTIAL;
  544.         }

  545.     },

  546.     /** Constant for Transverse Velocity Normal coordinate system
  547.      * (Y axis aligned with velocity, Z axis aligned with orbital momentum).
  548.      * <p>
  549.      * The axes of this frame are parallel to the axes of the {@link #TNW}
  550.      * and {@link #VNC} frames:
  551.      * <ul>
  552.      *   <li>X<sub>NTW</sub> = -Y<sub>TNW</sub> = Z<sub>VNC</sub></li>
  553.      *   <li>Y<sub>NTW</sub> =  X<sub>TNW</sub> = X<sub>VNC</sub></li>
  554.      *   <li>Z<sub>NTW</sub> =  Z<sub>TNW</sub> = Y<sub>VNC</sub></li>
  555.      * </ul>
  556.      * @see #TNW
  557.      * @see #VNC
  558.      * @since 11.0
  559.      */
  560.     NTW {
  561.         /** {@inheritDoc} */
  562.         @Override
  563.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  564.             return new Rotation(pv.getVelocity(), pv.getMomentum(),
  565.                                 Vector3D.PLUS_J, Vector3D.PLUS_K);
  566.         }

  567.         /** {@inheritDoc} */
  568.         @Override
  569.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  570.                                                                                          final FieldPVCoordinates<T> pv) {
  571.             return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(),
  572.                                        new FieldVector3D<>(field, Vector3D.PLUS_J),
  573.                                        new FieldVector3D<>(field, Vector3D.PLUS_K));
  574.         }

  575.         /** {@inheritDoc} */
  576.         @Override
  577.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  578.             return OrbitRelativeFrame.NTW_ROTATING;
  579.         }

  580.     },

  581.     /**
  582.      * Constant for Transverse Velocity Normal coordinate system considered inertial (Y axis aligned with velocity, Z
  583.      * axis aligned with orbital momentum).
  584.      * <p>
  585.      * The axes of this frame are parallel to the axes of the {@link #TNW} and {@link #VNC} frames:
  586.      * <ul>
  587.      *   <li>X<sub>NTW</sub> = -Y<sub>TNW</sub> = Z<sub>VNC</sub></li>
  588.      *   <li>Y<sub>NTW</sub> =  X<sub>TNW</sub> = X<sub>VNC</sub></li>
  589.      *   <li>Z<sub>NTW</sub> =  Z<sub>TNW</sub> = Y<sub>VNC</sub></li>
  590.      * </ul>
  591.      *
  592.      * @see #TNW
  593.      * @see #VNC
  594.      * @since 11.0
  595.      */
  596.     NTW_INERTIAL {
  597.         /** {@inheritDoc} */
  598.         @Override
  599.         public Rotation rotationFromInertial(final PVCoordinates pv) {
  600.             return NTW.rotationFromInertial(pv);
  601.         }

  602.         /** {@inheritDoc} */
  603.         @Override
  604.         public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  605.                                                                                          final FieldPVCoordinates<T> pv) {
  606.             return NTW.rotationFromInertial(field, pv);
  607.         }

  608.         /** {@inheritDoc} */
  609.         @Override
  610.         public boolean isQuasiInertial() {
  611.             return true;
  612.         }

  613.         /** {@inheritDoc} */
  614.         @Override
  615.         public OrbitRelativeFrame toOrbitRelativeFrame() {
  616.             return OrbitRelativeFrame.NTW_INERTIAL;
  617.         }

  618.     };

  619.     /** {@inheritDoc} */
  620.     public String getName() {
  621.         return this.name();
  622.     };

  623.     /**
  624.      * Get the rotation from input to output {@link LOFType local orbital frame}.
  625.      * <p>
  626.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  627.      * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, AbsoluteDate, PVCoordinates)} method must be called and
  628.      * the complete rotation transform must be extracted from it.
  629.      *
  630.      * @param in input commonly used local orbital frame
  631.      * @param out output commonly used local orbital frame
  632.      * @param pv position-velocity of the spacecraft in some inertial frame
  633.      *
  634.      * @return rotation from input to output local orbital frame
  635.      */
  636.     static Rotation rotationFromLOFInToLOFOut(final LOFType in, final LOFType out, final PVCoordinates pv) {
  637.         return out.rotationFromLOF(in, pv);
  638.     }

  639.     /**
  640.      * Get the rotation from input to output {@link LOFType local orbital frame}.
  641.      * <p>
  642.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  643.      * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, FieldAbsoluteDate, FieldPVCoordinates)}  method must be called and
  644.      * the complete rotation transform must be extracted from it.
  645.      *
  646.      * @param field field to which the elements belong
  647.      * @param in input commonly used local orbital frame
  648.      * @param out output commonly used local orbital frame
  649.      * @param pv position-velocity of the spacecraft in some inertial frame
  650.      * @param <T> type of the field elements
  651.      *
  652.      * @return rotation from input to output local orbital frame
  653.      */
  654.     static <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOFInToLOFOut(final Field<T> field,
  655.                                                                                           final LOFType in,
  656.                                                                                           final LOFType out,
  657.                                                                                           final FieldPVCoordinates<T> pv) {
  658.         return out.rotationFromLOF(field, in, pv);
  659.     }

  660.     /**
  661.      * Get the rotation from input {@link LOF local orbital frame} to the instance.
  662.      * <p>
  663.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  664.      * the full {@link #transformFromLOF(LOF, AbsoluteDate, PVCoordinates)} method must be called and the complete rotation
  665.      * transform must be extracted from it.
  666.      *
  667.      * @param fromLOF input local orbital frame
  668.      * @param pv position-velocity of the spacecraft in some inertial frame
  669.      *
  670.      * @return rotation from input local orbital frame to the instance
  671.      */
  672.     public Rotation rotationFromLOF(final LOFType fromLOF, final PVCoordinates pv) {

  673.         // First compute the rotation from the input LOF to the pivot inertial
  674.         final Rotation fromLOFToInertial = fromLOF.rotationFromInertial(pv).revert();

  675.         // Then compute the rotation from the pivot inertial to the output LOF
  676.         final Rotation inertialToThis = this.rotationFromInertial(pv);

  677.         // Output composed rotation
  678.         return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM);
  679.     }

  680.     /**
  681.      * Get the rotation from input {@link LOFType local orbital frame} to the instance.
  682.      * <p>
  683.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  684.      * the full {@link #transformFromLOF(LOF, FieldAbsoluteDate, FieldPVCoordinates)} method must be called and the complete
  685.      * rotation transform must be extracted from it.
  686.      *
  687.      * @param field field to which the elements belong
  688.      * @param fromLOF input local orbital frame
  689.      * @param pv position-velocity of the spacecraft in some inertial frame
  690.      * @param <T> type of the field elements
  691.      *
  692.      * @return rotation from input local orbital frame to the instance
  693.      */
  694.     public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOF(final Field<T> field,
  695.                                                                                 final LOFType fromLOF,
  696.                                                                                 final FieldPVCoordinates<T> pv) {

  697.         // First compute the rotation from the input LOF to the pivot inertial
  698.         final FieldRotation<T> fromLOFToInertial = fromLOF.rotationFromInertial(field, pv).revert();

  699.         // Then compute the rotation from the pivot inertial to the output LOF
  700.         final FieldRotation<T> inertialToThis = this.rotationFromInertial(field, pv);

  701.         // Output composed rotation
  702.         return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM);
  703.     }

  704.     /**
  705.      * {@inheritDoc} It is unnecessary to use this method when dealing with {@link LOFType}, use
  706.      * {@link #rotationFromInertial(PVCoordinates)} instead.
  707.      */
  708.     @Override
  709.     public Rotation rotationFromInertial(final AbsoluteDate date, final PVCoordinates pv) {
  710.         return rotationFromInertial(pv);
  711.     }

  712.     /**
  713.      * Get the rotation from inertial frame to local orbital frame.
  714.      * <p>
  715.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  716.      * the full {@link #transformFromInertial(AbsoluteDate, PVCoordinates)} method must be called and
  717.      * the complete rotation transform must be extracted from it.
  718.      * </p>
  719.      *
  720.      * @param pv position-velocity of the spacecraft in some inertial frame
  721.      *
  722.      * @return rotation from inertial frame to local orbital frame
  723.      */
  724.     public abstract Rotation rotationFromInertial(PVCoordinates pv);

  725.     /**
  726.      * {@inheritDoc} It is unnecessary to use this method when dealing with {@link LOFType}, use
  727.      * {@link #rotationFromInertial(Field, FieldPVCoordinates)} instead.
  728.      */
  729.     @Override
  730.     public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
  731.                                                                                      final FieldAbsoluteDate<T> date,
  732.                                                                                      final FieldPVCoordinates<T> pv) {
  733.         return rotationFromInertial(field, pv);
  734.     }

  735.     /**
  736.      * Get the rotation from inertial frame to local orbital frame.
  737.      * <p>
  738.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  739.      * the full {@link #transformFromInertial(FieldAbsoluteDate, FieldPVCoordinates)} method must be
  740.      * called and the complete rotation transform must be extracted from it.
  741.      * </p>
  742.      *
  743.      * @param field field to which the elements belong
  744.      * @param pv position-velocity of the spacecraft in some inertial frame
  745.      * @param <T> type of the field elements
  746.      *
  747.      * @return rotation from inertial frame to local orbital frame
  748.      */
  749.     public abstract <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(Field<T> field,
  750.                                                                                               FieldPVCoordinates<T> pv);

  751.     /**
  752.      * Convert current local orbital frame to CCSDS equivalent orbit relative frame when possible, null otherwise.
  753.      *
  754.      * @return CCSDS equivalent orbit relative frame when possible, null otherwise
  755.      *
  756.      * @see OrbitRelativeFrame
  757.      */
  758.     public abstract OrbitRelativeFrame toOrbitRelativeFrame();

  759. }