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