1   /* Contributed in the public domain.
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.geometry.euclidean.threed.FieldRotation;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.geometry.euclidean.threed.Line;
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.TimeStamped;
28  
29  /**
30   * A transform that only includes translation and rotation. It is static in the
31   * sense that no rates thereof are included.
32   *
33   * @author Evan Ward
34   * @see Transform
35   * @since 11.2
36   */
37  public interface StaticTransform extends TimeStamped {
38  
39      /**
40       * Get the identity static transform.
41       *
42       * @return identity transform.
43       */
44      static StaticTransform getIdentity() {
45          return Transform.IDENTITY;
46      }
47  
48      /**
49       * Transform a position vector (including translation effects).
50       *
51       * @param position vector to transform
52       * @return transformed position
53       */
54      default Vector3D transformPosition(final Vector3D position) {
55          return getRotation().applyTo(getTranslation().add(position));
56      }
57  
58      /**
59       * Transform a position vector (including translation effects).
60       *
61       * @param position vector to transform
62       * @param <T>      the type of the field elements
63       * @return transformed position
64       */
65      default  <T extends CalculusFieldElement<T>> FieldVector3D<T> transformPosition(
66              final FieldVector3D<T> position) {
67          return FieldRotation.applyTo(getRotation(), position.add(getTranslation()));
68      }
69  
70      /**
71       * Transform a vector (ignoring translation effects).
72       *
73       * @param vector vector to transform
74       * @return transformed vector
75       */
76      default  Vector3D transformVector(final Vector3D vector) {
77          return getRotation().applyTo(vector);
78      }
79  
80      /**
81       * Transform a vector (ignoring translation effects).
82       *
83       * @param vector vector to transform
84       * @param <T>    the type of the field elements
85       * @return transformed vector
86       */
87      default <T extends CalculusFieldElement<T>> FieldVector3D<T> transformVector(
88              final FieldVector3D<T> vector) {
89          return FieldRotation.applyTo(getRotation(), vector);
90      }
91  
92      /**
93       * Transform a line.
94       *
95       * @param line to transform
96       * @return transformed line
97       */
98      default Line transformLine(final Line line) {
99          final Vector3D transformedP0 = transformPosition(line.getOrigin());
100         final Vector3D transformedD  = transformVector(line.getDirection());
101         return Line.fromDirection(transformedP0, transformedD, line.getTolerance());
102     }
103 
104     /**
105      * Get the underlying elementary translation.
106      * <p>A transform can be uniquely represented as an elementary
107      * translation followed by an elementary rotation. This method returns this
108      * unique elementary translation.</p>
109      *
110      * @return underlying elementary translation
111      */
112     Vector3D getTranslation();
113 
114     /**
115      * Get the underlying elementary rotation.
116      * <p>A transform can be uniquely represented as an elementary
117      * translation followed by an elementary rotation. This method returns this
118      * unique elementary rotation.</p>
119      *
120      * @return underlying elementary rotation
121      */
122     Rotation getRotation();
123 
124     /**
125      * Get the inverse transform of the instance.
126      *
127      * @return inverse transform of the instance
128      */
129     StaticTransform getInverse();
130 
131     /**
132      * Get the inverse transform of the instance in static form (without rates).
133      * This enables to create a purely static inverse, as inheritors such as {@link Transform} may
134      * have a relatively computationally-heavy #getInverse() method.
135      *
136      * @return inverse static transform of the instance
137      * @since 12.1
138      */
139     default StaticTransform getStaticInverse() {
140         final Rotation rotation = getRotation();
141         return StaticTransform.of(getDate(), rotation.applyTo(getTranslation()).negate(), rotation.revert());
142     }
143 
144     /**
145      * Build a transform by combining two existing ones.
146      * <p>
147      * Note that the dates of the two existing transformed are <em>ignored</em>,
148      * and the combined transform date is set to the date supplied in this
149      * constructor without any attempt to shift the raw transforms. This is a
150      * design choice allowing user full control of the combination.
151      * </p>
152      *
153      * @param date   date of the transform
154      * @param first  first transform applied
155      * @param second second transform applied
156      * @return the newly created static transform that has the same effect as
157      * applying {@code first}, then {@code second}.
158      * @see #of(AbsoluteDate, Vector3D, Rotation)
159      */
160     static StaticTransform compose(final AbsoluteDate date,
161                                    final StaticTransform first,
162                                    final StaticTransform second) {
163         return of(date,
164                 compositeTranslation(first, second),
165                 compositeRotation(first, second));
166     }
167 
168     /**
169      * Compute a composite translation.
170      *
171      * @param first  first applied transform
172      * @param second second applied transform
173      * @return translation part of the composite transform
174      */
175     static Vector3D compositeTranslation(
176             final StaticTransform first,
177             final StaticTransform second) {
178         final Vector3D p1 = first.getTranslation();
179         final Rotation r1 = first.getRotation();
180         final Vector3D p2 = second.getTranslation();
181 
182         return p1.add(r1.applyInverseTo(p2));
183     }
184 
185     /**
186      * Compute a composite rotation.
187      *
188      * @param first  first applied transform
189      * @param second second applied transform
190      * @return rotation part of the composite transform
191      */
192     static Rotation compositeRotation(final StaticTransform first,
193                                       final StaticTransform second) {
194         final Rotation r1 = first.getRotation();
195         final Rotation r2 = second.getRotation();
196         return r1.compose(r2, RotationConvention.FRAME_TRANSFORM);
197 
198     }
199 
200     /**
201      * Create a new static transform from a rotation and zero translation.
202      *
203      * @param date     of translation.
204      * @param rotation to apply after the translation. That is after translating
205      *                 applying this rotation produces positions expressed in
206      *                 the new frame.
207      * @return the newly created static transform.
208      * @see #of(AbsoluteDate, Vector3D, Rotation)
209      */
210     static StaticTransform of(final AbsoluteDate date,
211                               final Rotation rotation) {
212         return of(date, Vector3D.ZERO, rotation);
213     }
214 
215     /**
216      * Create a new static transform from a translation and rotation.
217      *
218      * @param date        of translation.
219      * @param translation to apply, expressed in the old frame. That is, the
220      *                    opposite of the coordinates of the new origin in the
221      *                    old frame.
222      * @return the newly created static transform.
223      * @see #of(AbsoluteDate, Vector3D, Rotation)
224      */
225     static StaticTransform of(final AbsoluteDate date,
226                               final Vector3D translation) {
227         return of(date, translation, Rotation.IDENTITY);
228     }
229 
230     /**
231      * Create a new static transform from a translation and rotation.
232      *
233      * @param date        of translation.
234      * @param translation to apply, expressed in the old frame. That is, the
235      *                    opposite of the coordinates of the new origin in the
236      *                    old frame.
237      * @param rotation    to apply after the translation. That is after
238      *                    translating applying this rotation produces positions
239      *                    expressed in the new frame.
240      * @return the newly created static transform.
241      * @see #compose(AbsoluteDate, StaticTransform, StaticTransform)
242      * @see #of(AbsoluteDate, Rotation)
243      * @see #of(AbsoluteDate, Vector3D)
244      */
245     static StaticTransform of(final AbsoluteDate date,
246                               final Vector3D translation,
247                               final Rotation rotation) {
248         return new StaticTransform() {
249 
250             @Override
251             public StaticTransform getInverse() {
252                 final Rotation r = getRotation();
253                 final Vector3D rp = r.applyTo(getTranslation());
254                 final Vector3D pInv = rp.negate();
255                 return StaticTransform.of(date, pInv, rotation.revert());
256             }
257 
258             @Override
259             public AbsoluteDate getDate() {
260                 return date;
261             }
262 
263             @Override
264             public Vector3D getTranslation() {
265                 return translation;
266             }
267 
268             @Override
269             public Rotation getRotation() {
270                 return rotation;
271             }
272 
273         };
274     }
275 
276 }