1   /* Copyright 2002-2025 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.concurrent.atomic.AtomicReference;
20  
21  import org.hipparchus.CalculusFieldElement;
22  import org.orekit.time.AbsoluteDate;
23  import org.orekit.time.FieldAbsoluteDate;
24  import org.orekit.time.TimeScale;
25  
26  
27  /** Provider for a specific version of International Terrestrial Reference Frame.
28   * <p>
29   * This class ensure the ITRF it defines is a specific version, regardless of
30   * the version of the underlying {@link EOPEntry Earth Orientation Parameters}.
31   * </p>
32   * @author Luc Maisonobe
33   * @since 9.2
34   */
35  class VersionedITRFProvider implements EOPBasedTransformProvider {
36  
37      /** ITRF version this provider should generate. */
38      private final ITRFVersion version;
39  
40      /** Raw ITRF provider. */
41      private final ITRFProvider rawProvider;
42  
43      /** Converter between different ITRF versions. */
44      private final AtomicReference<ITRFVersion.Converter> converter;
45  
46      /** TT time scale. */
47      private final TimeScale tt;
48  
49      /** Simple constructor.
50       * @param version ITRF version this provider should generate
51       * @param rawProvider raw ITRF provider
52       * @param tt TT time scale.
53       */
54      VersionedITRFProvider(final ITRFVersion version,
55                            final ITRFProvider rawProvider,
56                            final TimeScale tt) {
57          this.version     = version;
58          this.rawProvider = rawProvider;
59          this.converter   = new AtomicReference<>();
60          this.tt = tt;
61      }
62  
63      /** Get the ITRF version.
64       * @return ITRF version
65       */
66      public ITRFVersion getITRFVersion() {
67          return version;
68      }
69  
70      /** {@inheritDoc} */
71      @Override
72      public EOPHistory getEOPHistory() {
73          return rawProvider.getEOPHistory();
74      }
75  
76      /** {@inheritDoc} */
77      @Override
78      public VersionedITRFProvider getNonInterpolatingProvider() {
79          return new VersionedITRFProvider(version, rawProvider.getNonInterpolatingProvider(), tt);
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      public Transform getTransform(final AbsoluteDate date) {
85  
86          // get the transform from the current EOP
87          final Transform rawTransform = rawProvider.getTransform(date);
88  
89          // add the conversion layer
90          final ITRFVersion.Converter converterForDate = getConverter(date);
91          if (converterForDate == null) {
92              return rawTransform;
93          } else {
94              return new Transform(date, rawTransform, converterForDate.getTransform(date));
95          }
96  
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public KinematicTransform getKinematicTransform(final AbsoluteDate date) {
102 
103         // get the transform from the current EOP
104         final KinematicTransform rawTransform = rawProvider.getKinematicTransform(date);
105 
106         // add the conversion layer
107         final ITRFVersion.Converter converterForDate = getConverter(date);
108         if (converterForDate == null) {
109             return rawTransform;
110         } else {
111             return KinematicTransform.compose(date, rawTransform, converterForDate.getKinematicTransform(date));
112         }
113 
114     }
115 
116     /** {@inheritDoc} */
117     @Override
118     public StaticTransform getStaticTransform(final AbsoluteDate date) {
119 
120         // get the transform from the current EOP
121         final StaticTransform rawTransform = rawProvider.getStaticTransform(date);
122 
123         // add the conversion layer
124         final ITRFVersion.Converter converterForDate = getConverter(date);
125         if (converterForDate == null) {
126             return rawTransform;
127         } else {
128             return StaticTransform.compose(
129                     date,
130                     rawTransform,
131                     converterForDate.getStaticTransform(date));
132         }
133 
134     }
135 
136     /** {@inheritDoc} */
137     @Override
138     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
139 
140         // get the transform from the current EOP
141         final FieldTransform<T> rawTransform = rawProvider.getTransform(date);
142 
143         // add the conversion layer
144         final ITRFVersion.Converter converterForDate = getConverter(date.toAbsoluteDate());
145         if (converterForDate == null) {
146             return rawTransform;
147         } else {
148             return new FieldTransform<>(date, rawTransform, converterForDate.getTransform(date));
149         }
150 
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public <T extends CalculusFieldElement<T>> FieldKinematicTransform<T> getKinematicTransform(final FieldAbsoluteDate<T> date) {
156 
157         // get the transform from the current EOP
158         final FieldKinematicTransform<T> rawTransform = rawProvider.getKinematicTransform(date);
159 
160         // add the conversion layer
161         final ITRFVersion.Converter converterForDate = getConverter(date.toAbsoluteDate());
162         if (converterForDate == null) {
163             return rawTransform;
164         } else {
165             return FieldKinematicTransform.compose(date, rawTransform, converterForDate.getKinematicTransform(date));
166         }
167 
168     }
169 
170     /** {@inheritDoc} */
171     @Override
172     public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
173 
174         // get the transform from the current EOP
175         final FieldStaticTransform<T> rawTransform = rawProvider.getStaticTransform(date);
176 
177         // add the conversion layer
178         final ITRFVersion.Converter converterForDate = getConverter(date.toAbsoluteDate());
179         if (converterForDate == null) {
180             return rawTransform;
181         } else {
182             return FieldStaticTransform.compose(
183                     date,
184                     rawTransform,
185                     converterForDate.getStaticTransform(date));
186         }
187 
188     }
189 
190     /** Get a converter for the date.
191      * @param date date to check
192      * @return converter that should be applied for this date, or null
193      * if no converter is needed
194      */
195     private ITRFVersion.Converter getConverter(final AbsoluteDate date) {
196 
197         // check if the current EOP already provides the version we want
198         final ITRFVersion rawVersion = getEOPHistory().getITRFVersion(date);
199         if (rawVersion == version) {
200             // we already have what we need
201             return null;
202         }
203 
204         final ITRFVersion.Converter existing = converter.get();
205         if (existing != null && existing.getOrigin() == rawVersion) {
206             // the current converter can handle this date
207             return existing;
208         }
209 
210         // we need to create a new converter from raw version to desired version
211         final ITRFVersion.Converter newConverter =
212                 ITRFVersion.getConverter(rawVersion, version, tt);
213         converter.compareAndSet(null, newConverter);
214         return newConverter;
215 
216     }
217 
218 }