1   /* Copyright 2002-2021 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.geometry.euclidean.threed.FieldRotation;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.geometry.euclidean.threed.Rotation;
23  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.hipparchus.util.Precision;
26  import org.orekit.annotation.DefaultDataContext;
27  import org.orekit.data.DataContext;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.time.DateTimeComponents;
30  import org.orekit.time.FieldAbsoluteDate;
31  import org.orekit.time.TimeScale;
32  import org.orekit.utils.Constants;
33  import org.orekit.utils.FieldPVCoordinates;
34  import org.orekit.utils.PVCoordinates;
35  
36  
37  /** Transformation class for geodetic systems.
38   *
39   * <p>The Helmert transformation is mainly used to convert between various
40   * realizations of geodetic frames, for example in the ITRF family.</p>
41   *
42   * <p>The original Helmert transformation is a 14 parameters transform that
43   * includes translation, velocity, rotation, rotation rate and scale factor.
44   * The scale factor is useful for coordinates near Earth surface, but it
45   * cannot be extended to outer space as it would correspond to a non-unitary
46   * transform. Therefore, the scale factor is <em>not</em> used here.
47   *
48   * <p>Instances of this class are guaranteed to be immutable.</p>
49   *
50   * @author Luc Maisonobe
51   * @since 5.1
52   */
53  public class HelmertTransformation implements TransformProvider {
54  
55      /** serializable UID. */
56      private static final long serialVersionUID = -1900615992141291146L;
57  
58      /** Enumerate for predefined Helmert transformations. */
59      public enum Predefined {
60  
61          // see http://itrf.ign.fr/doc_ITRF/Transfo-ITRF2014_ITRFs.txt
62          // SOLUTION         Tx       Ty       Tz        D        Rx        Ry        Rz      EPOCH
63          // UNITS----------> mm       mm       mm       ppb       .001"     .001"     .001"
64          //                  .        .        .         .        .         .         .
65          //        RATES     Tx       Ty       Tz        D        Rx        Ry        Rz
66          // UNITS----------> mm/y     mm/y     mm/y     ppb/y    .001"/y   .001"/y   .001"/y
67          // -----------------------------------------------------------------------------------------
68          //   ITRF2008        1.6      1.9      2.4     -0.02      0.00      0.00      0.00    2010.0
69          //        rates      0.0      0.0     -0.1      0.03      0.00      0.00      0.00
70          //   ITRF2005        2.6      1.0     -2.3      0.92      0.00      0.00      0.00    2010.0
71          //        rates      0.3      0.0     -0.1      0.03      0.00      0.00      0.00
72          //   ITRF2000        0.7      1.2    -26.1      2.12      0.00      0.00      0.00    2010.0
73          //        rates      0.1      0.1     -1.9      0.11      0.00      0.00      0.00
74          //   ITRF97          7.4     -0.5    -62.8      3.80      0.00      0.00      0.26    2010.0
75          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
76          //   ITRF96          7.4     -0.5    -62.8      3.80      0.00      0.00      0.26    2010.0
77          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
78          //   ITRF94          7.4     -0.5    -62.8      3.80      0.00      0.00      0.26    2010.0
79          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
80          //   ITRF93        -50.4      3.3    -60.2      4.29     -2.81     -3.38      0.40    2010.0
81          //        rates     -2.8     -0.1     -2.5      0.12     -0.11     -0.19      0.07
82          //   ITRF92         15.4      1.5    -70.8      3.09      0.00      0.00      0.26    2010.0
83          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
84          //   ITRF91         27.4     15.5    -76.8      4.49      0.00      0.00      0.26    2010.0
85          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
86          //   ITRF90         25.4     11.5    -92.8      4.79      0.00      0.00      0.26    2010.0
87          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
88          //   ITRF89         30.4     35.5   -130.8      8.19      0.00      0.00      0.26    2010.0
89          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
90          //   ITRF88         25.4     -0.5   -154.8     11.29      0.10      0.00      0.26    2010.0
91          //        rates      0.1     -0.5     -3.3      0.12      0.00      0.00      0.02
92          // _________________________________________________________________________________________
93  
94          /** Transformation from ITRF 2014 To ITRF 2008. */
95          ITRF_2014_TO_ITRF_2008(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_2008, 2010,
96                                  1.6, 1.9,     2.4, 0.00, 0.00, 0.00,
97                                  0.0, 0.0,    -0.1, 0.00, 0.00, 0.00),
98  
99          /** Transformation from ITRF 2014 To ITRF 2005. */
100         ITRF_2014_TO_ITRF_2005(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_2005, 2010,
101                                 2.6, 1.0,    -2.3, 0.00, 0.00, 0.00,
102                                 0.3, 0.0,    -0.1, 0.00, 0.00, 0.00),
103 
104         /** Transformation from ITRF 2014 To ITRF 2000. */
105         ITRF_2014_TO_ITRF_2000(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_2000, 2010,
106                                 0.7, 1.2,   -26.1, 0.00, 0.00, 0.00,
107                                 0.1, 0.1,    -1.9, 0.00, 0.00, 0.00),
108 
109         /** Transformation from ITRF 2014 To ITRF 97. */
110         ITRF_2014_TO_ITRF_1997(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1997, 2010,
111                                7.4, -0.5,  -62.8, 0.00, 0.00, 0.26,
112                                0.1, -0.5,   -3.3, 0.00, 0.00, 0.02),
113 
114         /** Transformation from ITRF 2014 To ITRF 96. */
115         ITRF_2014_TO_ITRF_1996(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1996, 2010,
116                                7.4, -0.5,  -62.8, 0.00, 0.00, 0.26,
117                                0.1, -0.5,  -3.3, 0.00, 0.00, 0.02),
118 
119         /** Transformation from ITRF 2014 To ITRF 94. */
120         ITRF_2014_TO_ITRF_1994(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1994, 2010,
121                                7.4, -0.5,  -62.8, 0.00, 0.00, 0.26,
122                                0.1, -0.5,   -3.3, 0.00, 0.00, 0.02),
123 
124         /** Transformation from ITRF 2014 To ITRF 93. */
125         ITRF_2014_TO_ITRF_1993(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1993, 2010,
126                                -50.4,  3.3,  -60.2, -2.81, -3.38, 0.40,
127                                -2.8, -0.1,   -2.5, -0.11, -0.19, 0.07),
128 
129         /** Transformation from ITRF 2014 To ITRF 92. */
130         ITRF_2014_TO_ITRF_1992(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1992, 2010,
131                                15.4,  1.5,  -70.8, 0.00, 0.00, 0.26,
132                                0.1, -0.5,   -3.3, 0.00, 0.00, 0.02),
133 
134         /** Transformation from ITRF 2014 To ITRF 91. */
135         ITRF_2014_TO_ITRF_1991(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1991, 2010,
136                                27.4, 15.5,  -76.8, 0.00, 0.00, 0.26,
137                                0.1, -0.5,   -3.3, 0.00, 0.00, 0.02),
138 
139         /** Transformation from ITRF 2014 To ITRF 90. */
140         ITRF_2014_TO_ITRF_1990(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1990, 2010,
141                                25.4, 11.5,  -92.8, 0.00, 0.00, 0.26,
142                                0.1, -0.5,   -3.3, 0.00, 0.00, 0.02),
143 
144         /** Transformation from ITRF 2014 To ITRF 89. */
145         ITRF_2014_TO_ITRF_1989(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1989, 2010,
146                                30.4, 35.5, -130.8, 0.00, 0.00, 0.26,
147                                0.1, -0.5,   -3.3, 0.00, 0.00, 0.02),
148 
149         /** Transformation from ITRF 2014 To ITRF 88. */
150         ITRF_2014_TO_ITRF_1988(ITRFVersion.ITRF_2014, ITRFVersion.ITRF_1988, 2010,
151                                25.4, -0.5, -154.8, 0.10, 0.00, 0.26,
152                                0.1, -0.5,   -3.3, 0.00, 0.00, 0.02),
153 
154         // see http://itrf.ensg.ign.fr/doc_ITRF/Transfo-ITRF2008_ITRFs.txt
155         // SOLUTION         Tx       Ty       Tz        D        Rx        Ry        Rz      EPOCH
156         // UNITS----------> mm       mm       mm       ppb       .001"     .001"     .001"
157         //                         .        .        .         .        .         .         .
158         //        RATES     Tx       Ty       Tz        D        Rx        Ry        Rz
159         // UNITS----------> mm/y     mm/y     mm/y     ppb/y    .001"/y   .001"/y   .001"/y
160         // -----------------------------------------------------------------------------------------
161         //   ITRF2005       -2.0     -0.9     -4.7      0.94      0.00      0.00      0.00    2000.0
162         //        rates      0.3      0.0      0.0      0.00      0.00      0.00      0.00
163         //   ITRF2000       -1.9     -1.7    -10.5      1.34      0.00      0.00      0.00    2000.0
164         //        rates      0.1      0.1     -1.8      0.08      0.00      0.00      0.00
165         //   ITRF97          4.8      2.6    -33.2      2.92      0.00      0.00      0.06    2000.0
166         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
167         //   ITRF96          4.8      2.6    -33.2      2.92      0.00      0.00      0.06    2000.0
168         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
169         //   ITRF94          4.8      2.6    -33.2      2.92      0.00      0.00      0.06    2000.0
170         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
171         //   ITRF93        -24.0      2.4    -38.6      3.41     -1.71     -1.48     -0.30    2000.0
172         //        rates     -2.8     -0.1     -2.4      0.09     -0.11     -0.19      0.07
173         //   ITRF92         12.8      4.6    -41.2      2.21      0.00      0.00      0.06    2000.0
174         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
175         //   ITRF91         24.8     18.6    -47.2      3.61      0.00      0.00      0.06    2000.0
176         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
177         //   ITRF90         22.8     14.6    -63.2      3.91      0.00      0.00      0.06    2000.0
178         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
179         //   ITRF89         27.8     38.6   -101.2      7.31      0.00      0.00      0.06    2000.0
180         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
181         //   ITRF88         22.8      2.6   -125.2     10.41      0.10      0.00      0.06    2000.0
182         //        rates      0.1     -0.5     -3.2      0.09      0.00      0.00      0.02
183         // _________________________________________________________________________________________
184 
185         /** Transformation from ITRF 2008 To ITRF 2005. */
186         ITRF_2008_TO_ITRF_2005(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_2005, 2000,
187                                -2.0, -0.9,   -4.7,  0.00,  0.00,  0.00,
188                                 0.3,  0.0,    0.0,  0.00,  0.00,  0.00),
189 
190         /** Transformation from ITRF 2008 To ITRF 2000. */
191         ITRF_2008_TO_ITRF_2000(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_2000, 2000,
192                                -1.9, -1.7,  -10.5,  0.00,  0.00,  0.00,
193                                 0.1,  0.1,   -1.8,  0.00,  0.00,  0.00),
194 
195         /** Transformation from ITRF 2008 To ITRF 97. */
196         ITRF_2008_TO_ITRF_1997(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1997, 2000,
197                                4.8,  2.6,  -33.2,  0.00,  0.00,  0.06,
198                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02),
199 
200         /** Transformation from ITRF 2008 To ITRF 96. */
201         ITRF_2008_TO_ITRF_1996(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1996, 2000,
202                                4.8,  2.6,  -33.2,  0.00,  0.00,  0.06,
203                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02),
204 
205         /** Transformation from ITRF 2008 To ITRF 94. */
206         ITRF_2008_TO_ITRF_1994(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1994, 2000,
207                                4.8,  2.6,  -33.2,  0.00,  0.00,  0.06,
208                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02),
209 
210         /** Transformation from ITRF 2008 To ITRF 93. */
211         ITRF_2008_TO_ITRF_1993(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1993, 2000,
212                                -24.0,  2.4,  -38.6, -1.71, -1.48, -0.30,
213                                -2.8, -0.1,   -2.4, -0.11, -0.19,  0.07),
214 
215         /** Transformation from ITRF 2008 To ITRF 92. */
216         ITRF_2008_TO_ITRF_1992(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1992, 2000,
217                                12.8,  4.6,  -41.2,  0.00,  0.00,  0.06,
218                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02),
219 
220         /** Transformation from ITRF 2008 To ITRF 91. */
221         ITRF_2008_TO_ITRF_1991(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1991, 2000,
222                                24.8, 18.6,  -47.2,  0.00,  0.00,  0.06,
223                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02),
224 
225         /** Transformation from ITRF 2008 To ITRF 90. */
226         ITRF_2008_TO_ITRF_1990(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1990, 2000,
227                                22.8, 14.6,  -63.2,  0.00,  0.00,  0.06,
228                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02),
229 
230         /** Transformation from ITRF 2008 To ITRF 89. */
231         ITRF_2008_TO_ITRF_1989(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1989, 2000,
232                                27.8, 38.6, -101.2,  0.00,  0.00,  0.06,
233                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02),
234 
235         /** Transformation from ITRF 2008 To ITRF 88. */
236         ITRF_2008_TO_ITRF_1988(ITRFVersion.ITRF_2008, ITRFVersion.ITRF_1988, 2000,
237                                22.8,  2.6, -125.2,  0.10,  0.00,  0.06,
238                                0.1, -0.5,   -3.2,  0.00,  0.00,  0.02);
239 
240         /** Origin ITRF. */
241         private final ITRFVersion origin;
242 
243         /** Destination ITRF. */
244         private final ITRFVersion destination;
245 
246         /** Transformation. */
247         private final transient HelmertTransformationWithoutTimeScale transformation;
248 
249         /** Simple constructor.
250          * @param origin origin ITRF
251          * @param destination destination ITRF
252          * @param refYear reference year for the epoch of the transform
253          * @param t1 translation parameter along X axis (BEWARE, this is in mm)
254          * @param t2 translation parameter along Y axis (BEWARE, this is in mm)
255          * @param t3 translation parameter along Z axis (BEWARE, this is in mm)
256          * @param r1 rotation parameter around X axis (BEWARE, this is in mas)
257          * @param r2 rotation parameter around Y axis (BEWARE, this is in mas)
258          * @param r3 rotation parameter around Z axis (BEWARE, this is in mas)
259          * @param t1Dot rate of translation parameter along X axis (BEWARE, this is in mm/y)
260          * @param t2Dot rate of translation parameter along Y axis (BEWARE, this is in mm/y)
261          * @param t3Dot rate of translation parameter along Z axis (BEWARE, this is in mm/y)
262          * @param r1Dot rate of rotation parameter around X axis (BEWARE, this is in mas/y)
263          * @param r2Dot rate of rotation parameter around Y axis (BEWARE, this is in mas/y)
264          * @param r3Dot rate of rotation parameter around Z axis (BEWARE, this is in mas/y)
265          */
266         Predefined(final ITRFVersion origin, final ITRFVersion destination, final int refYear,
267                    final double t1, final double t2, final double t3,
268                    final double r1, final double r2, final double r3,
269                    final double t1Dot, final double t2Dot, final double t3Dot,
270                    final double r1Dot, final double r2Dot, final double r3Dot) {
271             this.origin         = origin;
272             this.destination    = destination;
273             this.transformation =
274                     new HelmertTransformationWithoutTimeScale(new DateTimeComponents(refYear, 1, 1, 12, 0, 0),
275                                               t1, t2, t3, r1, r2, r3, t1Dot, t2Dot, t3Dot, r1Dot, r2Dot, r3Dot);
276         }
277 
278         /** Get the origin ITRF.
279          * @return origin ITRF
280          * @since 9.2
281          */
282         public ITRFVersion getOrigin() {
283             return origin;
284         }
285 
286         /** Get the destination ITRF.
287          * @return destination ITRF
288          * @since 9.2
289          */
290         public ITRFVersion getDestination() {
291             return destination;
292         }
293 
294         /** Get the underlying {@link HelmertTransformation}.
295          *
296          * <p>This method uses the {@link DataContext#getDefault() default data context}.
297          *
298          * @return underlying {@link HelmertTransformation}
299          * @since 9.2
300          * @see #getTransformation(TimeScale)
301          */
302         @DefaultDataContext
303         public HelmertTransformation getTransformation() {
304             return getTransformation(DataContext.getDefault().getTimeScales().getTT());
305         }
306 
307         /** Get the underlying {@link HelmertTransformation}.
308          * @return underlying {@link HelmertTransformation}
309          * @param tt TT time scale.
310          * @since 10.1
311          */
312         public HelmertTransformation getTransformation(final TimeScale tt) {
313             return transformation.withTimeScale(tt);
314         }
315 
316         /** Create an ITRF frame by transforming another ITRF frame.
317          *
318          * <p>This method uses the {@link DataContext#getDefault() default data context}.
319          *
320          * @param parent parent ITRF frame
321          * @param name name of the frame to create
322          * @return new ITRF frame
323          * @see #createTransformedITRF(Frame, String, TimeScale)
324          */
325         @DefaultDataContext
326         public Frame createTransformedITRF(final Frame parent, final String name) {
327             return createTransformedITRF(parent, name,
328                     DataContext.getDefault().getTimeScales().getTT());
329         }
330 
331         /** Create an ITRF frame by transforming another ITRF frame.
332          * @param parent parent ITRF frame
333          * @param name name of the frame to create
334          * @param tt TT time scale.
335          * @return new ITRF frame
336          * @since 10.1
337          */
338         public Frame createTransformedITRF(final Frame parent,
339                                            final String name,
340                                            final TimeScale tt) {
341             return new Frame(parent, getTransformation(tt), name);
342         }
343 
344     }
345 
346     /**
347      * A {@link HelmertTransformation} without reference to a {@link TimeScale}. This
348      * class is needed to maintain compatibility with Orekit 10.0 since {@link Predefined}
349      * is an enum and it had a reference to the TT time scale.
350      */
351     private static class HelmertTransformationWithoutTimeScale {
352 
353         /** Cartesian part of the transform. */
354         private final PVCoordinates cartesian;
355 
356         /** Global rotation vector (applying rotation is done by computing cross product). */
357         private final Vector3D rotationVector;
358 
359         /** First time derivative of the rotation (norm representing angular rate). */
360         private final Vector3D rotationRate;
361 
362         /** Reference epoch of the transform. */
363         private final DateTimeComponents epoch;
364 
365         /** Build a transform from its primitive operations.
366          * @param epoch reference epoch of the transform
367          * @param t1 translation parameter along X axis (BEWARE, this is in mm)
368          * @param t2 translation parameter along Y axis (BEWARE, this is in mm)
369          * @param t3 translation parameter along Z axis (BEWARE, this is in mm)
370          * @param r1 rotation parameter around X axis (BEWARE, this is in mas)
371          * @param r2 rotation parameter around Y axis (BEWARE, this is in mas)
372          * @param r3 rotation parameter around Z axis (BEWARE, this is in mas)
373          * @param t1Dot rate of translation parameter along X axis (BEWARE, this is in mm/y)
374          * @param t2Dot rate of translation parameter along Y axis (BEWARE, this is in mm/y)
375          * @param t3Dot rate of translation parameter along Z axis (BEWARE, this is in mm/y)
376          * @param r1Dot rate of rotation parameter around X axis (BEWARE, this is in mas/y)
377          * @param r2Dot rate of rotation parameter around Y axis (BEWARE, this is in mas/y)
378          * @param r3Dot rate of rotation parameter around Z axis (BEWARE, this is in mas/y)
379          */
380         HelmertTransformationWithoutTimeScale(
381                 final DateTimeComponents epoch,
382                 final double t1, final double t2, final double t3,
383                 final double r1, final double r2, final double r3,
384                 final double t1Dot, final double t2Dot, final double t3Dot,
385                 final double r1Dot, final double r2Dot, final double r3Dot) {
386 
387             // conversion parameters to SI units
388             final double mmToM    = 1.0e-3;
389             final double masToRad = 1.0e-3 * Constants.ARC_SECONDS_TO_RADIANS;
390 
391             this.epoch          = epoch;
392             this.cartesian = new PVCoordinates(new Vector3D(t1 * mmToM,
393                     t2 * mmToM,
394                     t3 * mmToM),
395                     new Vector3D(t1Dot * mmToM / Constants.JULIAN_YEAR,
396                             t2Dot * mmToM / Constants.JULIAN_YEAR,
397                             t3Dot * mmToM / Constants.JULIAN_YEAR));
398             this.rotationVector = new Vector3D(r1 * masToRad,
399                     r2 * masToRad,
400                     r3 * masToRad);
401             this.rotationRate   = new Vector3D(r1Dot * masToRad / Constants.JULIAN_YEAR,
402                     r2Dot * masToRad / Constants.JULIAN_YEAR,
403                     r3Dot * masToRad / Constants.JULIAN_YEAR);
404 
405         }
406 
407         /**
408          * Get the Helmert transformation with reference to the given time scale.
409          *
410          * @param tt TT time scale.
411          * @return Helmert transformation.
412          */
413         public HelmertTransformation withTimeScale(final TimeScale tt) {
414             return new HelmertTransformation(cartesian, rotationVector, rotationRate,
415                     new AbsoluteDate(epoch, tt));
416         }
417 
418     }
419 
420     /** Cartesian part of the transform. */
421     private final PVCoordinates cartesian;
422 
423     /** Global rotation vector (applying rotation is done by computing cross product). */
424     private final Vector3D rotationVector;
425 
426     /** First time derivative of the rotation (norm representing angular rate). */
427     private final Vector3D rotationRate;
428 
429     /** Reference epoch of the transform. */
430     private final AbsoluteDate epoch;
431 
432     /** Build a transform from its primitive operations.
433      * @param epoch reference epoch of the transform
434      * @param t1 translation parameter along X axis (BEWARE, this is in mm)
435      * @param t2 translation parameter along Y axis (BEWARE, this is in mm)
436      * @param t3 translation parameter along Z axis (BEWARE, this is in mm)
437      * @param r1 rotation parameter around X axis (BEWARE, this is in mas)
438      * @param r2 rotation parameter around Y axis (BEWARE, this is in mas)
439      * @param r3 rotation parameter around Z axis (BEWARE, this is in mas)
440      * @param t1Dot rate of translation parameter along X axis (BEWARE, this is in mm/y)
441      * @param t2Dot rate of translation parameter along Y axis (BEWARE, this is in mm/y)
442      * @param t3Dot rate of translation parameter along Z axis (BEWARE, this is in mm/y)
443      * @param r1Dot rate of rotation parameter around X axis (BEWARE, this is in mas/y)
444      * @param r2Dot rate of rotation parameter around Y axis (BEWARE, this is in mas/y)
445      * @param r3Dot rate of rotation parameter around Z axis (BEWARE, this is in mas/y)
446      */
447     public HelmertTransformation(final AbsoluteDate epoch,
448                                  final double t1, final double t2, final double t3,
449                                  final double r1, final double r2, final double r3,
450                                  final double t1Dot, final double t2Dot, final double t3Dot,
451                                  final double r1Dot, final double r2Dot, final double r3Dot) {
452 
453         // conversion parameters to SI units
454         final double mmToM    = 1.0e-3;
455         final double masToRad = 1.0e-3 * Constants.ARC_SECONDS_TO_RADIANS;
456 
457         this.epoch          = epoch;
458         this.cartesian = new PVCoordinates(new Vector3D(t1 * mmToM,
459                                                         t2 * mmToM,
460                                                         t3 * mmToM),
461                                            new Vector3D(t1Dot * mmToM / Constants.JULIAN_YEAR,
462                                                         t2Dot * mmToM / Constants.JULIAN_YEAR,
463                                                         t3Dot * mmToM / Constants.JULIAN_YEAR));
464         this.rotationVector = new Vector3D(r1 * masToRad,
465                                            r2 * masToRad,
466                                            r3 * masToRad);
467         this.rotationRate   = new Vector3D(r1Dot * masToRad / Constants.JULIAN_YEAR,
468                                            r2Dot * masToRad / Constants.JULIAN_YEAR,
469                                            r3Dot * masToRad / Constants.JULIAN_YEAR);
470 
471     }
472 
473     /**
474      * Private constructor.
475      *
476      * @param cartesian      part of the transform.
477      * @param rotationVector global rotation vector.
478      * @param rotationRate   time derivative of rotation.
479      * @param epoch          of transform.
480      */
481     private HelmertTransformation(final PVCoordinates cartesian,
482                                   final Vector3D rotationVector,
483                                   final Vector3D rotationRate,
484                                   final AbsoluteDate epoch) {
485         this.cartesian = cartesian;
486         this.rotationVector = rotationVector;
487         this.rotationRate = rotationRate;
488         this.epoch = epoch;
489     }
490 
491     /** Get the reference epoch of the transform.
492      * @return reference epoch of the transform
493      */
494     public AbsoluteDate getEpoch() {
495         return epoch;
496     }
497 
498     /** {@inheritDoc} */
499     @Override
500     public Transform getTransform(final AbsoluteDate date) {
501 
502         // compute parameters evolution since reference epoch
503         final double dt = date.durationFrom(epoch);
504         final Vector3D dR = new Vector3D(1, rotationVector, dt, rotationRate);
505 
506         // build translation part
507         final Transform translationTransform = new Transform(date, cartesian.shiftedBy(dt));
508 
509         // build rotation part
510         final double angle = dR.getNorm();
511         final Transform rotationTransform =
512                 new Transform(date,
513                               (angle < Precision.SAFE_MIN) ?
514                               Rotation.IDENTITY :
515                               new Rotation(dR, angle, RotationConvention.VECTOR_OPERATOR),
516                               rotationRate);
517 
518         // combine both parts
519         return new Transform(date, translationTransform, rotationTransform);
520 
521     }
522 
523     /** {@inheritDoc} */
524     @Override
525     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
526 
527         // compute parameters evolution since reference epoch
528         final T dt = date.durationFrom(epoch);
529         final FieldVector3D<T> dR = new FieldVector3D<>(date.getField().getOne(), rotationVector,
530                                                         dt, rotationRate);
531 
532         // build translation part
533         final FieldTransform<T> translationTransform =
534                         new FieldTransform<>(date,
535                                              new FieldPVCoordinates<>(date.getField(), cartesian).shiftedBy(dt));
536 
537         // build rotation part
538         final T angle = dR.getNorm();
539         final FieldTransform<T> rotationTransform =
540                 new FieldTransform<>(date,
541                                     (angle.getReal() < Precision.SAFE_MIN) ?
542                                      FieldRotation.getIdentity(date.getField()) :
543                                     new FieldRotation<>(dR, angle, RotationConvention.VECTOR_OPERATOR),
544                                     new FieldVector3D<>(date.getField(), rotationRate));
545 
546         // combine both parts
547         return new FieldTransform<>(date, translationTransform, rotationTransform);
548 
549     }
550 
551 }