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}&lt;{@link Derivative}&gt;.
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