1   /* Copyright 2022-2026 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  
19  import org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.hipparchus.util.FastMath;
21  import org.hipparchus.util.SinCos;
22  import org.orekit.errors.OrekitIllegalArgumentException;
23  import org.orekit.errors.OrekitMessages;
24  import org.orekit.utils.PVCoordinates;
25  
26  /**
27   * Class for converting between equinoctial elements and Cartesian coordinates.
28   * @author Romain Serra
29   * @see EquinoctialParameters
30   * @since 14.0
31   */
32  public class EquinoctialParametersConverter {
33  
34      /** Central body gravitational parameter. */
35      private final double mu;
36  
37      /**
38       * Constructor.
39       * @param mu central body gravitational parameter
40       */
41      public EquinoctialParametersConverter(final double mu) {
42          this.mu = mu;
43      }
44  
45      /**
46       * Convert Cartesian coordinates to equinoctial elements.
47       * @param cartesian position and velocity in inertial frame
48       * @param positionAngleType type of position angle to use
49       * @return equinoctial elements
50       */
51      public EquinoctialParameters toParameters(final PVCoordinates cartesian, final PositionAngleType positionAngleType) {
52          //  compute semi-major axis
53          final Vector3D pvP   = cartesian.getPosition();
54          final Vector3D pvV   = cartesian.getVelocity();
55          final double r2      = pvP.getNorm2Sq();
56          final double r       = FastMath.sqrt(r2);
57          final double V2      = pvV.getNorm2Sq();
58          final double rV2OnMu = r * V2 / mu;
59  
60          // compute semi-major axis
61          final double a = r / (2 - rV2OnMu);
62  
63          if (a <= 0.) {
64              throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
65                      getClass().getName());
66          }
67  
68          // compute inclination vector
69          final Vector3D w = cartesian.getMomentum().normalize();
70          final double d = 1.0 / (1 + w.getZ());
71          final double hx = -d * w.getY();
72          final double hy =  d * w.getX();
73  
74          // compute true longitude argument
75          final double cLv = (pvP.getX() - d * pvP.getZ() * w.getX()) / r;
76          final double sLv = (pvP.getY() - d * pvP.getZ() * w.getY()) / r;
77          final double lV = FastMath.atan2(sLv, cLv);
78  
79          // compute eccentricity vector
80          final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(mu * a);
81          final double eCE = rV2OnMu - 1;
82          final double e2  = eCE * eCE + eSE * eSE;
83          final double f   = eCE - e2;
84          final double g   = FastMath.sqrt(1 - e2) * eSE;
85          final double ex = a * (f * cLv + g * sLv) / r;
86          final double ey = a * (f * sLv - g * cLv) / r;
87  
88          final EquinoctialParameters elements = new EquinoctialParameters(a, ex, ey, hx, hy, lV, PositionAngleType.TRUE);
89          return positionAngleType == PositionAngleType.TRUE ? elements : elements.withPositionAngleType(positionAngleType);
90      }
91  
92      /**
93       * Convert equinoctial elements to Cartesian coordinates.
94       * @param elements equinoctial elements
95       * @return position and velocity in inertial frame
96       */
97      public PVCoordinates toCartesian(final EquinoctialParameters elements) {
98          // get equinoctial parameters
99          final double a = elements.a();
100         final double ex = elements.ex();
101         final double ey = elements.ey();
102         final double hx = elements.hx();
103         final double hy = elements.hy();
104         final double lE = elements.positionAngleType() == PositionAngleType.ECCENTRIC ? elements.longitudeArgument() :
105                 elements.withPositionAngleType(PositionAngleType.ECCENTRIC).longitudeArgument();
106 
107         // inclination-related intermediate parameters
108         final double hx2   = hx * hx;
109         final double hy2   = hy * hy;
110         final double factH = 1. / (1 + hx2 + hy2);
111 
112         // reference axes defining the orbital plane
113         final double ux = (1 + hx2 - hy2) * factH;
114         final double uy =  2 * hx * hy * factH;
115         final double uz = -2 * hy * factH;
116 
117         final double vx = uy;
118         final double vy = (1 - hx2 + hy2) * factH;
119         final double vz =  2 * hx * factH;
120 
121         // eccentricity-related intermediate parameters
122         final double exey = ex * ey;
123         final double ex2  = ex * ex;
124         final double ey2  = ey * ey;
125         final double e2   = ex2 + ey2;
126         final double eta  = 1 + FastMath.sqrt(1 - e2);
127         final double beta = 1. / eta;
128 
129         // eccentric longitude argument
130         final SinCos scLe   = FastMath.sinCos(lE);
131         final double cLe    = scLe.cos();
132         final double sLe    = scLe.sin();
133         final double exCeyS = ex * cLe + ey * sLe;
134 
135         // coordinates of position and velocity in the orbital plane
136         final double x      = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - ex);
137         final double y      = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - ey);
138 
139         final double factor = FastMath.sqrt(mu / a) / (1 - exCeyS);
140         final double xdot   = factor * (-sLe + beta * ey * exCeyS);
141         final double ydot   = factor * ( cLe - beta * ex * exCeyS);
142 
143         final Vector3D position =
144                 new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
145         final Vector3D velocity =
146                 new Vector3D(xdot * ux + ydot * vx, xdot * uy + ydot * vy, xdot * uz + ydot * vz);
147         return new PVCoordinates(position, velocity);
148     }
149 }