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.apache.commons.math3.util.FastMath;
25 import org.orekit.errors.OrekitException;
26 import org.orekit.errors.OrekitExceptionWrapper;
27 import org.orekit.time.AbsoluteDate;
28 import org.orekit.utils.AngularDerivativesFilter;
29 import org.orekit.utils.CartesianDerivativesFilter;
30 import org.orekit.utils.GenericTimeStampedCache;
31 import org.orekit.utils.TimeStampedGenerator;
32
33 /** Transform provider using thread-safe shifts on transforms sample.
34 * <p>
35 * The shifts take derivatives into account, up to user specified order.
36 * </p>
37 * @see GenericTimeStampedCache
38 * @see InterpolatingTransformProvider
39 * @since 7.1
40 * @author Luc Maisonobe
41 */
42 public class ShiftingTransformProvider implements TransformProvider {
43
44 /** Serializable UID. */
45 private static final long serialVersionUID = 20150601L;
46
47 /** First level cache. */
48 private final InterpolatingTransformProvider interpolatingProvider;
49
50 /** Cache for sample points. */
51 private final transient GenericTimeStampedCache<Transform> cache;
52
53 /** Simple constructor.
54 * @param rawProvider provider for raw (non-interpolated) transforms
55 * @param cFilter filter for derivatives from the sample to use in interpolation
56 * @param aFilter filter for derivatives from the sample to use in interpolation
57 * @param earliest earliest supported date
58 * @param latest latest supported date
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 */
68 public ShiftingTransformProvider(final TransformProvider rawProvider,
69 final CartesianDerivativesFilter cFilter,
70 final AngularDerivativesFilter aFilter,
71 final AbsoluteDate earliest, final AbsoluteDate latest,
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 earliest, latest, gridPoints, step,
76 maxSlots, maxSpan, newSlotInterval),
77 maxSlots, maxSpan, newSlotInterval);
78 }
79
80 /** Simple constructor.
81 * @param interpolatingProvider first level cache provider
82 * @param maxSlots maximum number of independent cached time slots
83 * in the {@link GenericTimeStampedCache time-stamped cache}
84 * @param maxSpan maximum duration span in seconds of one slot
85 * in the {@link GenericTimeStampedCache time-stamped cache}
86 * @param newSlotInterval time interval above which a new slot is created
87 * in the {@link GenericTimeStampedCache time-stamped cache}
88 */
89 private ShiftingTransformProvider(final InterpolatingTransformProvider interpolatingProvider,
90 final int maxSlots, final double maxSpan, final double newSlotInterval) {
91 this.interpolatingProvider = interpolatingProvider;
92 this.cache = new GenericTimeStampedCache<Transform>(2, maxSlots, maxSpan, newSlotInterval,
93 new Generator(), Transform.class);
94 }
95
96 /** Get the underlying provider for raw (non-interpolated) transforms.
97 * @return provider for raw (non-interpolated) transforms
98 */
99 public TransformProvider getRawProvider() {
100 return interpolatingProvider.getRawProvider();
101 }
102
103 /** Get the number of interpolation grid points.
104 * @return number of interpolation grid points
105 */
106 public int getGridPoints() {
107 return interpolatingProvider.getGridPoints();
108 }
109
110 /** Get the grid points time step.
111 * @return grid points time step
112 */
113 public double getStep() {
114 return interpolatingProvider.getStep();
115 }
116
117 /** {@inheritDoc} */
118 public Transform getTransform(final AbsoluteDate date) throws OrekitException {
119 try {
120
121 // retrieve a sample from the thread-safe cache
122 final List<Transform> sample = cache.getNeighbors(date);
123 final double dt0 = date.durationFrom(sample.get(0).getDate());
124 final double dt1 = date.durationFrom(sample.get(1).getDate());
125 if (FastMath.abs(dt0) < FastMath.abs(dt1)) {
126 return sample.get(0).shiftedBy(dt0);
127 } else {
128 return sample.get(1).shiftedBy(dt1);
129 }
130
131 } catch (OrekitExceptionWrapper oew) {
132 // something went wrong while generating the sample,
133 // we just forward the exception up
134 throw oew.getException();
135 }
136 }
137
138 /** Replace the instance with a data transfer object for serialization.
139 * <p>
140 * This intermediate class serializes only the data needed for generation,
141 * but does <em>not</em> serializes the cache itself (in fact the cache is
142 * not serializable).
143 * </p>
144 * @return data transfer object that will be serialized
145 */
146 private Object writeReplace() {
147 return new DTO(interpolatingProvider,
148 cache.getMaxSlots(), cache.getMaxSpan(), cache.getNewSlotQuantumGap());
149 }
150
151 /** Internal class used only for serialization. */
152 private static class DTO implements Serializable {
153
154 /** Serializable UID. */
155 private static final long serialVersionUID = 20150601L;
156
157 /** Provider for raw (non-interpolated) transforms. */
158 private final InterpolatingTransformProvider interpolatingProvider;
159
160 /** Maximum number of independent cached time slots. */
161 private final int maxSlots;
162
163 /** Maximum duration span in seconds of one slot. */
164 private final double maxSpan;
165
166 /** Time interval above which a new slot is created. */
167 private final double newSlotInterval;
168
169 /** Simple constructor.
170 * @param interpolatingProvider first level cache provider
171 * @param maxSlots maximum number of independent cached time slots
172 * in the {@link GenericTimeStampedCache time-stamped cache}
173 * @param maxSpan maximum duration span in seconds of one slot
174 * in the {@link GenericTimeStampedCache time-stamped cache}
175 * @param newSlotInterval time interval above which a new slot is created
176 * in the {@link GenericTimeStampedCache time-stamped cache}
177 */
178 private DTO(final InterpolatingTransformProvider interpolatingProvider,
179 final int maxSlots, final double maxSpan, final double newSlotInterval) {
180 this.interpolatingProvider = interpolatingProvider;
181 this.maxSlots = maxSlots;
182 this.maxSpan = maxSpan;
183 this.newSlotInterval = newSlotInterval;
184 }
185
186 /** Replace the deserialized data transfer object with a {@link ShiftingTransformProvider}.
187 * @return replacement {@link ShiftingTransformProvider}
188 */
189 private Object readResolve() {
190 // build a new provider, with an empty cache
191 return new ShiftingTransformProvider(interpolatingProvider,
192 maxSlots, maxSpan, newSlotInterval);
193 }
194
195 }
196
197 /** Local generator for thread-safe cache. */
198 private class Generator implements TimeStampedGenerator<Transform> {
199
200 /** {@inheritDoc} */
201 public List<Transform> generate(final Transform existing, final AbsoluteDate date) {
202
203 try {
204 final List<Transform> generated = new ArrayList<Transform>();
205
206 if (existing == null) {
207
208 // no prior existing transforms, just generate a first set
209 for (int i = 0; i < cache.getNeighborsSize(); ++i) {
210 generated.add(interpolatingProvider.getTransform(date.shiftedBy(i * interpolatingProvider.getStep())));
211 }
212
213 } else {
214
215 // some transforms have already been generated
216 // add the missing ones up to specified date
217
218 AbsoluteDate t = existing.getDate();
219 if (date.compareTo(t) > 0) {
220 // forward generation
221 do {
222 t = t.shiftedBy(interpolatingProvider.getStep());
223 generated.add(generated.size(), interpolatingProvider.getTransform(t));
224 } while (t.compareTo(date) <= 0);
225 } else {
226 // backward generation
227 do {
228 t = t.shiftedBy(-interpolatingProvider.getStep());
229 generated.add(0, interpolatingProvider.getTransform(t));
230 } while (t.compareTo(date) >= 0);
231 }
232 }
233
234 // return the generated transforms
235 return generated;
236 } catch (OrekitException oe) {
237 throw new OrekitExceptionWrapper(oe);
238 }
239
240 }
241
242 }
243
244 }