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  
18  package org.orekit.frames;
19  
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import org.hipparchus.Field;
24  import org.hipparchus.CalculusFieldElement;
25  import org.hipparchus.util.FastMath;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.time.FieldAbsoluteDate;
28  import org.orekit.utils.AngularDerivativesFilter;
29  import org.orekit.utils.CartesianDerivativesFilter;
30  import org.orekit.utils.GenericTimeStampedCache;
31  
32  /** Transform provider using thread-safe shifts on transforms sample.
33   * <p>
34   * The shifts take derivatives into account, up to user specified order.
35   * </p>
36   * @see GenericTimeStampedCache
37   * @see InterpolatingTransformProvider
38   * @since 7.1
39   * @author Luc Maisonobe
40   */
41  public class ShiftingTransformProvider implements TransformProvider {
42  
43      /** First level cache. */
44      private final InterpolatingTransformProvider interpolatingProvider;
45  
46      /** Cache for sample points. */
47      private final GenericTimeStampedCache<Transform> cache;
48  
49      /** Field caches for sample points. */
50      // we use Object as the value of fieldCaches because despite numerous attempts,
51      // we could not find a way to use GenericTimeStampedCache<FieldTransform<? extends CalculusFieldElement<?>>
52      // without the compiler complaining
53      private final Map<Field<? extends CalculusFieldElement<?>>, Object> fieldCaches;
54  
55      /** Simple constructor.
56       * @param rawProvider provider for raw (non-interpolated) transforms
57       * @param cFilter filter for derivatives from the sample to use in interpolation
58       * @param aFilter filter for derivatives from the sample to use in interpolation
59       * @param gridPoints number of interpolation grid points
60       * @param step grid points time step
61       * @param maxSlots maximum number of independent cached time slots
62       * in the {@link GenericTimeStampedCache time-stamped cache}
63       * @param maxSpan maximum duration span in seconds of one slot
64       * in the {@link GenericTimeStampedCache time-stamped cache}
65       * @param newSlotInterval time interval above which a new slot is created
66       * in the {@link GenericTimeStampedCache time-stamped cache}
67       * @since 9.1
68       */
69      public ShiftingTransformProvider(final TransformProvider rawProvider,
70                                       final CartesianDerivativesFilter cFilter,
71                                       final AngularDerivativesFilter aFilter,
72                                       final int gridPoints, final double step,
73                                       final int maxSlots, final double maxSpan, final double newSlotInterval) {
74          this(new InterpolatingTransformProvider(rawProvider, cFilter, aFilter,
75                                                  gridPoints, step, maxSlots, maxSpan, newSlotInterval),
76               maxSlots, maxSpan, newSlotInterval);
77      }
78  
79      /** Simple constructor.
80       * @param interpolatingProvider first level cache provider
81       * @param maxSlots maximum number of independent cached time slots
82       * in the {@link GenericTimeStampedCache time-stamped cache}
83       * @param maxSpan maximum duration span in seconds of one slot
84       * in the {@link GenericTimeStampedCache time-stamped cache}
85       * @param newSlotInterval time interval above which a new slot is created
86       * in the {@link GenericTimeStampedCache time-stamped cache}
87       */
88      private ShiftingTransformProvider(final InterpolatingTransformProvider interpolatingProvider,
89                                       final int maxSlots, final double maxSpan, final double newSlotInterval) {
90          this.interpolatingProvider = interpolatingProvider;
91          this.cache = new GenericTimeStampedCache<>(2, maxSlots, maxSpan, newSlotInterval,
92                  new TransformGenerator(2,
93                          interpolatingProvider,
94                          interpolatingProvider.getStep()));
95          this.fieldCaches = new HashMap<>();
96      }
97  
98      /** Get the underlying provider for raw (non-interpolated) transforms.
99       * @return provider for raw (non-interpolated) transforms
100      */
101     public TransformProvider getRawProvider() {
102         return interpolatingProvider.getRawProvider();
103     }
104 
105     /** Get the number of interpolation grid points.
106      * @return number of interpolation grid points
107      */
108     public int getGridPoints() {
109         return interpolatingProvider.getGridPoints();
110     }
111 
112     /** Get the grid points time step.
113      * @return grid points time step
114      */
115     public double getStep() {
116         return interpolatingProvider.getStep();
117     }
118 
119     /** {@inheritDoc} */
120     public Transform getTransform(final AbsoluteDate date) {
121         // retrieve a sample from the thread-safe cache
122         final Transform closest = cache.getNeighbors(date).reduce((t0, t1) ->
123             FastMath.abs(date.durationFrom(t0.getDate())) < FastMath.abs(date.durationFrom(t1.getDate())) ? t0 : t1
124         ).get();
125         return closest.shiftedBy(date.durationFrom(closest.getDate()));
126     }
127 
128     /** {@inheritDoc} */
129     @Override
130     public StaticTransform getStaticTransform(final AbsoluteDate date) {
131         // retrieve a sample from the thread-safe cache
132         final Transform closest = cache.getNeighbors(date).reduce((t0, t1) ->
133                 FastMath.abs(date.durationFrom(t0.getDate())) < FastMath.abs(date.durationFrom(t1.getDate())) ? t0 : t1
134         ).get();
135         return closest.staticShiftedBy(date.durationFrom(closest.getDate()));
136     }
137 
138     /** {@inheritDoc} */
139     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
140         @SuppressWarnings("unchecked")
141         GenericTimeStampedCache<FieldTransform<T>> fieldCache =
142             (GenericTimeStampedCache<FieldTransform<T>>) fieldCaches.get(date.getField());
143         if (fieldCache == null) {
144             fieldCache =
145                     new GenericTimeStampedCache<>(cache.getMaxNeighborsSize(),
146                             cache.getMaxSlots(),
147                             cache.getMaxSpan(),
148                             cache.getNewSlotQuantumGap(),
149                             new FieldTransformGenerator<>(date.getField(),
150                                     cache.getMaxNeighborsSize(),
151                                     interpolatingProvider,
152                                     interpolatingProvider.getStep()));
153             fieldCaches.put(date.getField(), fieldCache);
154         }
155 
156         // retrieve a sample from the thread-safe cache
157         final FieldTransform<T> closest = fieldCache.getNeighbors(date.toAbsoluteDate()).reduce((t0, t1) ->
158             date.durationFrom(t0.getDate()).abs().getReal() < date.durationFrom(t1.getDate()).abs().getReal() ?
159             t0 : t1
160         ).get();
161         return closest.shiftedBy(date.durationFrom(closest.getDate()));
162     }
163 
164     /** {@inheritDoc} */
165     @Override
166     public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
167         @SuppressWarnings("unchecked")
168         GenericTimeStampedCache<FieldTransform<T>> fieldCache =
169             (GenericTimeStampedCache<FieldTransform<T>>) fieldCaches.get(date.getField());
170         if (fieldCache == null) {
171             fieldCache =
172                     new GenericTimeStampedCache<>(cache.getMaxNeighborsSize(),
173                             cache.getMaxSlots(),
174                             cache.getMaxSpan(),
175                             cache.getNewSlotQuantumGap(),
176                             new FieldTransformGenerator<>(date.getField(),
177                                     cache.getMaxNeighborsSize(),
178                                     interpolatingProvider,
179                                     interpolatingProvider.getStep()));
180             fieldCaches.put(date.getField(), fieldCache);
181         }
182 
183         // retrieve a sample from the thread-safe cache
184         final FieldTransform<T> closest = fieldCache.getNeighbors(date.toAbsoluteDate()).reduce((t0, t1) ->
185             date.durationFrom(t0.getDate()).abs().getReal() < date.durationFrom(t1.getDate()).abs().getReal() ?
186             t0 : t1
187         ).get();
188         return closest.staticShiftedBy(date.durationFrom(closest.getDate()));
189     }
190 
191 }