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