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  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
22  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
23  import org.hipparchus.geometry.euclidean.threed.Rotation;
24  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.time.FieldAbsoluteDate;
28  import org.orekit.utils.FieldPVCoordinates;
29  import org.orekit.utils.PVCoordinates;
30  
31  /**
32   * Interface for local orbital frame.
33   *
34   * @author Vincent Cucchietti
35   */
36  public interface LOF {
37  
38      /**
39       * Get the rotation from input to output {@link LOF local orbital frame}.
40       * <p>
41       * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
42       * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, FieldAbsoluteDate, FieldPVCoordinates)} method must be called and
43       * the complete rotation transform must be extracted from it.
44       *
45       * @param field field to which the elements belong
46       * @param in input commonly used local orbital frame
47       * @param out output commonly used local orbital frame
48       * @param date date of the rotation
49       * @param pv position-velocity of the spacecraft in some inertial frame
50       * @param <T> type of the field elements
51       *
52       * @return rotation from input to output local orbital frame
53       *
54       * @since 11.3
55       */
56      static <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOFInToLOFOut(final Field<T> field,
57                                                                                            final LOF in, final LOF out,
58                                                                                            final FieldAbsoluteDate<T> date,
59                                                                                            final FieldPVCoordinates<T> pv) {
60          return out.rotationFromLOF(field, in, date, pv);
61      }
62  
63      /**
64       * Get the transform from input to output {@link LOF local orbital frame}.
65       *
66       * @param in input commonly used local orbital frame
67       * @param out output commonly used local orbital frame
68       * @param date date of the transform
69       * @param pv position-velocity of the spacecraft in some inertial frame
70       * @param <T> type of the field elements
71       *
72       * @return rotation from input to output local orbital frame.
73       *
74       * @since 11.3
75       */
76      static <T extends CalculusFieldElement<T>> FieldTransform<T> transformFromLOFInToLOFOut(final LOF in, final LOF out,
77                                                                                              final FieldAbsoluteDate<T> date,
78                                                                                              final FieldPVCoordinates<T> pv) {
79          return out.transformFromLOF(in, date, pv);
80      }
81  
82      /**
83       * Get the rotation from input to output {@link LOF local orbital frame}.
84       * <p>
85       * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
86       * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, AbsoluteDate, PVCoordinates)}   method must be called and
87       * the complete rotation transform must be extracted from it.
88       *
89       * @param in input commonly used local orbital frame
90       * @param out output commonly used local orbital frame
91       * @param date date of the rotation
92       * @param pv position-velocity of the spacecraft in some inertial frame
93       *
94       * @return rotation from input to output local orbital frame.
95       *
96       * @since 11.3
97       */
98      static Rotation rotationFromLOFInToLOFOut(final LOF in, final LOF out, final AbsoluteDate date, final PVCoordinates pv) {
99          return out.rotationFromLOF(in, date, pv);
100     }
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     /**
120      * Get the rotation from input {@link LOF local orbital frame} to the instance.
121      * <p>
122      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
123      * the full {@link #transformFromLOF(LOF, FieldAbsoluteDate, FieldPVCoordinates)}   method must be called and
124      * the complete rotation transform must be extracted from it.
125      *
126      * @param field field to which the elements belong
127      * @param fromLOF input local orbital frame
128      * @param date date of the rotation
129      * @param pv position-velocity of the spacecraft in some inertial frame
130      * @param <T> type of the field elements
131      *
132      * @return rotation from input local orbital frame to the instance
133      *
134      * @since 11.3
135      */
136     default <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOF(final Field<T> field,
137                                                                                  final LOF fromLOF,
138                                                                                  final FieldAbsoluteDate<T> date,
139                                                                                  final FieldPVCoordinates<T> pv) {
140 
141         // First compute the rotation from the input LOF to the pivot inertial
142         final FieldRotation<T> fromLOFToInertial = fromLOF.rotationFromInertial(field, date, pv).revert();
143 
144         // Then compute the rotation from the pivot inertial to the output LOF
145         final FieldRotation<T> inertialToThis = this.rotationFromInertial(field, date, pv);
146 
147         // Output composed rotation
148         return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM);
149     }
150 
151     /**
152      * Get the rotation from input {@link LOF commonly used local orbital frame} to the instance.
153      *
154      * @param fromLOF input local orbital frame
155      * @param date date of the transform
156      * @param pv position-velocity of the spacecraft in some inertial frame
157      * @param <T> type of the field elements
158      *
159      * @return rotation from input local orbital frame to the instance
160      *
161      * @since 11.3
162      */
163     default <T extends CalculusFieldElement<T>> FieldTransform<T> transformFromLOF(final LOF fromLOF,
164                                                                                    final FieldAbsoluteDate<T> date,
165                                                                                    final FieldPVCoordinates<T> pv) {
166 
167         // Get transform from input local orbital frame to inertial
168         final FieldTransform<T> fromLOFToInertial = fromLOF.transformFromInertial(date, pv).getInverse();
169 
170         // Get transform from inertial to output local orbital frame
171         final FieldTransform<T> inertialToLOFOut = this.transformFromInertial(date, pv);
172 
173         // Output composition of both transforms
174         return new FieldTransform<>(date, fromLOFToInertial, inertialToLOFOut);
175     }
176 
177     /**
178      * Get the transform from an inertial frame defining position-velocity and the local orbital frame.
179      *
180      * @param date current date
181      * @param pv position-velocity of the spacecraft in some inertial frame
182      * @param <T> type of the fields elements
183      *
184      * @return transform from the frame where position-velocity are defined to local orbital frame
185      *
186      * @since 9.0
187      */
188     default <T extends CalculusFieldElement<T>> FieldTransform<T> transformFromInertial(final FieldAbsoluteDate<T> date,
189                                                                                         final FieldPVCoordinates<T> pv) {
190 
191         // compute the translation part of the transform
192         final FieldTransform<T> translation = new FieldTransform<>(date, pv.negate());
193 
194         // compute the rotation part of the transform
195         final FieldRotation<T> r        = rotationFromInertial(date.getField(), date, pv);
196         final FieldVector3D<T> p        = pv.getPosition();
197         final FieldVector3D<T> momentum = pv.getMomentum();
198         final FieldTransform<T> rotation = new FieldTransform<>(date, r,
199                                                                 new FieldVector3D<>(p.getNormSq().reciprocal(),
200                                                                                     r.applyTo(momentum)));
201 
202         final FieldTransform<T> transform = new FieldTransform<>(date, translation, rotation);
203 
204         // If LOF is considered pseudo-inertial, freeze transform
205         return isQuasiInertial() ? transform.freeze() : transform;
206 
207     }
208 
209     /**
210      * Get the rotation from inertial frame to local orbital frame.
211      * <p>
212      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
213      * the full {@link #transformFromInertial(FieldAbsoluteDate, FieldPVCoordinates)} method must be
214      * called and the complete rotation transform must be extracted from it.
215      * </p>
216      *
217      * @param field field to which the elements belong
218      * @param date date of the rotation
219      * @param pv position-velocity of the spacecraft in some inertial frame
220      * @param <T> type of the field elements
221      *
222      * @return rotation from inertial frame to local orbital frame
223      *
224      * @since 9.0
225      */
226     <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(Field<T> field, FieldAbsoluteDate<T> date,
227                                                                               FieldPVCoordinates<T> pv);
228 
229     /**
230      * Get the rotation from input {@link LOF local orbital frame} to the instance.
231      * <p>
232      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
233      * the full {@link #transformFromLOF(LOF, AbsoluteDate, PVCoordinates)}  method must be called and
234      * the complete rotation transform must be extracted from it.
235      *
236      * @param fromLOF input local orbital frame
237      * @param date date of the rotation
238      * @param pv position-velocity of the spacecraft in some inertial frame
239      *
240      * @return rotation from input local orbital frame to the instance
241      *
242      * @since 11.3
243      */
244     default Rotation rotationFromLOF(final LOF fromLOF, final AbsoluteDate date, final PVCoordinates pv) {
245 
246         // First compute the rotation from the input LOF to the pivot inertial
247         final Rotation fromLOFToInertial = fromLOF.rotationFromInertial(date, pv).revert();
248 
249         // Then compute the rotation from the pivot inertial to the output LOF
250         final Rotation inertialToThis = this.rotationFromInertial(date, pv);
251 
252         // Output composed rotation
253         return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM);
254     }
255 
256     /**
257      * Get the rotation from input {@link LOF local orbital frame} to the instance.
258      *
259      * @param fromLOF input local orbital frame
260      * @param date date of the transform
261      * @param pv position-velocity of the spacecraft in some inertial frame
262      *
263      * @return rotation from input local orbital frame to the instance
264      *
265      * @since 11.3
266      */
267     default Transform transformFromLOF(final LOF fromLOF, final AbsoluteDate date, final PVCoordinates pv) {
268 
269         // First compute the rotation from the input LOF to the pivot inertial
270         final Transform fromLOFToInertial = fromLOF.transformFromInertial(date, pv).getInverse();
271 
272         // Then compute the rotation from the pivot inertial to the output LOF
273         final Transform inertialToThis = this.transformFromInertial(date, pv);
274 
275         // Output composed rotation
276         return new Transform(date, fromLOFToInertial, inertialToThis);
277     }
278 
279     /**
280      * Get the transform from an inertial frame defining position-velocity and the local orbital frame.
281      *
282      * @param date current date
283      * @param pv position-velocity of the spacecraft in some inertial frame
284      *
285      * @return transform from the frame where position-velocity are defined to local orbital frame
286      */
287     default Transform transformFromInertial(final AbsoluteDate date, final PVCoordinates pv) {
288 
289         // compute the translation part of the transform
290         final Transform translation = new Transform(date, pv.negate());
291 
292         // compute the rotation part of the transform
293         final Rotation  r        = rotationFromInertial(date, pv);
294         final Vector3D  p        = pv.getPosition();
295         final Vector3D  momentum = pv.getMomentum();
296         final Transform rotation = new Transform(date, r, new Vector3D(1.0 / p.getNormSq(), r.applyTo(momentum)));
297 
298         final Transform transform = new Transform(date, translation, rotation);
299 
300         // If LOF is considered pseudo-inertial, freeze transform
301         return isQuasiInertial() ? transform.freeze() : transform;
302 
303     }
304 
305     /**
306      * Get the rotation from inertial frame to local orbital frame.
307      * <p>
308      * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well,
309      * the full {@link #transformFromInertial(AbsoluteDate, PVCoordinates) transformFromInertial} method must be called and
310      * the complete rotation transform must be extracted from it.
311      *
312      * @param date date of the rotation
313      * @param pv position-velocity of the spacecraft in some inertial frame
314      *
315      * @return rotation from inertial frame to local orbital frame
316      */
317     Rotation rotationFromInertial(AbsoluteDate date, PVCoordinates pv);
318 
319     /** Get flag that indicates if current local orbital frame shall be treated as pseudo-inertial.
320      * @return flag that indicates if current local orbital frame shall be treated as pseudo-inertial
321      */
322     default boolean isQuasiInertial() {
323         return false;
324     }
325 
326     /** Get name of the local orbital frame.
327      * @return name of the local orbital frame
328      */
329     String getName();
330 
331 }