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.frames;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.geometry.euclidean.threed.FieldLine;
22  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Line;
25  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
26  import org.hipparchus.geometry.euclidean.threed.Vector3D;
27  import org.orekit.time.AbsoluteDate;
28  import org.orekit.time.FieldAbsoluteDate;
29  import org.orekit.time.TimeStamped;
30  
31  /**
32   * A transform that only includes translation and rotation. It is static in the
33   * sense that no rates thereof are included.
34   *
35   * @param <T> the type of the field elements
36   * @author Bryan Cazabonne
37   * @see FieldTransform
38   * @since 12.0
39   */
40  public interface FieldStaticTransform<T extends CalculusFieldElement<T>> extends TimeStamped {
41  
42      /**
43       * Get the identity static transform.
44       * Override methods for speed.
45       *
46       * @param <T> type of the elements
47       * @param field field used by default
48       * @return identity transform.
49       */
50      static <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getIdentity(final Field<T> field) {
51          return new FieldStaticTransform<T>() {
52              @Override
53              public FieldVector3D<T> getTranslation() {
54                  return  FieldVector3D.getZero(field);
55              }
56  
57              @Override
58              public FieldRotation<T> getRotation() {
59                  return FieldRotation.getIdentity(field);
60              }
61  
62              @Override
63              public FieldStaticTransform<T> getStaticInverse() {
64                  return getInverse();
65              }
66  
67              @Override
68              public FieldStaticTransform<T> getInverse() {
69                  return this;
70              }
71  
72              @Override
73              public AbsoluteDate getDate() {
74                  return AbsoluteDate.ARBITRARY_EPOCH;
75              }
76  
77              @Override
78              public FieldVector3D<T> transformVector(final FieldVector3D<T> vector) {
79                  return new FieldVector3D<>(vector.getX(), vector.getY(), vector.getZ());
80              }
81  
82              @Override
83              public FieldVector3D<T> transformVector(final Vector3D vector) {
84                  return new FieldVector3D<>(field, vector);
85              }
86  
87              @Override
88              public FieldVector3D<T> transformPosition(final FieldVector3D<T> position) {
89                  return transformVector(position);
90              }
91  
92              @Override
93              public FieldVector3D<T> transformPosition(final Vector3D position) {
94                  return transformVector(position);
95              }
96          };
97      }
98  
99      /**
100      * Transform a position vector (including translation effects).
101      *
102      * @param position vector to transform
103      * @return transformed position
104      */
105     default FieldVector3D<T> transformPosition(final Vector3D position) {
106         return getRotation().applyTo(getTranslation().add(position));
107     }
108 
109     /**
110      * Transform a position vector (including translation effects).
111      *
112      * @param position vector to transform
113      * @return transformed position
114      */
115     default FieldVector3D<T> transformPosition(final FieldVector3D<T> position) {
116         return getRotation().applyTo(getTranslation().add(position));
117     }
118 
119     /**
120      * Transform a vector (ignoring translation effects).
121      *
122      * @param vector vector to transform
123      * @return transformed vector
124      */
125     default FieldVector3D<T> transformVector(final Vector3D vector) {
126         return getRotation().applyTo(vector);
127     }
128 
129     /**
130      * Transform a vector (ignoring translation effects).
131      *
132      * @param vector vector to transform
133      * @return transformed vector
134      */
135     default FieldVector3D<T> transformVector(final FieldVector3D<T> vector) {
136         return getRotation().applyTo(vector);
137     }
138 
139     /**
140      * Transform a line.
141      *
142      * @param line to transform
143      * @return transformed line
144      */
145     default FieldLine<T> transformLine(final Line line) {
146         final FieldVector3D<T> transformedP0 = transformPosition(line.getOrigin());
147         final FieldVector3D<T> transformedP1 = transformPosition(line.pointAt(1.0e6));
148         return new FieldLine<>(transformedP0, transformedP1, line.getTolerance());
149     }
150 
151     /**
152      * Transform a line.
153      *
154      * @param line to transform
155      * @return transformed line
156      */
157     default FieldLine<T> transformLine(final FieldLine<T> line) {
158         final FieldVector3D<T> transformedP0 = transformPosition(line.getOrigin());
159         final FieldVector3D<T> transformedP1 = transformPosition(line.pointAt(1.0e6));
160         return new FieldLine<>(transformedP0, transformedP1, line.getTolerance());
161     }
162 
163     /** Get the Field date.
164      * This default implementation is there so that no API is broken by a minor release.
165      * It is overloaded by native inheritors and shall be removed in the next major release.
166      * @return Field date attached to the object
167      * @since 12.1
168      */
169     default FieldAbsoluteDate<T> getFieldDate() {
170         return new FieldAbsoluteDate<>(getTranslation().getX().getField(), getDate());
171     }
172 
173     /**
174      * Get the underlying elementary translation.
175      * <p>A transform can be uniquely represented as an elementary
176      * translation followed by an elementary rotation. This method returns this
177      * unique elementary translation.</p>
178      *
179      * @return underlying elementary translation
180      */
181     FieldVector3D<T> getTranslation();
182 
183     /**
184      * Get the underlying elementary rotation.
185      * <p>A transform can be uniquely represented as an elementary
186      * translation followed by an elementary rotation. This method returns this
187      * unique elementary rotation.</p>
188      *
189      * @return underlying elementary rotation
190      */
191     FieldRotation<T> getRotation();
192 
193     /**
194      * Get the inverse transform of the instance.
195      *
196      * @return inverse transform of the instance
197      */
198     FieldStaticTransform<T> getInverse();
199 
200     /**
201      * Get the inverse transform of the instance in static form (without rates).
202      * This enables to create a purely static inverse, as inheritors such as {@link FieldTransform} may
203      * have a relatively computationally-heavy #getInverse() method.
204      *
205      * @return inverse static transform of the instance
206      * @since 12.1
207      */
208     default FieldStaticTransform<T> getStaticInverse() {
209         final FieldVector3D<T> negatedTranslation = getTranslation().negate();
210         final FieldRotation<T> rotation = getRotation();
211         return FieldStaticTransform.of(getFieldDate(), rotation.applyTo(negatedTranslation), rotation.revert());
212     }
213 
214     /**
215      * Build a transform by combining two existing ones.
216      * <p>
217      * Note that the dates of the two existing transformed are <em>ignored</em>,
218      * and the combined transform date is set to the date supplied in this
219      * constructor without any attempt to shift the raw transforms. This is a
220      * design choice allowing user full control of the combination.
221      * </p>
222      *
223      * @param <T>    type of the elements
224      * @param date   date of the transform
225      * @param first  first transform applied
226      * @param second second transform applied
227      * @return the newly created static transform that has the same effect as
228      * applying {@code first}, then {@code second}.
229      * @see #of(FieldAbsoluteDate, FieldVector3D, FieldRotation)
230      */
231     static <T extends CalculusFieldElement<T>> FieldStaticTransform<T> compose(final FieldAbsoluteDate<T> date,
232                                                                                final FieldStaticTransform<T> first,
233                                                                                final FieldStaticTransform<T> second) {
234         return of(date,
235                   compositeTranslation(first, second),
236                   compositeRotation(first, second));
237     }
238 
239     /**
240      * Compute a composite translation.
241      *
242      * @param first first applied transform
243      * @param second second applied transform
244      * @param <T> the type of the field elements
245      * @return translation part of the composite transform
246      */
247     static <T extends CalculusFieldElement<T>> FieldVector3D<T> compositeTranslation(final FieldStaticTransform<T> first,
248                                                                                      final FieldStaticTransform<T> second) {
249 
250         final FieldVector3D<T> p1 = first.getTranslation();
251         final FieldRotation<T> r1 = first.getRotation();
252         final FieldVector3D<T> p2 = second.getTranslation();
253 
254         return p1.add(r1.applyInverseTo(p2));
255 
256     }
257 
258     /**
259      * Compute a composite rotation.
260      *
261      * @param first first applied transform
262      * @param second second applied transform
263      * @param <T> the type of the field elements
264      * @return rotation part of the composite transform
265      */
266     static <T extends CalculusFieldElement<T>> FieldRotation<T> compositeRotation(final FieldStaticTransform<T> first,
267                                                                                   final FieldStaticTransform<T> second) {
268         final FieldRotation<T> r1 = first.getRotation();
269         final FieldRotation<T> r2 = second.getRotation();
270         return r1.compose(r2, RotationConvention.FRAME_TRANSFORM);
271     }
272 
273     /**
274      * Create a new static transform from a rotation and zero translation.
275      *
276      * @param <T>         type of the elements
277      * @param date     of translation.
278      * @param rotation to apply after the translation. That is after translating
279      *                 applying this rotation produces positions expressed in
280      *                 the new frame.
281      * @return the newly created static transform.
282      * @see #of(FieldAbsoluteDate, FieldVector3D, FieldRotation)
283      */
284     static <T extends CalculusFieldElement<T>> FieldStaticTransform<T> of(final FieldAbsoluteDate<T> date,
285                                                                           final FieldRotation<T> rotation) {
286         return of(date, FieldVector3D.getZero(date.getField()), rotation);
287     }
288 
289     /**
290      * Create a new static transform from a translation and rotation.
291      *
292      * @param <T>         type of the elements
293      * @param date        of translation.
294      * @param translation to apply, expressed in the old frame. That is, the
295      *                    opposite of the coordinates of the new origin in the
296      *                    old frame.
297      * @return the newly created static transform.
298      * @see #of(FieldAbsoluteDate, FieldVector3D, FieldRotation)
299      */
300     static <T extends CalculusFieldElement<T>> FieldStaticTransform<T> of(final FieldAbsoluteDate<T> date,
301                                                                           final FieldVector3D<T> translation) {
302         return of(date, translation, FieldRotation.getIdentity(date.getField()));
303     }
304 
305     /**
306      * Create a new static transform from an {@link FieldAbsoluteDate} and a {@link StaticTransform}.
307      *
308      * @param <T>         type of the elements
309      * @param date        of translation.
310      * @param staticTransform to apply
311      * @return the newly created static transform.
312      * @see #of(FieldAbsoluteDate, FieldVector3D, FieldRotation)
313      */
314     static <T extends CalculusFieldElement<T>> FieldStaticTransform<T> of(final FieldAbsoluteDate<T> date,
315                                                                           final StaticTransform staticTransform) {
316         return of(date,
317                   new FieldVector3D<>(date.getField(), staticTransform.getTranslation()),
318                   new FieldRotation<>(date.getField(), staticTransform.getRotation()));
319     }
320 
321     /**
322      * Create a new static transform from a translation and rotation.
323      *
324      * @param <T>         type of the elements
325      * @param date        of translation.
326      * @param translation to apply, expressed in the old frame. That is, the
327      *                    opposite of the coordinates of the new origin in the
328      *                    old frame.
329      * @param rotation    to apply after the translation. That is after
330      *                    translating applying this rotation produces positions
331      *                    expressed in the new frame.
332      * @return the newly created static transform.
333      * @see #compose(FieldAbsoluteDate, FieldStaticTransform, FieldStaticTransform)
334      * @see #of(FieldAbsoluteDate, FieldRotation)
335      * @see #of(FieldAbsoluteDate, FieldVector3D)
336      */
337     static <T extends CalculusFieldElement<T>> FieldStaticTransform<T> of(final FieldAbsoluteDate<T> date,
338                                                                           final FieldVector3D<T> translation,
339                                                                           final FieldRotation<T> rotation) {
340         return new FieldStaticTransform<T>() {
341 
342             @Override
343             public FieldStaticTransform<T> getInverse() {
344                 final FieldRotation<T> r = getRotation();
345                 final FieldVector3D<T> rp = r.applyTo(getTranslation());
346                 final FieldVector3D<T> pInv = rp.negate();
347                 return FieldStaticTransform.of(date, pInv, rotation.revert());
348             }
349 
350             @Override
351             public AbsoluteDate getDate() {
352                 return date.toAbsoluteDate();
353             }
354 
355             @Override
356             public FieldAbsoluteDate<T> getFieldDate() {
357                 return date;
358             }
359 
360             @Override
361             public FieldVector3D<T> getTranslation() {
362                 return translation;
363             }
364 
365             @Override
366             public FieldRotation<T> getRotation() {
367                 return rotation;
368             }
369 
370         };
371     }
372 
373 }