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.bodies;
18  
19  
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.orekit.frames.FieldStaticTransform;
24  import org.orekit.frames.FieldTransform;
25  import org.orekit.frames.Frame;
26  import org.orekit.frames.KinematicTransform;
27  import org.orekit.frames.StaticTransform;
28  import org.orekit.frames.Transform;
29  import org.orekit.time.AbsoluteDate;
30  import org.orekit.time.FieldAbsoluteDate;
31  import org.orekit.utils.FieldPVCoordinates;
32  import org.orekit.utils.PVCoordinates;
33  import org.orekit.utils.TimeStampedFieldPVCoordinates;
34  import org.orekit.utils.TimeStampedPVCoordinates;
35  
36  /** Implementation of the {@link CelestialBody} interface using JPL or INPOP ephemerides.
37   * @author Luc Maisonobe
38   */
39  class JPLCelestialBody implements CelestialBody {
40  
41      /** Name of the body. */
42      private final String name;
43  
44      /** Regular expression for supported files names. */
45      private final String supportedNames;
46  
47      /** Ephemeris type to generate. */
48      private final JPLEphemeridesLoader.EphemerisType generateType;
49  
50      /** Raw position-velocity provider. */
51      private final transient JPLEphemeridesLoader.RawPVProvider rawPVProvider;
52  
53      /** Attraction coefficient of the body (m³/s²). */
54      private final double gm;
55  
56      /** Scaling factor for position-velocity. */
57      private final double scale;
58  
59      /** IAU pole. */
60      private final IAUPole iauPole;
61  
62      /** Inertially oriented, body-centered frame. */
63      private final Frame inertialFrame;
64  
65      /** Body oriented, body-centered frame. */
66      private final Frame bodyFrame;
67  
68      /** Build an instance and the underlying frame.
69       * @param name name of the body
70       * @param supportedNames regular expression for supported files names
71       * @param generateType ephemeris type to generate
72       * @param rawPVProvider raw position-velocity provider
73       * @param gm attraction coefficient (in m³/s²)
74       * @param scale scaling factor for position-velocity
75       * @param iauPole IAU pole implementation
76       * @param definingFrameAlignedWithICRF frame in which celestial body coordinates are defined,
77       * this frame <strong>must</strong> be aligned with ICRF
78       * @param inertialFrameName name to use for inertial frame (if null a default name will be built)
79       * @param bodyOrientedFrameName name to use for body-oriented frame (if null a default name will be built)
80       */
81      JPLCelestialBody(final String name, final String supportedNames,
82                       final JPLEphemeridesLoader.EphemerisType generateType,
83                       final JPLEphemeridesLoader.RawPVProvider rawPVProvider,
84                       final double gm, final double scale,
85                       final IAUPole iauPole, final Frame definingFrameAlignedWithICRF,
86                       final String inertialFrameName, final String bodyOrientedFrameName) {
87          this.name           = name;
88          this.gm             = gm;
89          this.scale          = scale;
90          this.supportedNames = supportedNames;
91          this.generateType   = generateType;
92          this.rawPVProvider  = rawPVProvider;
93          this.iauPole        = iauPole;
94          this.inertialFrame  = new InertiallyOriented(new JPLInertialTransformProvider(definingFrameAlignedWithICRF, this, iauPole),
95                  inertialFrameName);
96          this.bodyFrame      = new BodyOriented(bodyOrientedFrameName, new JPLRotatingTransformProvider(iauPole));
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
102 
103         // apply the scale factor to raw position-velocity
104         final PVCoordinates rawPV    = rawPVProvider.getRawPV(date);
105         final TimeStampedPVCoordinates scaledPV = new TimeStampedPVCoordinates(date, scale, rawPV);
106 
107         // the raw PV are relative to the parent of the body centered inertially oriented frame
108         final Transform transform = getInertiallyOrientedFrame().getParent().getTransformTo(frame, date);
109 
110         // convert to requested frame
111         return transform.transformPVCoordinates(scaledPV);
112 
113     }
114 
115     /** Get the {@link FieldPVCoordinates} of the body in the selected frame.
116      * @param date current date
117      * @param frame the frame where to define the position
118      * @param <T> type of the field elements
119      * @return time-stamped position/velocity of the body (m and m/s)
120      */
121     @Override
122     public <T extends CalculusFieldElement<T>> TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date,
123                                                                                                  final Frame frame) {
124 
125         // apply the scale factor to raw position-velocity
126         final FieldPVCoordinates<T>            rawPV    = rawPVProvider.getRawPV(date);
127         final TimeStampedFieldPVCoordinates<T> scaledPV = new TimeStampedFieldPVCoordinates<>(date, scale, rawPV);
128 
129         // the raw PV are relative to the parent of the body centered inertially oriented frame
130         final FieldTransform<T> transform = getInertiallyOrientedFrame().getParent().getTransformTo(frame, date);
131 
132         // convert to requested frame
133         return transform.transformPVCoordinates(scaledPV);
134 
135     }
136 
137     /** {@inheritDoc} */
138     @Override
139     public Vector3D getVelocity(final AbsoluteDate date, final Frame frame) {
140 
141         // apply the scale factor to raw position-velocity
142         final PVCoordinates rawPV    = rawPVProvider.getRawPV(date);
143         final TimeStampedPVCoordinates scaledPV = new TimeStampedPVCoordinates(date, scale, rawPV);
144 
145         // the raw PV are relative to the parent of the body centered inertially oriented frame
146         final KinematicTransform transform = getInertiallyOrientedFrame().getParent().getKinematicTransformTo(frame, date);
147 
148         // convert to requested frame
149         return transform.transformOnlyPV(scaledPV).getVelocity();
150 
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public Vector3D getPosition(final AbsoluteDate date, final Frame frame) {
156 
157         // apply the scale factor to raw position
158         final Vector3D rawPosition    = rawPVProvider.getRawPosition(date);
159         final Vector3D scaledPosition = rawPosition.scalarMultiply(scale);
160 
161         // the raw position is relative to the parent of the body centered inertially oriented frame
162         final StaticTransform transform = getInertiallyOrientedFrame().getParent().getStaticTransformTo(frame, date);
163 
164         // convert to requested frame
165         return transform.transformPosition(scaledPosition);
166     }
167 
168     /** {@inheritDoc} */
169     @Override
170     public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPosition(final FieldAbsoluteDate<T> date, final Frame frame) {
171 
172         // apply the scale factor to raw position
173         final FieldVector3D<T> rawPosition     = rawPVProvider.getRawPosition(date);
174         final FieldVector3D<T> scaledPosition  = rawPosition.scalarMultiply(scale);
175 
176         // the raw position is relative to the parent of the body centered inertially oriented frame
177         final FieldStaticTransform<T> transform = getInertiallyOrientedFrame().getParent().getStaticTransformTo(frame, date);
178 
179         // convert to requested frame
180         return transform.transformPosition(scaledPosition);
181     }
182 
183     /** {@inheritDoc} */
184     public String getName() {
185         return name;
186     }
187 
188     /** {@inheritDoc} */
189     public double getGM() {
190         return gm;
191     }
192 
193     /** {@inheritDoc} */
194     public Frame getInertiallyOrientedFrame() {
195         return inertialFrame;
196     }
197 
198     /** {@inheritDoc} */
199     public Frame getBodyOrientedFrame() {
200         return bodyFrame;
201     }
202 
203     /** Inertially oriented body centered frame. */
204     private class InertiallyOriented extends Frame {
205 
206         /** Suffix for inertial frame name. */
207         private static final String INERTIAL_FRAME_SUFFIX = "/inertial";
208 
209         /** Simple constructor.
210          * @param transformProvider transform provider to frame in which celestial body coordinates are defined
211          * @param frameName name to use (if null a default name will be built)
212          */
213         InertiallyOriented(final JPLInertialTransformProvider transformProvider, final String frameName) {
214             super(transformProvider.getDefiningFrame(), transformProvider, frameName == null ? name + INERTIAL_FRAME_SUFFIX : frameName, true);
215         }
216 
217     }
218 
219     /** Body oriented body centered frame. */
220     private class BodyOriented extends Frame {
221 
222         /**
223          * Suffix for body frame name.
224          */
225         private static final String BODY_FRAME_SUFFIX = "/rotating";
226 
227         /**
228          * Simple constructor.
229          *
230          * @param frameName name to use (if null a default name will be built)
231          * @param transformProvider transform provider to body-fixed frame
232          */
233         BodyOriented(final String frameName, final JPLRotatingTransformProvider transformProvider) {
234             super(inertialFrame, transformProvider, frameName == null ? name + BODY_FRAME_SUFFIX : frameName, false);
235         }
236     }
237 }