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.List;
22  import java.util.Map;
23  import java.util.stream.Collectors;
24  import java.util.stream.Stream;
25  
26  import org.hipparchus.Field;
27  import org.hipparchus.CalculusFieldElement;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.time.FieldAbsoluteDate;
30  import org.orekit.utils.AngularDerivativesFilter;
31  import org.orekit.utils.CartesianDerivativesFilter;
32  import org.orekit.utils.GenericTimeStampedCache;
33  
34  /** Transform provider using thread-safe interpolation on transforms sample.
35   * <p>
36   * The interpolation is a polynomial Hermite interpolation, which
37   * can either use or ignore the derivatives provided by the raw
38   * provider. This means that simple raw providers that do not compute
39   * derivatives can be used, the derivatives will be added appropriately
40   * by the interpolation process.
41   * </p>
42   * @see GenericTimeStampedCache
43   * @see ShiftingTransformProvider
44   * @author Luc Maisonobe
45   */
46  public class InterpolatingTransformProvider implements TransformProvider {
47  
48      /** Provider for raw (non-interpolated) transforms. */
49      private final TransformProvider rawProvider;
50  
51      /** Filter for Cartesian derivatives to use in interpolation. */
52      private final CartesianDerivativesFilter cFilter;
53  
54      /** Filter for angular derivatives to use in interpolation. */
55      private final AngularDerivativesFilter aFilter;
56  
57      /** Grid points time step. */
58      private final double step;
59  
60      /** Cache for sample points. */
61      private final GenericTimeStampedCache<Transform> cache;
62  
63      /** Field caches for sample points. */
64      // we use Object as the value of fieldCaches because despite numerous attempts,
65      // we could not find a way to use GenericTimeStampedCache<FieldTransform<? extends CalculusFieldElement<?>>
66      // without the compiler complaining
67      private final Map<Field<? extends CalculusFieldElement<?>>, Object> fieldCaches;
68  
69      /** Simple constructor.
70       * @param rawProvider provider for raw (non-interpolated) transforms
71       * @param cFilter filter for derivatives from the sample to use in interpolation
72       * @param aFilter filter for derivatives from the sample to use in interpolation
73       * @param gridPoints number of interpolation grid points
74       * @param step grid points time step
75       * @param maxSlots maximum number of independent cached time slots
76       * in the {@link GenericTimeStampedCache time-stamped cache}
77       * @param maxSpan maximum duration span in seconds of one slot
78       * in the {@link GenericTimeStampedCache time-stamped cache}
79       * @param newSlotInterval time interval above which a new slot is created
80       * in the {@link GenericTimeStampedCache time-stamped cache}
81       * @since 9.1
82       */
83      public InterpolatingTransformProvider(final TransformProvider rawProvider,
84                                            final CartesianDerivativesFilter cFilter,
85                                            final AngularDerivativesFilter aFilter,
86                                            final int gridPoints, final double step,
87                                            final int maxSlots, final double maxSpan, final double newSlotInterval) {
88          this.rawProvider = rawProvider;
89          this.cFilter     = cFilter;
90          this.aFilter     = aFilter;
91          this.step        = step;
92          this.cache       = new GenericTimeStampedCache<>(gridPoints, maxSlots, maxSpan, newSlotInterval,
93                  new TransformGenerator(gridPoints,
94                          rawProvider,
95                          step));
96          this.fieldCaches = new HashMap<>();
97      }
98  
99      /** Get the underlying provider for raw (non-interpolated) transforms.
100      * @return provider for raw (non-interpolated) transforms
101      */
102     public TransformProvider getRawProvider() {
103         return rawProvider;
104     }
105 
106     /** Get the number of interpolation grid points.
107      * @return number of interpolation grid points
108      */
109     public int getGridPoints() {
110         return cache.getMaxNeighborsSize();
111     }
112 
113     /** Get the grid points time step.
114      * @return grid points time step
115      */
116     public double getStep() {
117         return step;
118     }
119 
120     /** {@inheritDoc} */
121     @Override
122     public Transform getTransform(final AbsoluteDate date) {
123         // retrieve a sample from the thread-safe cache
124         final List<Transform> sample = cache.getNeighbors(date).collect(Collectors.toList());
125 
126         // interpolate to specified date
127         return Transform.interpolate(date, cFilter, aFilter, sample);
128     }
129 
130     /** {@inheritDoc} */
131     @Override
132     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
133         @SuppressWarnings("unchecked")
134         GenericTimeStampedCache<FieldTransform<T>> fieldCache =
135             (GenericTimeStampedCache<FieldTransform<T>>) fieldCaches.get(date.getField());
136         if (fieldCache == null) {
137             fieldCache =
138                     new GenericTimeStampedCache<>(cache.getMaxNeighborsSize(),
139                             cache.getMaxSlots(),
140                             cache.getMaxSpan(),
141                             cache.getNewSlotQuantumGap(),
142                             new FieldTransformGenerator<>(date.getField(),
143                                     cache.getMaxNeighborsSize(),
144                                     rawProvider,
145                                     step));
146             fieldCaches.put(date.getField(), fieldCache);
147         }
148 
149         // retrieve a sample from the thread-safe cache
150         final Stream<FieldTransform<T>> sample = fieldCache.getNeighbors(date.toAbsoluteDate());
151 
152         // interpolate to specified date
153         return FieldTransform.interpolate(date, cFilter, aFilter, sample);
154     }
155 
156 }