1 /* Copyright 2002-2024 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 package org.orekit.utils;
18
19 import java.io.Serializable;
20
21 import org.hipparchus.analysis.differentiation.Derivative;
22 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
23 import org.hipparchus.geometry.euclidean.threed.Vector3D;
24 import org.hipparchus.util.FastMath;
25 import org.orekit.annotation.DefaultDataContext;
26 import org.orekit.data.DataContext;
27 import org.orekit.errors.OrekitException;
28 import org.orekit.errors.OrekitIllegalArgumentException;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.frames.Frame;
31 import org.orekit.frames.StaticTransform;
32 import org.orekit.frames.Transform;
33 import org.orekit.time.AbsoluteDate;
34 import org.orekit.time.TimeStamped;
35
36 /** Position - Velocity - Acceleration linked to a date and a frame.
37 */
38 public class AbsolutePVCoordinates extends TimeStampedPVCoordinates
39 implements TimeStamped, Serializable, PVCoordinatesProvider {
40
41 /** Serializable UID. */
42 private static final long serialVersionUID = 20150824L;
43
44 /** Frame in which are defined the coordinates. */
45 private final Frame frame;
46
47 /** Build from position, velocity, acceleration.
48 * @param frame the frame in which the coordinates are defined
49 * @param date coordinates date
50 * @param position the position vector (m)
51 * @param velocity the velocity vector (m/s)
52 * @param acceleration the acceleration vector (m/sÂý)
53 */
54 public AbsolutePVCoordinates(final Frame frame, final AbsoluteDate date,
55 final Vector3D position, final Vector3D velocity, final Vector3D acceleration) {
56 super(date, position, velocity, acceleration);
57 this.frame = frame;
58 }
59
60 /** Build from position and velocity. Acceleration is set to zero.
61 * @param frame the frame in which the coordinates are defined
62 * @param date coordinates date
63 * @param position the position vector (m)
64 * @param velocity the velocity vector (m/s)
65 */
66 public AbsolutePVCoordinates(final Frame frame, final AbsoluteDate date,
67 final Vector3D position,
68 final Vector3D velocity) {
69 this(frame, date, position, velocity, Vector3D.ZERO);
70 }
71
72 /** Build from frame, date and PVA coordinates.
73 * @param frame the frame in which the coordinates are defined
74 * @param date date of the coordinates
75 * @param pva TimeStampedPVCoordinates
76 */
77 public AbsolutePVCoordinates(final Frame frame, final AbsoluteDate date, final PVCoordinates pva) {
78 super(date, pva);
79 this.frame = frame;
80 }
81
82 /** Build from frame and TimeStampedPVCoordinates.
83 * @param frame the frame in which the coordinates are defined
84 * @param pva TimeStampedPVCoordinates
85 */
86 public AbsolutePVCoordinates(final Frame frame, final TimeStampedPVCoordinates pva) {
87 super(pva.getDate(), pva);
88 this.frame = frame;
89 }
90
91 /** Multiplicative constructor
92 * <p>Build a AbsolutePVCoordinates from another one and a scale factor.</p>
93 * <p>The TimeStampedPVCoordinates built will be a * AbsPva</p>
94 * @param date date of the built coordinates
95 * @param a scale factor
96 * @param AbsPva base (unscaled) AbsolutePVCoordinates
97 */
98 public AbsolutePVCoordinates(final AbsoluteDate date,
99 final double a, final AbsolutePVCoordinates AbsPva) {
100 super(date, a, AbsPva);
101 this.frame = AbsPva.frame;
102 }
103
104 /** Subtractive constructor
105 * <p>Build a relative AbsolutePVCoordinates from a start and an end position.</p>
106 * <p>The AbsolutePVCoordinates built will be end - start.</p>
107 * <p>In case start and end use two different pseudo-inertial frames,
108 * the new AbsolutePVCoordinates arbitrarily be defined in the start frame. </p>
109 * @param date date of the built coordinates
110 * @param start Starting AbsolutePVCoordinates
111 * @param end ending AbsolutePVCoordinates
112 */
113 public AbsolutePVCoordinates(final AbsoluteDate date,
114 final AbsolutePVCoordinates start, final AbsolutePVCoordinates end) {
115 super(date, start, end);
116 ensureIdenticalFrames(start, end);
117 this.frame = start.frame;
118 }
119
120 /** Linear constructor
121 * <p>Build a AbsolutePVCoordinates from two other ones and corresponding scale factors.</p>
122 * <p>The AbsolutePVCoordinates built will be a1 * u1 + a2 * u2</p>
123 * <p>In case the AbsolutePVCoordinates use different pseudo-inertial frames,
124 * the new AbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
125 * @param date date of the built coordinates
126 * @param a1 first scale factor
127 * @param absPv1 first base (unscaled) AbsolutePVCoordinates
128 * @param a2 second scale factor
129 * @param absPv2 second base (unscaled) AbsolutePVCoordinates
130 */
131 public AbsolutePVCoordinates(final AbsoluteDate date,
132 final double a1, final AbsolutePVCoordinates absPv1,
133 final double a2, final AbsolutePVCoordinates absPv2) {
134 super(date, a1, absPv1.getPVCoordinates(), a2, absPv2.getPVCoordinates());
135 ensureIdenticalFrames(absPv1, absPv2);
136 this.frame = absPv1.getFrame();
137 }
138
139 /** Linear constructor
140 * <p>Build a AbsolutePVCoordinates from three other ones and corresponding scale factors.</p>
141 * <p>The AbsolutePVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
142 * <p>In case the AbsolutePVCoordinates use different pseudo-inertial frames,
143 * the new AbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
144 * @param date date of the built coordinates
145 * @param a1 first scale factor
146 * @param absPv1 first base (unscaled) AbsolutePVCoordinates
147 * @param a2 second scale factor
148 * @param absPv2 second base (unscaled) AbsolutePVCoordinates
149 * @param a3 third scale factor
150 * @param absPv3 third base (unscaled) AbsolutePVCoordinates
151 */
152 public AbsolutePVCoordinates(final AbsoluteDate date,
153 final double a1, final AbsolutePVCoordinates absPv1,
154 final double a2, final AbsolutePVCoordinates absPv2,
155 final double a3, final AbsolutePVCoordinates absPv3) {
156 super(date, a1, absPv1.getPVCoordinates(), a2, absPv2.getPVCoordinates(),
157 a3, absPv3.getPVCoordinates());
158 ensureIdenticalFrames(absPv1, absPv2);
159 ensureIdenticalFrames(absPv1, absPv3);
160 this.frame = absPv1.getFrame();
161 }
162
163 /** Linear constructor
164 * <p>Build a AbsolutePVCoordinates from four other ones and corresponding scale factors.</p>
165 * <p>The AbsolutePVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
166 * <p>In case the AbsolutePVCoordinates use different pseudo-inertial frames,
167 * the new AbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
168 * @param date date of the built coordinates
169 * @param a1 first scale factor
170 * @param absPv1 first base (unscaled) AbsolutePVCoordinates
171 * @param a2 second scale factor
172 * @param absPv2 second base (unscaled) AbsolutePVCoordinates
173 * @param a3 third scale factor
174 * @param absPv3 third base (unscaled) AbsolutePVCoordinates
175 * @param a4 fourth scale factor
176 * @param absPv4 fourth base (unscaled) AbsolutePVCoordinates
177 */
178 public AbsolutePVCoordinates(final AbsoluteDate date,
179 final double a1, final AbsolutePVCoordinates absPv1,
180 final double a2, final AbsolutePVCoordinates absPv2,
181 final double a3, final AbsolutePVCoordinates absPv3,
182 final double a4, final AbsolutePVCoordinates absPv4) {
183 super(date, a1, absPv1.getPVCoordinates(), a2, absPv2.getPVCoordinates(),
184 a3, absPv3.getPVCoordinates(), a4, absPv4.getPVCoordinates());
185 ensureIdenticalFrames(absPv1, absPv2);
186 ensureIdenticalFrames(absPv1, absPv3);
187 ensureIdenticalFrames(absPv1, absPv4);
188 this.frame = absPv1.getFrame();
189 }
190
191 /** Builds a AbsolutePVCoordinates triplet from a {@link FieldVector3D}<{@link Derivative}>.
192 * <p>
193 * The vector components must have time as their only derivation parameter and
194 * have consistent derivation orders.
195 * </p>
196 * @param frame the frame in which the parameters are defined
197 * @param date date of the built coordinates
198 * @param p vector with time-derivatives embedded within the coordinates
199 * @param <U> type of the derivative
200 */
201 public <U extends Derivative<U>> AbsolutePVCoordinates(final Frame frame, final AbsoluteDate date,
202 final FieldVector3D<U> p) {
203 super(date, p);
204 this.frame = frame;
205 }
206
207 /** Ensure that the frames from two AbsolutePVCoordinates are identical.
208 * @param absPv1 first AbsolutePVCoordinates
209 * @param absPv2 first AbsolutePVCoordinates
210 * @throws OrekitIllegalArgumentException if frames are different
211 */
212 private static void ensureIdenticalFrames(final AbsolutePVCoordinates absPv1, final AbsolutePVCoordinates absPv2)
213 throws OrekitIllegalArgumentException {
214 if (!absPv1.frame.equals(absPv2.frame)) {
215 throw new OrekitIllegalArgumentException(OrekitMessages.INCOMPATIBLE_FRAMES,
216 absPv1.frame.getName(), absPv2.frame.getName());
217 }
218 }
219
220 /** Get a time-shifted state.
221 * <p>
222 * The state can be slightly shifted to close dates. This shift is based on
223 * a simple Taylor expansion. It is <em>not</em> intended as a replacement for
224 * proper orbit propagation (it is not even Keplerian!) but should be sufficient
225 * for either small time shifts or coarse accuracy.
226 * </p>
227 * @param dt time shift in seconds
228 * @return a new state, shifted with respect to the instance (which is immutable)
229 */
230 public AbsolutePVCoordinates shiftedBy(final double dt) {
231 final TimeStampedPVCoordinates spv = super.shiftedBy(dt);
232 return new AbsolutePVCoordinates(frame, spv);
233 }
234
235 /** Create a local provider using simply Taylor expansion through {@link #shiftedBy(double)}.
236 * <p>
237 * The time evolution is based on a simple Taylor expansion. It is <em>not</em> intended as a
238 * replacement for proper orbit propagation (it is not even Keplerian!) but should be sufficient
239 * for either small time shifts or coarse accuracy.
240 * </p>
241 * @return provider based on Taylor expansion, for small time shifts around instance date
242 */
243 public PVCoordinatesProvider toTaylorProvider() {
244 return new PVCoordinatesProvider() {
245 /** {@inheritDoc} */
246 public Vector3D getPosition(final AbsoluteDate d, final Frame f) {
247 final TimeStampedPVCoordinates shifted = shiftedBy(d.durationFrom(getDate()));
248 final StaticTransform transform = frame.getStaticTransformTo(f, d);
249 return transform.transformPosition(shifted.getPosition());
250 }
251 /** {@inheritDoc} */
252 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate d, final Frame f) {
253 final TimeStampedPVCoordinates shifted = shiftedBy(d.durationFrom(getDate()));
254 final Transform transform = frame.getTransformTo(f, d);
255 return transform.transformPVCoordinates(shifted);
256 }
257 };
258 }
259
260 /** Get the frame in which the coordinates are defined.
261 * @return frame in which the coordinates are defined
262 */
263 public Frame getFrame() {
264 return frame;
265 }
266
267 /** Get the TimeStampedPVCoordinates.
268 * @return TimeStampedPVCoordinates
269 */
270 public TimeStampedPVCoordinates getPVCoordinates() {
271 return this;
272 }
273
274 /** Get the position in a specified frame.
275 * @param outputFrame frame in which the position coordinates shall be computed
276 * @return position
277 * @see #getPVCoordinates(Frame)
278 * @since 12.0
279 */
280 public Vector3D getPosition(final Frame outputFrame) {
281 // If output frame requested is the same as definition frame,
282 // Position vector is returned directly
283 if (outputFrame == frame) {
284 return getPosition();
285 }
286
287 // Else, position vector is transformed to output frame
288 final StaticTransform t = frame.getStaticTransformTo(outputFrame, getDate());
289 return t.transformPosition(getPosition());
290 }
291
292 /** Get the TimeStampedPVCoordinates in a specified frame.
293 * @param outputFrame frame in which the position/velocity coordinates shall be computed
294 * @return TimeStampedPVCoordinates
295 * @exception OrekitException if transformation between frames cannot be computed
296 * @see #getPVCoordinates()
297 */
298 public TimeStampedPVCoordinates getPVCoordinates(final Frame outputFrame) {
299 // If output frame requested is the same as definition frame,
300 // PV coordinates are returned directly
301 if (outputFrame == frame) {
302 return getPVCoordinates();
303 }
304
305 // Else, PV coordinates are transformed to output frame
306 final Transform t = frame.getTransformTo(outputFrame, getDate());
307 return t.transformPVCoordinates(getPVCoordinates());
308 }
309
310 @Override
311 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate otherDate, final Frame outputFrame) {
312 return shiftedBy(otherDate.durationFrom(getDate())).getPVCoordinates(outputFrame);
313 }
314
315 /** Replace the instance with a data transfer object for serialization.
316 * @return data transfer object that will be serialized
317 */
318 @DefaultDataContext
319 private Object writeReplace() {
320 return new DTO(this);
321 }
322
323 /** Internal class used only for serialization. */
324 @DefaultDataContext
325 private static class DTO implements Serializable {
326
327 /** Serializable UID. */
328 private static final long serialVersionUID = 20150916L;
329
330 /** Double values. */
331 private double[] d;
332
333 /** Frame in which acoordinates are defined. */
334 private final Frame frame;
335
336 /** Simple constructor.
337 * @param absPva instance to serialize
338 */
339 private DTO(final AbsolutePVCoordinates absPva) {
340
341 // decompose date
342 final AbsoluteDate j2000Epoch =
343 DataContext.getDefault().getTimeScales().getJ2000Epoch();
344 final double epoch = FastMath.floor(absPva.getDate().durationFrom(j2000Epoch));
345 final double offset = absPva.getDate().durationFrom(j2000Epoch.shiftedBy(epoch));
346
347 this.d = new double[] {
348 epoch, offset,
349 absPva.getPosition().getX(), absPva.getPosition().getY(), absPva.getPosition().getZ(),
350 absPva.getVelocity().getX(), absPva.getVelocity().getY(), absPva.getVelocity().getZ(),
351 absPva.getAcceleration().getX(), absPva.getAcceleration().getY(), absPva.getAcceleration().getZ()
352 };
353 this.frame = absPva.frame;
354
355 }
356
357 /** Replace the deserialized data transfer object with a {@link AbsolutePVCoordinates}.
358 * @return replacement {@link AbsolutePVCoordinates}
359 */
360 private Object readResolve() {
361 final AbsoluteDate j2000Epoch =
362 DataContext.getDefault().getTimeScales().getJ2000Epoch();
363 return new AbsolutePVCoordinates(frame,
364 j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]),
365 new Vector3D(d[2], d[3], d[ 4]),
366 new Vector3D(d[5], d[6], d[ 7]),
367 new Vector3D(d[8], d[9], d[10]));
368 }
369
370 }
371
372 }
373
374
375