LOF.java

  1. /* Copyright 2002-2025 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.analysis.differentiation.FieldUnivariateDerivative2;
  21. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2Field;
  22. import org.hipparchus.analysis.differentiation.UnivariateDerivative2;
  23. import org.hipparchus.analysis.differentiation.UnivariateDerivative2Field;
  24. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  25. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  26. import org.hipparchus.geometry.euclidean.threed.Rotation;
  27. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  28. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.time.FieldAbsoluteDate;
  31. import org.orekit.utils.AngularCoordinates;
  32. import org.orekit.utils.FieldAngularCoordinates;
  33. import org.orekit.utils.FieldPVCoordinates;
  34. import org.orekit.utils.PVCoordinates;

  35. /**
  36.  * Interface for local orbital frame.
  37.  *
  38.  * @author Vincent Cucchietti
  39.  */
  40. public interface LOF {

  41.     /**
  42.      * Get the rotation from input to output {@link LOF local orbital frame}.
  43.      * <p>
  44.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  45.      * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, FieldAbsoluteDate, FieldPVCoordinates)} method must be called and
  46.      * the complete rotation transform must be extracted from it.
  47.      *
  48.      * @param field field to which the elements belong
  49.      * @param in input commonly used local orbital frame
  50.      * @param out output commonly used local orbital frame
  51.      * @param date date of the rotation
  52.      * @param pv position-velocity of the spacecraft in some inertial frame
  53.      * @param <T> type of the field elements
  54.      *
  55.      * @return rotation from input to output local orbital frame
  56.      *
  57.      * @since 11.3
  58.      */
  59.     static <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOFInToLOFOut(final Field<T> field,
  60.                                                                                           final LOF in, final LOF out,
  61.                                                                                           final FieldAbsoluteDate<T> date,
  62.                                                                                           final FieldPVCoordinates<T> pv) {
  63.         return out.rotationFromLOF(field, in, date, pv);
  64.     }

  65.     /**
  66.      * Get the transform from input to output {@link LOF local orbital frame}.
  67.      *
  68.      * @param in input commonly used local orbital frame
  69.      * @param out output commonly used local orbital frame
  70.      * @param date date of the transform
  71.      * @param pv position-velocity of the spacecraft in some inertial frame
  72.      * @param <T> type of the field elements
  73.      *
  74.      * @return rotation from input to output local orbital frame.
  75.      *
  76.      * @since 11.3
  77.      */
  78.     static <T extends CalculusFieldElement<T>> FieldTransform<T> transformFromLOFInToLOFOut(final LOF in, final LOF out,
  79.                                                                                             final FieldAbsoluteDate<T> date,
  80.                                                                                             final FieldPVCoordinates<T> pv) {
  81.         return out.transformFromLOF(in, date, pv);
  82.     }

  83.     /**
  84.      * Get the rotation from input to output {@link LOF local orbital frame}.
  85.      * <p>
  86.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  87.      * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, AbsoluteDate, PVCoordinates)}   method must be called and
  88.      * the complete rotation transform must be extracted from it.
  89.      *
  90.      * @param in input commonly used local orbital frame
  91.      * @param out output commonly used local orbital frame
  92.      * @param date date of the rotation
  93.      * @param pv position-velocity of the spacecraft in some inertial frame
  94.      *
  95.      * @return rotation from input to output local orbital frame.
  96.      *
  97.      * @since 11.3
  98.      */
  99.     static Rotation rotationFromLOFInToLOFOut(final LOF in, final LOF out, final AbsoluteDate date, final PVCoordinates pv) {
  100.         return out.rotationFromLOF(in, date, pv);
  101.     }

  102.     /**
  103.      * Get the transform from input to output {@link LOF local orbital frame}.
  104.      *
  105.      * @param in input commonly used local orbital frame
  106.      * @param out output commonly used local orbital frame
  107.      * @param date date of the transform
  108.      * @param pv position-velocity of the spacecraft in some inertial frame
  109.      *
  110.      * @return rotation from input to output local orbital frame
  111.      *
  112.      * @since 11.3
  113.      */
  114.     static Transform transformFromLOFInToLOFOut(final LOF in, final LOF out, final AbsoluteDate date,
  115.                                                 final PVCoordinates pv) {
  116.         return out.transformFromLOF(in, date, pv);
  117.     }

  118.     /**
  119.      * Get the rotation from input {@link LOF local orbital frame} to the instance.
  120.      * <p>
  121.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  122.      * the full {@link #transformFromLOF(LOF, FieldAbsoluteDate, FieldPVCoordinates)}   method must be called and
  123.      * the complete rotation transform must be extracted from it.
  124.      *
  125.      * @param field field to which the elements belong
  126.      * @param fromLOF input local orbital frame
  127.      * @param date date of the rotation
  128.      * @param pv position-velocity of the spacecraft in some inertial frame
  129.      * @param <T> type of the field elements
  130.      *
  131.      * @return rotation from input local orbital frame to the instance
  132.      *
  133.      * @since 11.3
  134.      */
  135.     default <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOF(final Field<T> field,
  136.                                                                                  final LOF fromLOF,
  137.                                                                                  final FieldAbsoluteDate<T> date,
  138.                                                                                  final FieldPVCoordinates<T> pv) {

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

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

  143.         // Output composed rotation
  144.         return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM);
  145.     }

  146.     /**
  147.      * Get the rotation from input {@link LOF commonly used local orbital frame} to the instance.
  148.      *
  149.      * @param fromLOF input local orbital frame
  150.      * @param date date of the transform
  151.      * @param pv position-velocity of the spacecraft in some inertial frame
  152.      * @param <T> type of the field elements
  153.      *
  154.      * @return rotation from input local orbital frame to the instance
  155.      *
  156.      * @since 11.3
  157.      */
  158.     default <T extends CalculusFieldElement<T>> FieldTransform<T> transformFromLOF(final LOF fromLOF,
  159.                                                                                    final FieldAbsoluteDate<T> date,
  160.                                                                                    final FieldPVCoordinates<T> pv) {

  161.         // Get transform from input local orbital frame to inertial
  162.         final FieldTransform<T> fromLOFToInertial = fromLOF.transformFromInertial(date, pv).getInverse();

  163.         // Get transform from inertial to output local orbital frame
  164.         final FieldTransform<T> inertialToLOFOut = this.transformFromInertial(date, pv);

  165.         // Output composition of both transforms
  166.         return new FieldTransform<>(date, fromLOFToInertial, inertialToLOFOut);
  167.     }

  168.     /**
  169.      * Get the transform from an inertial frame defining position-velocity and the local orbital frame.
  170.      *
  171.      * @param date current date
  172.      * @param pv position-velocity of the spacecraft in some inertial frame
  173.      * @param <T> type of the fields elements
  174.      *
  175.      * @return transform from the frame where position-velocity are defined to local orbital frame
  176.      *
  177.      * @since 9.0
  178.      */
  179.     default <T extends CalculusFieldElement<T>> FieldTransform<T> transformFromInertial(final FieldAbsoluteDate<T> date,
  180.                                                                                         final FieldPVCoordinates<T> pv) {
  181.         final Field<T> field = date.getField();
  182.         if (isQuasiInertial()) {
  183.             return new FieldTransform<>(date, pv.getPosition().negate(), rotationFromInertial(field, date, pv));

  184.         } else if (pv.getAcceleration().equals(FieldVector3D.getZero(field))) {
  185.             // we consider that the acceleration is not known
  186.             // compute the translation part of the transform
  187.             final FieldTransform<T> translation = new FieldTransform<>(date, pv.negate());

  188.             // compute the rotation part of the transform
  189.             final FieldRotation<T> r        = rotationFromInertial(date.getField(), date, pv);
  190.             final FieldVector3D<T> p        = pv.getPosition();
  191.             final FieldVector3D<T> momentum = pv.getMomentum();
  192.             final FieldTransform<T> rotation = new FieldTransform<>(date, r,
  193.                     new FieldVector3D<>(p.getNormSq().reciprocal(), r.applyTo(momentum)));

  194.             return new FieldTransform<>(date, translation, rotation);

  195.         } else {
  196.             // use automatic differentiation
  197.             // create date with independent variable
  198.             final FieldUnivariateDerivative2Field<T> fud2Field = FieldUnivariateDerivative2Field.getUnivariateDerivative2Field(field);
  199.             final FieldAbsoluteDate<FieldUnivariateDerivative2<T>> fud2Date = date.toFUD2Field();
  200.             // create PV with independent variable
  201.             final FieldPVCoordinates<FieldUnivariateDerivative2<T>> fud2PV = pv.toUnivariateDerivative2PV();
  202.             // compute rotation
  203.             final FieldRotation<FieldUnivariateDerivative2<T>> fud2Rotation = rotationFromInertial(fud2Field, fud2Date,
  204.                 fud2PV);
  205.             // turn into FieldTransform whilst adding the translation
  206.             final FieldAngularCoordinates<T> fieldAngularCoordinates = new FieldAngularCoordinates<>(fud2Rotation);
  207.             return new FieldTransform<>(date, new FieldTransform<>(date, pv.negate()),
  208.                 new FieldTransform<>(date, fieldAngularCoordinates));
  209.         }
  210.     }

  211.     /**
  212.      * Get the rotation from inertial frame to local orbital frame.
  213.      * <p>
  214.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  215.      * the full {@link #transformFromInertial(FieldAbsoluteDate, FieldPVCoordinates)} method must be
  216.      * called and the complete rotation transform must be extracted from it.
  217.      * </p>
  218.      *
  219.      * @param field field to which the elements belong
  220.      * @param date date of the rotation
  221.      * @param pv position-velocity of the spacecraft in some inertial frame
  222.      * @param <T> type of the field elements
  223.      *
  224.      * @return rotation from inertial frame to local orbital frame
  225.      *
  226.      * @since 9.0
  227.      */
  228.     <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(Field<T> field, FieldAbsoluteDate<T> date,
  229.                                                                               FieldPVCoordinates<T> pv);

  230.     /**
  231.      * Get the rotation from input {@link LOF local orbital frame} to the instance.
  232.      * <p>
  233.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  234.      * the full {@link #transformFromLOF(LOF, AbsoluteDate, PVCoordinates)}  method must be called and
  235.      * the complete rotation transform must be extracted from it.
  236.      *
  237.      * @param fromLOF input local orbital frame
  238.      * @param date date of the rotation
  239.      * @param pv position-velocity of the spacecraft in some inertial frame
  240.      *
  241.      * @return rotation from input local orbital frame to the instance
  242.      *
  243.      * @since 11.3
  244.      */
  245.     default Rotation rotationFromLOF(final LOF fromLOF, final AbsoluteDate date, final PVCoordinates pv) {

  246.         // First compute the rotation from the input LOF to the pivot inertial
  247.         final Rotation fromLOFToInertial = fromLOF.rotationFromInertial(date, pv).revert();

  248.         // Then compute the rotation from the pivot inertial to the output LOF
  249.         final Rotation inertialToThis = this.rotationFromInertial(date, pv);

  250.         // Output composed rotation
  251.         return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM);
  252.     }

  253.     /**
  254.      * Get the rotation from input {@link LOF local orbital frame} to the instance.
  255.      *
  256.      * @param fromLOF input local orbital frame
  257.      * @param date date of the transform
  258.      * @param pv position-velocity of the spacecraft in some inertial frame
  259.      *
  260.      * @return rotation from input local orbital frame to the instance
  261.      *
  262.      * @since 11.3
  263.      */
  264.     default Transform transformFromLOF(final LOF fromLOF, final AbsoluteDate date, final PVCoordinates pv) {

  265.         // First compute the rotation from the input LOF to the pivot inertial
  266.         final Transform fromLOFToInertial = fromLOF.transformFromInertial(date, pv).getInverse();

  267.         // Then compute the rotation from the pivot inertial to the output LOF
  268.         final Transform inertialToThis = this.transformFromInertial(date, pv);

  269.         // Output composed rotation
  270.         return new Transform(date, fromLOFToInertial, inertialToThis);
  271.     }

  272.     /**
  273.      * Get the transform from an inertial frame defining position-velocity and the local orbital frame.
  274.      *
  275.      * @param date current date
  276.      * @param pv position-velocity of the spacecraft in some inertial frame
  277.      *
  278.      * @return transform from the frame where position-velocity are defined to local orbital frame
  279.      */
  280.     default Transform transformFromInertial(final AbsoluteDate date, final PVCoordinates pv) {
  281.         if (isQuasiInertial()) {
  282.             return new Transform(date, pv.getPosition().negate(), rotationFromInertial(date, pv));

  283.         } else if (pv.getAcceleration().equals(Vector3D.ZERO)) {
  284.             // compute the rotation part of the transform assuming there is no known acceleration
  285.             final Rotation  r        = rotationFromInertial(date, pv);
  286.             final Vector3D  p        = pv.getPosition();
  287.             final Vector3D  momentum = pv.getMomentum();
  288.             final AngularCoordinates angularCoordinates = new AngularCoordinates(r,
  289.                 new Vector3D(1.0 / p.getNormSq(), r.applyTo(momentum)));

  290.             return new Transform(date, pv.negate(), angularCoordinates);

  291.         } else {
  292.             // use automatic differentiation
  293.             // create date with independent variable
  294.             final UnivariateDerivative2Field ud2Field = UnivariateDerivative2Field.getInstance();
  295.             final UnivariateDerivative2 dt = new UnivariateDerivative2(0, 1, 0);
  296.             final FieldAbsoluteDate<UnivariateDerivative2> ud2Date = new FieldAbsoluteDate<>(ud2Field, date).shiftedBy(dt);
  297.             // create PV with independent variable
  298.             final FieldPVCoordinates<UnivariateDerivative2> ud2PVCoordinates = pv.toUnivariateDerivative2PV();
  299.             // compute Field rotation
  300.             final FieldRotation<UnivariateDerivative2> ud2Rotation = rotationFromInertial(ud2Field, ud2Date,
  301.                 ud2PVCoordinates);
  302.             // turn into Transform whilst adding translation
  303.             final AngularCoordinates angularCoordinates = new AngularCoordinates(ud2Rotation);
  304.             return new Transform(date, pv.negate(), angularCoordinates);
  305.         }
  306.     }

  307.     /**
  308.      * Get the rotation from inertial frame to local orbital frame.
  309.      * <p>
  310.      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
  311.      * the full {@link #transformFromInertial(AbsoluteDate, PVCoordinates) transformFromInertial} method must be called and
  312.      * the complete rotation transform must be extracted from it.
  313.      *
  314.      * @param date date of the rotation
  315.      * @param pv position-velocity of the spacecraft in some inertial frame
  316.      *
  317.      * @return rotation from inertial frame to local orbital frame
  318.      */
  319.     Rotation rotationFromInertial(AbsoluteDate date, PVCoordinates pv);

  320.     /** Get flag that indicates if current local orbital frame shall be treated as pseudo-inertial.
  321.      * @return flag that indicates if current local orbital frame shall be treated as pseudo-inertial
  322.      */
  323.     default boolean isQuasiInertial() {
  324.         return false;
  325.     }

  326.     /** Get name of the local orbital frame.
  327.      * @return name of the local orbital frame
  328.      */
  329.     String getName();

  330. }