1   /* Copyright 2002-2016 CS Systèmes d'Information
2    * Licensed to CS Systèmes d'Information (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.io.Serializable;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.orekit.errors.OrekitException;
25  import org.orekit.errors.OrekitExceptionWrapper;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.utils.AngularDerivativesFilter;
28  import org.orekit.utils.CartesianDerivativesFilter;
29  import org.orekit.utils.GenericTimeStampedCache;
30  import org.orekit.utils.TimeStampedGenerator;
31  
32  /** Transform provider using thread-safe interpolation on transforms sample.
33   * <p>
34   * The interpolation is a polynomial Hermite interpolation, which
35   * can either use or ignore the derivatives provided by the raw
36   * provider. This means that simple raw providers that do not compute
37   * derivatives can be used, the derivatives will be added appropriately
38   * by the interpolation process.
39   * </p>
40   * @see GenericTimeStampedCache
41   * @see ShiftingTransformProvider
42   * @author Luc Maisonobe
43   */
44  public class InterpolatingTransformProvider implements TransformProvider {
45  
46      /** Serializable UID. */
47      private static final long serialVersionUID = 20140723L;
48  
49      /** Provider for raw (non-interpolated) transforms. */
50      private final TransformProvider rawProvider;
51  
52      /** Filter for Cartesian derivatives to use in interpolation. */
53      private final CartesianDerivativesFilter cFilter;
54  
55      /** Filter for angular derivatives to use in interpolation. */
56      private final AngularDerivativesFilter aFilter;
57  
58      /** Earliest supported date. */
59      private final AbsoluteDate earliest;
60  
61      /** Latest supported date. */
62      private final AbsoluteDate latest;
63  
64      /** Grid points time step. */
65      private final double step;
66  
67      /** Cache for sample points. */
68      private final transient GenericTimeStampedCache<Transform> cache;
69  
70      /** Simple constructor.
71       * @param rawProvider provider for raw (non-interpolated) transforms
72       * @param useVelocities if true, use sample transforms velocities,
73       * otherwise ignore them and use only positions
74       * @param useRotationRates if true, use sample points rotation rates,
75       * otherwise ignore them and use only rotations
76       * @param earliest earliest supported date
77       * @param latest latest supported date
78       * @param gridPoints number of interpolation grid points
79       * @param step grid points time step
80       * @param maxSlots maximum number of independent cached time slots
81       * in the {@link GenericTimeStampedCache time-stamped cache}
82       * @param maxSpan maximum duration span in seconds of one slot
83       * in the {@link GenericTimeStampedCache time-stamped cache}
84       * @param newSlotInterval time interval above which a new slot is created
85       * in the {@link GenericTimeStampedCache time-stamped cache}
86       * @deprecated as of 7.0, replaced with {@link #InterpolatingTransformProvider(TransformProvider,
87       * CartesianDerivativesFilter, AngularDerivativesFilter, AbsoluteDate, AbsoluteDate,
88       * int, double, int, double, double)}
89       */
90      @Deprecated
91      public InterpolatingTransformProvider(final TransformProvider rawProvider,
92                                            final boolean useVelocities, final boolean useRotationRates,
93                                            final AbsoluteDate earliest, final AbsoluteDate latest,
94                                            final int gridPoints, final double step,
95                                            final int maxSlots, final double maxSpan, final double newSlotInterval) {
96          this(rawProvider,
97               useVelocities ? CartesianDerivativesFilter.USE_PV : CartesianDerivativesFilter.USE_P,
98               useRotationRates ? AngularDerivativesFilter.USE_RR : AngularDerivativesFilter.USE_R,
99               earliest, latest, gridPoints, step, maxSlots, maxSpan, newSlotInterval);
100     }
101 
102     /** Simple constructor.
103      * @param rawProvider provider for raw (non-interpolated) transforms
104      * @param cFilter filter for derivatives from the sample to use in interpolation
105      * @param aFilter filter for derivatives from the sample to use in interpolation
106      * @param earliest earliest supported date
107      * @param latest latest supported date
108      * @param gridPoints number of interpolation grid points
109      * @param step grid points time step
110      * @param maxSlots maximum number of independent cached time slots
111      * in the {@link GenericTimeStampedCache time-stamped cache}
112      * @param maxSpan maximum duration span in seconds of one slot
113      * in the {@link GenericTimeStampedCache time-stamped cache}
114      * @param newSlotInterval time interval above which a new slot is created
115      * in the {@link GenericTimeStampedCache time-stamped cache}
116      */
117     public InterpolatingTransformProvider(final TransformProvider rawProvider,
118                                           final CartesianDerivativesFilter cFilter,
119                                           final AngularDerivativesFilter aFilter,
120                                           final AbsoluteDate earliest, final AbsoluteDate latest,
121                                           final int gridPoints, final double step,
122                                           final int maxSlots, final double maxSpan, final double newSlotInterval) {
123         this.rawProvider = rawProvider;
124         this.cFilter     = cFilter;
125         this.aFilter     = aFilter;
126         this.earliest    = earliest;
127         this.latest      = latest;
128         this.step        = step;
129         this.cache       = new GenericTimeStampedCache<Transform>(gridPoints, maxSlots, maxSpan, newSlotInterval,
130                                                                   new Generator(), Transform.class);
131     }
132 
133     /** Get the underlying provider for raw (non-interpolated) transforms.
134      * @return provider for raw (non-interpolated) transforms
135      */
136     public TransformProvider getRawProvider() {
137         return rawProvider;
138     }
139 
140     /** Get the number of interpolation grid points.
141      * @return number of interpolation grid points
142      */
143     public int getGridPoints() {
144         return cache.getNeighborsSize();
145     }
146 
147     /** Get the grid points time step.
148      * @return grid points time step
149      */
150     public double getStep() {
151         return step;
152     }
153 
154     /** {@inheritDoc} */
155     public Transform getTransform(final AbsoluteDate date) throws OrekitException {
156         try {
157 
158             // retrieve a sample from the thread-safe cache
159             final List<Transform> sample = cache.getNeighbors(date);
160 
161             // interpolate to specified date
162             return Transform.interpolate(date, cFilter, aFilter, sample);
163 
164         } catch (OrekitExceptionWrapper oew) {
165             // something went wrong while generating the sample,
166             // we just forward the exception up
167             throw oew.getException();
168         }
169     }
170 
171     /** Replace the instance with a data transfer object for serialization.
172      * <p>
173      * This intermediate class serializes only the data needed for generation,
174      * but does <em>not</em> serializes the cache itself (in fact the cache is
175      * not serializable).
176      * </p>
177      * @return data transfer object that will be serialized
178      */
179     private Object writeReplace() {
180         return new DTO(rawProvider, cFilter.getMaxOrder(), aFilter.getMaxOrder(),
181                        earliest, latest, cache.getNeighborsSize(), step,
182                        cache.getMaxSlots(), cache.getMaxSpan(), cache.getNewSlotQuantumGap());
183     }
184 
185     /** Internal class used only for serialization. */
186     private static class DTO implements Serializable {
187 
188         /** Serializable UID. */
189         private static final long serialVersionUID = 20140723L;
190 
191         /** Provider for raw (non-interpolated) transforms. */
192         private final TransformProvider rawProvider;
193 
194         /** Cartesian derivatives to use in interpolation. */
195         private final int cDerivatives;
196 
197         /** Angular derivatives to use in interpolation. */
198         private final int aDerivatives;
199 
200         /** Earliest supported date. */
201         private final AbsoluteDate earliest;
202 
203         /** Latest supported date. */
204         private final AbsoluteDate latest;
205 
206         /** Number of grid points. */
207         private final int gridPoints;
208 
209         /** Grid points time step. */
210         private final double step;
211 
212         /** Maximum number of independent cached time slots. */
213         private final int maxSlots;
214 
215         /** Maximum duration span in seconds of one slot. */
216         private final double maxSpan;
217 
218         /** Time interval above which a new slot is created. */
219         private final double newSlotInterval;
220 
221         /** Simple constructor.
222          * @param rawProvider provider for raw (non-interpolated) transforms
223          * @param cDerivatives derivation order for Cartesian coordinates
224          * @param aDerivatives derivation order for angular coordinates
225          * @param earliest earliest supported date
226          * @param latest latest supported date
227          * @param gridPoints number of interpolation grid points
228          * @param step grid points time step
229          * @param maxSlots maximum number of independent cached time slots
230          * in the {@link GenericTimeStampedCache time-stamped cache}
231          * @param maxSpan maximum duration span in seconds of one slot
232          * in the {@link GenericTimeStampedCache time-stamped cache}
233          * @param newSlotInterval time interval above which a new slot is created
234          * in the {@link GenericTimeStampedCache time-stamped cache}
235          */
236         private DTO(final TransformProvider rawProvider, final int cDerivatives, final int aDerivatives,
237                     final AbsoluteDate earliest, final AbsoluteDate latest,
238                     final int gridPoints, final double step,
239                     final int maxSlots, final double maxSpan, final double newSlotInterval) {
240             this.rawProvider      = rawProvider;
241             this.cDerivatives     = cDerivatives;
242             this.aDerivatives     = aDerivatives;
243             this.earliest         = earliest;
244             this.latest           = latest;
245             this.gridPoints       = gridPoints;
246             this.step             = step;
247             this.maxSlots         = maxSlots;
248             this.maxSpan          = maxSpan;
249             this.newSlotInterval  = newSlotInterval;
250         }
251 
252         /** Replace the deserialized data transfer object with a {@link InterpolatingTransformProvider}.
253          * @return replacement {@link InterpolatingTransformProvider}
254          */
255         private Object readResolve() {
256             // build a new provider, with an empty cache
257             return new InterpolatingTransformProvider(rawProvider,
258                                                       CartesianDerivativesFilter.getFilter(cDerivatives),
259                                                       AngularDerivativesFilter.getFilter(aDerivatives),
260                                                       earliest, latest, gridPoints, step,
261                                                       maxSlots, maxSpan, newSlotInterval);
262         }
263 
264     }
265 
266     /** Local generator for thread-safe cache. */
267     private class Generator implements TimeStampedGenerator<Transform> {
268 
269         /** {@inheritDoc} */
270         public List<Transform> generate(final Transform existing, final AbsoluteDate date) {
271 
272             try {
273                 final List<Transform> generated = new ArrayList<Transform>();
274 
275                 if (existing == null) {
276 
277                     // no prior existing transforms, just generate a first set
278                     for (int i = 0; i < cache.getNeighborsSize(); ++i) {
279                         generated.add(rawProvider.getTransform(date.shiftedBy(i * step)));
280                     }
281 
282                 } else {
283 
284                     // some transforms have already been generated
285                     // add the missing ones up to specified date
286 
287                     AbsoluteDate t = existing.getDate();
288                     if (date.compareTo(t) > 0) {
289                         // forward generation
290                         do {
291                             t = t.shiftedBy(step);
292                             generated.add(generated.size(), rawProvider.getTransform(t));
293                         } while (t.compareTo(date) <= 0);
294                     } else {
295                         // backward generation
296                         do {
297                             t = t.shiftedBy(-step);
298                             generated.add(0, rawProvider.getTransform(t));
299                         } while (t.compareTo(date) >= 0);
300                     }
301                 }
302 
303                 // return the generated transforms
304                 return generated;
305             } catch (OrekitException oe) {
306                 throw new OrekitExceptionWrapper(oe);
307             }
308 
309         }
310 
311     }
312 
313 }