EquinoctialLongitudeArgumentUtility.java

  1. /* Copyright 2022-2025 Romain Serra
  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.orbits;

  18. import org.hipparchus.util.FastMath;
  19. import org.hipparchus.util.SinCos;
  20. import org.orekit.errors.OrekitException;
  21. import org.orekit.errors.OrekitInternalError;
  22. import org.orekit.errors.OrekitMessages;

  23. /**
  24.  * Utility methods for converting between different longitude arguments used by {@link EquinoctialOrbit}.
  25.  * @author Romain Serra
  26.  * @see EquinoctialOrbit
  27.  * @since 12.1
  28.  */
  29. public class EquinoctialLongitudeArgumentUtility {

  30.     /** Tolerance for stopping criterion in iterative conversion from mean to eccentric angle. */
  31.     private static final double TOLERANCE_CONVERGENCE = 1.0e-11;

  32.     /** Maximum number of iterations in iterative conversion from mean to eccentric angle. */
  33.     private static final int MAXIMUM_ITERATION = 50;

  34.     /** Private constructor for utility class. */
  35.     private EquinoctialLongitudeArgumentUtility() {
  36.         // nothing here (utils class)
  37.     }

  38.     /**
  39.      * Computes the true longitude argument from the eccentric longitude argument.
  40.      *
  41.      * @param ex e cos(ω), first component of eccentricity vector
  42.      * @param ey e sin(ω), second component of eccentricity vector
  43.      * @param lE = E + ω + Ω eccentric longitude argument (rad)
  44.      * @return the true longitude argument.
  45.      */
  46.     public static double eccentricToTrue(final double ex, final double ey, final double lE) {
  47.         final double epsilon = eccentricAndTrueEpsilon(ex, ey);
  48.         final SinCos scLE    = FastMath.sinCos(lE);
  49.         final double num     = ex * scLE.sin() - ey * scLE.cos();
  50.         final double den     = epsilon + 1 - ex * scLE.cos() - ey * scLE.sin();
  51.         return lE + eccentricAndTrueAtan(num, den);
  52.     }

  53.     /**
  54.      * Computes the eccentric longitude argument from the true longitude argument.
  55.      *
  56.      * @param ex e cos(ω), first component of eccentricity vector
  57.      * @param ey e sin(ω), second component of eccentricity vector
  58.      * @param lV = V + ω + Ω true longitude argument (rad)
  59.      * @return the eccentric longitude argument.
  60.      */
  61.     public static double trueToEccentric(final double ex, final double ey, final double lV) {
  62.         final double epsilon = eccentricAndTrueEpsilon(ex, ey);
  63.         final SinCos scLv    = FastMath.sinCos(lV);
  64.         final double num     = ey * scLv.cos() - ex * scLv.sin();
  65.         final double den     = epsilon + 1 + ex * scLv.cos() + ey * scLv.sin();
  66.         return lV + eccentricAndTrueAtan(num, den);
  67.     }

  68.     /**
  69.      * Computes an intermediate quantity for conversions between true and eccentric.
  70.      *
  71.      * @param ex e cos(ω), first component of eccentricity vector
  72.      * @param ey e sin(ω), second component of eccentricity vector
  73.      * @return intermediate variable referred to as epsilon.
  74.      */
  75.     private static double eccentricAndTrueEpsilon(final double ex, final double ey) {
  76.         return FastMath.sqrt(1 - ex * ex - ey * ey);
  77.     }

  78.     /**
  79.      * Computes another intermediate quantity for conversions between true and eccentric.
  80.      *
  81.      * @param num numerator for angular conversion
  82.      * @param den denominator for angular conversion
  83.      * @return arc-tangent of ratio of inputs times two.
  84.      */
  85.     private static double eccentricAndTrueAtan(final double num, final double den) {
  86.         return 2. * FastMath.atan(num / den);
  87.     }

  88.     /**
  89.      * Computes the eccentric longitude argument from the mean longitude argument.
  90.      *
  91.      * @param ex e cos(ω), first component of eccentricity vector
  92.      * @param ey e sin(ω), second component of eccentricity vector
  93.      * @param lM = M + ω + Ω  mean longitude argument (rad)
  94.      * @return the eccentric longitude argument.
  95.      */
  96.     public static double meanToEccentric(final double ex, final double ey, final double lM) {
  97.         // Generalization of Kepler equation to equinoctial parameters
  98.         // with lE = PA + RAAN + E and
  99.         //      lM = PA + RAAN + M = lE - ex.sin(lE) + ey.cos(lE)
  100.         double lE = lM;
  101.         double shift;
  102.         double lEmlM = 0.0;
  103.         boolean hasConverged;
  104.         int iter = 0;
  105.         do {
  106.             final SinCos scLE  = FastMath.sinCos(lE);
  107.             final double f2 = ex * scLE.sin() - ey * scLE.cos();
  108.             final double f1 = 1.0 - ex * scLE.cos() - ey * scLE.sin();
  109.             final double f0 = lEmlM - f2;

  110.             final double f12 = 2.0 * f1;
  111.             shift = f0 * f12 / (f1 * f12 - f0 * f2);

  112.             lEmlM -= shift;
  113.             lE     = lM + lEmlM;

  114.             hasConverged = FastMath.abs(shift) <= TOLERANCE_CONVERGENCE;
  115.         } while (++iter < MAXIMUM_ITERATION && !hasConverged);

  116.         if (!hasConverged) {
  117.             throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT, iter);
  118.         }
  119.         return lE;

  120.     }

  121.     /**
  122.      * Computes the mean longitude argument from the eccentric longitude argument.
  123.      *
  124.      * @param ex e cos(ω), first component of eccentricity vector
  125.      * @param ey e sin(ω), second component of eccentricity vector
  126.      * @param lE = E + ω + Ω  mean longitude argument (rad)
  127.      * @return the mean longitude argument.
  128.      */
  129.     public static double eccentricToMean(final double ex, final double ey, final double lE) {
  130.         final SinCos scLE = FastMath.sinCos(lE);
  131.         return lE - ex * scLE.sin() + ey * scLE.cos();
  132.     }

  133.     /**
  134.      * Computes the mean longitude argument from the eccentric longitude argument.
  135.      *
  136.      * @param ex e cos(ω), first component of eccentricity vector
  137.      * @param ey e sin(ω), second component of eccentricity vector
  138.      * @param lV = V + ω + Ω  true longitude argument (rad)
  139.      * @return the mean longitude argument.
  140.      */
  141.     public static double trueToMean(final double ex, final double ey, final double lV) {
  142.         final double lE = trueToEccentric(ex, ey, lV);
  143.         return eccentricToMean(ex, ey, lE);
  144.     }

  145.     /**
  146.      * Computes the true longitude argument from the eccentric longitude argument.
  147.      *
  148.      * @param ex e cos(ω), first component of eccentricity vector
  149.      * @param ey e sin(ω), second component of eccentricity vector
  150.      * @param lM = M + ω + Ω  mean longitude argument (rad)
  151.      * @return the true longitude argument.
  152.      */
  153.     public static double meanToTrue(final double ex, final double ey, final double lM) {
  154.         final double lE = meanToEccentric(ex, ey, lM);
  155.         return eccentricToTrue(ex, ey, lE);
  156.     }

  157.     /**
  158.      * Convert argument of longitude.
  159.      * @param oldType old position angle type
  160.      * @param l old value for argument of longitude
  161.      * @param ex ex
  162.      * @param ey ey
  163.      * @param newType new position angle type
  164.      * @return converted argument of longitude
  165.      * @since 12.2
  166.      */
  167.     public static double convertL(final PositionAngleType oldType, final double l, final double ex,
  168.                                   final double ey, final PositionAngleType newType) {
  169.         if (oldType == newType) {
  170.             return l;

  171.         } else {
  172.             switch (newType) {

  173.                 case ECCENTRIC:
  174.                     if (oldType == PositionAngleType.MEAN) {
  175.                         return EquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, l);
  176.                     } else {
  177.                         return EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, l);
  178.                     }

  179.                 case MEAN:
  180.                     if (oldType == PositionAngleType.TRUE) {
  181.                         return EquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, l);
  182.                     } else {
  183.                         return EquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, l);
  184.                     }

  185.                 case TRUE:
  186.                     if (oldType == PositionAngleType.MEAN) {
  187.                         return EquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, l);
  188.                     } else {
  189.                         return EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, l);
  190.                     }

  191.                 default:
  192.                     throw new OrekitInternalError(null);
  193.             }
  194.         }
  195.     }
  196. }