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