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 java.util.regex.Matcher;
20  import java.util.regex.Pattern;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.orekit.annotation.DefaultDataContext;
24  import org.orekit.data.DataContext;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.time.AbsoluteDate;
28  import org.orekit.time.FieldAbsoluteDate;
29  import org.orekit.time.TimeScale;
30  
31  /** Enumerate for ITRF versions.
32   * @see EOPEntry
33   * @see HelmertTransformation
34   * @author Luc Maisonobe
35   * @since 9.2
36   */
37  public enum ITRFVersion {
38  
39      /** Constant for ITRF 2020. */
40      ITRF_2020(2020),
41  
42      /** Constant for ITRF 2014. */
43      ITRF_2014(2014),
44  
45      /** Constant for ITRF 2008. */
46      ITRF_2008(2008),
47  
48      /** Constant for ITRF 2005. */
49      ITRF_2005(2005),
50  
51      /** Constant for ITRF 2000. */
52      ITRF_2000(2000),
53  
54      /** Constant for ITRF 1997. */
55      ITRF_1997(1997),
56  
57      /** Constant for ITRF 1996. */
58      ITRF_1996(1996),
59  
60      /** Constant for ITRF 1994. */
61      ITRF_1994(1994),
62  
63      /** Constant for ITRF 1993. */
64      ITRF_1993(1993),
65  
66      /** Constant for ITRF 1992. */
67      ITRF_1992(1992),
68  
69      /** Constant for ITRF 1991. */
70      ITRF_1991(1991),
71  
72      /** Constant for ITRF 1990. */
73      ITRF_1990(1990),
74  
75      /** Constant for ITRF 89. */
76      ITRF_1989(1989),
77  
78      /** Constant for ITRF 88. */
79      ITRF_1988(1988);
80  
81      /** Regular expression for ITRF names, using several variations. */
82      private static final Pattern PATTERN = Pattern.compile("[Ii][Tt][Rr][Ff][-_ ]?([0-9]{2,4})");
83  
84      /** Reference year of the frame version. */
85      private final int year;
86  
87      /** Name. */
88      private final String name;
89  
90      /** Simple constructor.
91       * @param year reference year of the frame version
92       */
93      ITRFVersion(final int year) {
94          this.year = year;
95          this.name = "ITRF-" + year;
96      }
97  
98      /** Get the reference year of the frame version.
99       * @return reference year of the frame version
100      */
101     public int getYear() {
102         return year;
103     }
104 
105     /** Get the name the frame version.
106      * @return name of the frame version
107      */
108     public String getName() {
109         return name;
110     }
111 
112     /** Find an ITRF version from its reference year.
113      * @param year reference year of the frame version
114      * @return ITRF version for specified year
115      */
116     public static ITRFVersion getITRFVersion(final int year) {
117 
118         final int fixedYear = (year < 100) ? (year + (year > 87 ? 1900 : 2000)) : year;
119 
120         // loop over all predefined frames versions
121         for (final ITRFVersion version : values()) {
122             if (version.getYear() == fixedYear) {
123                 return version;
124             }
125         }
126 
127         // we don't have the required frame
128         throw new OrekitException(OrekitMessages.NO_SUCH_ITRF_FRAME, year);
129 
130     }
131 
132     /** Find an ITRF version from its name.
133      * @param name name of the frame version (case is ignored)
134      * @return ITRF version
135      */
136     public static ITRFVersion getITRFVersion(final String name) {
137 
138         // extract year from name
139         final Matcher matcher = PATTERN.matcher(name);
140         if (matcher.matches()) {
141             try {
142                 return getITRFVersion(Integer.parseInt(matcher.group(1)));
143             } catch (OrekitException oe) {
144                 throw new OrekitException(OrekitMessages.NO_SUCH_ITRF_FRAME, name);
145             }
146         }
147 
148         // we don't have the required frame
149         throw new OrekitException(OrekitMessages.NO_SUCH_ITRF_FRAME, name);
150 
151     }
152 
153     /** Get last supported ITRF version.
154      * @return last supported ITRF version
155      * @since 11.2
156      */
157     public static ITRFVersion getLast() {
158         ITRFVersion last = ITRFVersion.ITRF_1988;
159         for (final ITRFVersion iv : ITRFVersion.values()) {
160             if (iv.getYear() > last.getYear()) {
161                 last = iv;
162             }
163         }
164         return last;
165     }
166 
167     /** Find a converter between specified ITRF frames.
168      *
169      * <p>This method uses the {@link DataContext#getDefault() default data context}.
170      *
171      * @param origin origin ITRF
172      * @param destination destination ITRF
173      * @return transform from {@code origin} to {@code destination}
174      * @see #getConverter(ITRFVersion, ITRFVersion, TimeScale)
175      */
176     @DefaultDataContext
177     public static Converter getConverter(final ITRFVersion origin, final ITRFVersion destination) {
178         return getConverter(origin, destination,
179                 DataContext.getDefault().getTimeScales().getTT());
180     }
181 
182     /** Find a converter between specified ITRF frames.
183      * @param origin origin ITRF
184      * @param destination destination ITRF
185      * @param tt TT time scale.
186      * @return transform from {@code origin} to {@code destination}
187      * @since 10.1
188      */
189     public static Converter getConverter(final ITRFVersion origin,
190                                          final ITRFVersion destination,
191                                          final TimeScale tt) {
192 
193         TransformProvider provider = null;
194 
195         // special case for no transform
196         if (origin == destination) {
197             provider = TransformProviderUtils.IDENTITY_PROVIDER;
198         }
199 
200         if (provider == null) {
201             // try to find a direct provider
202             provider = getDirectTransformProvider(origin, destination, tt);
203         }
204 
205         if (provider == null) {
206             // no direct provider found, use last supported ITRF as a pivot frame
207             final ITRFVersion last = getLast();
208             provider = TransformProviderUtils.getCombinedProvider(getDirectTransformProvider(origin, last, tt),
209                                                                   getDirectTransformProvider(last, destination, tt));
210         }
211 
212         // build the converter, to keep the origin and destination information
213         return new Converter(origin, destination, provider);
214 
215     }
216 
217     /** Find a direct transform provider between specified ITRF frames.
218      * @param origin origin ITRF
219      * @param destination destination ITRF
220      * @param tt TT time scale.
221      * @return transform from {@code origin} to {@code destination}, or null if no direct transform is found
222      */
223     private static TransformProvider getDirectTransformProvider(
224             final ITRFVersion origin,
225             final ITRFVersion destination,
226             final TimeScale tt) {
227 
228         // loop over all predefined transforms
229         for (final HelmertTransformation.Predefined predefined : HelmertTransformation.Predefined.values()) {
230             if (predefined.getOrigin() == origin && predefined.getDestination() == destination) {
231                 // we have an Helmert transformation in the specified direction
232                 return predefined.getTransformation(tt);
233             } else if (predefined.getOrigin() == destination && predefined.getDestination() == origin) {
234                 // we have an Helmert transformation in the opposite direction
235                 return TransformProviderUtils.getReversedProvider(predefined.getTransformation(tt));
236             }
237         }
238 
239         // we don't have the required transform
240         return null;
241 
242     }
243 
244     /** Specialized transform provider between ITRF frames. */
245     public static class Converter implements TransformProvider {
246 
247         /** Serializable UID. */
248         private static final long serialVersionUID = 20180330L;
249 
250         /** Origin ITRF. */
251         private final ITRFVersion origin;
252 
253         /** Destination ITRF. */
254         private final ITRFVersion destination;
255 
256         /** Underlying provider. */
257         private final TransformProvider provider;
258 
259         /** Simple constructor.
260          * @param origin origin ITRF
261          * @param destination destination ITRF
262          * @param provider underlying provider
263          */
264         Converter(final ITRFVersion origin, final ITRFVersion destination, final TransformProvider provider) {
265             this.origin      = origin;
266             this.destination = destination;
267             this.provider    = provider;
268         }
269 
270         /** Get the origin ITRF.
271          * @return origin ITRF
272          */
273         public ITRFVersion getOrigin() {
274             return origin;
275         }
276 
277         /** Get the destination ITRF.
278          * @return destination ITRF
279          */
280         public ITRFVersion getDestination() {
281             return destination;
282         }
283 
284         /** {@inheritDoc} */
285         @Override
286         public Transform getTransform(final AbsoluteDate date) {
287             return provider.getTransform(date);
288         }
289 
290         /** {@inheritDoc} */
291         @Override
292         public KinematicTransform getKinematicTransform(final AbsoluteDate date) {
293             return provider.getKinematicTransform(date);
294         }
295 
296         /** {@inheritDoc} */
297         @Override
298         public StaticTransform getStaticTransform(final AbsoluteDate date) {
299             return provider.getStaticTransform(date);
300         }
301 
302         /** {@inheritDoc} */
303         @Override
304         public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
305             return provider.getTransform(date);
306         }
307 
308         /** {@inheritDoc} */
309         @Override
310         public <T extends CalculusFieldElement<T>> FieldKinematicTransform<T> getKinematicTransform(final FieldAbsoluteDate<T> date) {
311             return provider.getKinematicTransform(date);
312         }
313 
314         /** {@inheritDoc} */
315         @Override
316         public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
317             return provider.getStaticTransform(date);
318         }
319 
320     }
321 
322 }