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