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