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.annotation.DefaultDataContext;
23  import org.orekit.errors.OrekitIllegalArgumentException;
24  import org.orekit.errors.OrekitMessages;
25  import org.orekit.frames.Frame;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.time.TimeOffset;
28  
29  /** Position - Velocity - Acceleration linked to a date and a frame.
30   */
31  public class AbsolutePVCoordinates implements ShiftablePVCoordinatesHolder<AbsolutePVCoordinates>, PVCoordinatesProvider {
32  
33      /** Frame in which are defined the coordinates. */
34      private final Frame frame;
35  
36      /** Position-velocity-acceleration vector. */
37      private final TimeStampedPVCoordinates timeStampedPVCoordinates;
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          this.timeStampedPVCoordinates = new TimeStampedPVCoordinates(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          this(frame, new TimeStampedPVCoordinates(date, pva));
71      }
72  
73      /** Build from frame and TimeStampedPVCoordinates.
74       * @param frame the frame in which the coordinates are defined
75       * @param pva TimeStampedPVCoordinates
76       */
77      public AbsolutePVCoordinates(final Frame frame, final TimeStampedPVCoordinates pva) {
78          this.timeStampedPVCoordinates = pva;
79          this.frame = frame;
80      }
81  
82      /** Multiplicative constructor
83       * <p>Build a AbsolutePVCoordinates from another one and a scale factor.</p>
84       * <p>The TimeStampedPVCoordinates built will be a * AbsPva</p>
85       * @param date date of the built coordinates
86       * @param a scale factor
87       * @param absPva base (unscaled) AbsolutePVCoordinates
88       */
89      public AbsolutePVCoordinates(final AbsoluteDate date,
90                                   final double a, final AbsolutePVCoordinates absPva) {
91          this(absPva.getFrame(), new TimeStampedPVCoordinates(date, a, absPva.getPVCoordinates()));
92      }
93  
94      /** Subtractive constructor
95       * <p>Build a relative AbsolutePVCoordinates from a start and an end position.</p>
96       * <p>The AbsolutePVCoordinates built will be end - start.</p>
97       * <p>In case start and end use two different pseudo-inertial frames,
98       * the new AbsolutePVCoordinates arbitrarily be defined in the start frame. </p>
99       * @param date date of the built coordinates
100      * @param start Starting AbsolutePVCoordinates
101      * @param end ending AbsolutePVCoordinates
102      */
103     public AbsolutePVCoordinates(final AbsoluteDate date,
104                                  final AbsolutePVCoordinates start, final AbsolutePVCoordinates end) {
105         this(start.getFrame(), new TimeStampedPVCoordinates(date, start.getPVCoordinates(), end.getPVCoordinates()));
106         ensureIdenticalFrames(start, end);
107     }
108 
109     /** Linear constructor
110      * <p>Build a AbsolutePVCoordinates from two other ones and corresponding scale factors.</p>
111      * <p>The AbsolutePVCoordinates built will be a1 * u1 + a2 * u2</p>
112      * <p>In case the AbsolutePVCoordinates use different pseudo-inertial frames,
113      * the new AbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
114      * @param date date of the built coordinates
115      * @param a1 first scale factor
116      * @param absPv1 first base (unscaled) AbsolutePVCoordinates
117      * @param a2 second scale factor
118      * @param absPv2 second base (unscaled) AbsolutePVCoordinates
119      */
120     public AbsolutePVCoordinates(final AbsoluteDate date,
121                                  final double a1, final AbsolutePVCoordinates absPv1,
122                                  final double a2, final AbsolutePVCoordinates absPv2) {
123         this(absPv1.getFrame(), new TimeStampedPVCoordinates(date, a1, absPv1.getPVCoordinates(), a2, absPv2.getPVCoordinates()));
124         ensureIdenticalFrames(absPv1, absPv2);
125     }
126 
127     /** Linear constructor
128      * <p>Build a AbsolutePVCoordinates from three other ones and corresponding scale factors.</p>
129      * <p>The AbsolutePVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
130      * <p>In case the AbsolutePVCoordinates use different pseudo-inertial frames,
131      * the new AbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
132      * @param date date of the built coordinates
133      * @param a1 first scale factor
134      * @param absPv1 first base (unscaled) AbsolutePVCoordinates
135      * @param a2 second scale factor
136      * @param absPv2 second base (unscaled) AbsolutePVCoordinates
137      * @param a3 third scale factor
138      * @param absPv3 third base (unscaled) AbsolutePVCoordinates
139      */
140     public AbsolutePVCoordinates(final AbsoluteDate date,
141                                  final double a1, final AbsolutePVCoordinates absPv1,
142                                  final double a2, final AbsolutePVCoordinates absPv2,
143                                  final double a3, final AbsolutePVCoordinates absPv3) {
144         this(absPv1.getFrame(), new TimeStampedPVCoordinates(date, a1, absPv1.getPVCoordinates(), a2,
145                 absPv2.getPVCoordinates(), a3, absPv3.getPVCoordinates()));
146         ensureIdenticalFrames(absPv1, absPv2);
147         ensureIdenticalFrames(absPv1, absPv3);
148     }
149 
150     /** Linear constructor
151      * <p>Build a AbsolutePVCoordinates from four other ones and corresponding scale factors.</p>
152      * <p>The AbsolutePVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
153      * <p>In case the AbsolutePVCoordinates use different pseudo-inertial frames,
154      * the new AbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
155      * @param date date of the built coordinates
156      * @param a1 first scale factor
157      * @param absPv1 first base (unscaled) AbsolutePVCoordinates
158      * @param a2 second scale factor
159      * @param absPv2 second base (unscaled) AbsolutePVCoordinates
160      * @param a3 third scale factor
161      * @param absPv3 third base (unscaled) AbsolutePVCoordinates
162      * @param a4 fourth scale factor
163      * @param absPv4 fourth base (unscaled) AbsolutePVCoordinates
164      */
165     public AbsolutePVCoordinates(final AbsoluteDate date,
166                                  final double a1, final AbsolutePVCoordinates absPv1,
167                                  final double a2, final AbsolutePVCoordinates absPv2,
168                                  final double a3, final AbsolutePVCoordinates absPv3,
169                                  final double a4, final AbsolutePVCoordinates absPv4) {
170         this(absPv1.getFrame(), new TimeStampedPVCoordinates(date, a1, absPv1.getPVCoordinates(), a2,
171                 absPv2.getPVCoordinates(), a3, absPv3.getPVCoordinates(), a4, absPv4.getPVCoordinates()));
172         ensureIdenticalFrames(absPv1, absPv2);
173         ensureIdenticalFrames(absPv1, absPv3);
174         ensureIdenticalFrames(absPv1, absPv4);
175     }
176 
177     /** Builds a AbsolutePVCoordinates triplet from  a {@link FieldVector3D}&lt;{@link Derivative}&gt;.
178      * <p>
179      * The vector components must have time as their only derivation parameter and
180      * have consistent derivation orders.
181      * </p>
182      * @param frame the frame in which the parameters are defined
183      * @param date date of the built coordinates
184      * @param p vector with time-derivatives embedded within the coordinates
185      * @param <U> type of the derivative
186      */
187     public <U extends Derivative<U>> AbsolutePVCoordinates(final Frame frame, final AbsoluteDate date,
188                                                            final FieldVector3D<U> p) {
189         this(frame, new TimeStampedPVCoordinates(date, p));
190     }
191 
192     /** Ensure that the frames from two AbsolutePVCoordinates are identical.
193      * @param absPv1 first AbsolutePVCoordinates
194      * @param absPv2 first AbsolutePVCoordinates
195      * @throws OrekitIllegalArgumentException if frames are different
196      */
197     private static void ensureIdenticalFrames(final AbsolutePVCoordinates absPv1, final AbsolutePVCoordinates absPv2)
198         throws OrekitIllegalArgumentException {
199         if (!absPv1.frame.equals(absPv2.frame)) {
200             throw new OrekitIllegalArgumentException(OrekitMessages.INCOMPATIBLE_FRAMES,
201                                                      absPv1.frame.getName(), absPv2.frame.getName());
202         }
203     }
204 
205     /** Get a time-shifted state.
206      * <p>
207      * The state can be slightly shifted to close dates. This shift is based on
208      * a simple Taylor expansion. It is <em>not</em> intended as a replacement for
209      * proper orbit propagation (it is not even Keplerian!) but should be sufficient
210      * for either small time shifts or coarse accuracy.
211      * </p>
212      * @param dt time shift in seconds
213      * @return a new state, shifted with respect to the instance (which is immutable)
214      */
215     public AbsolutePVCoordinates shiftedBy(final double dt) {
216         final TimeStampedPVCoordinates spv = timeStampedPVCoordinates.shiftedBy(dt);
217         return new AbsolutePVCoordinates(frame, spv);
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      * @since 13.0
230      */
231     @Override
232     public AbsolutePVCoordinates shiftedBy(final TimeOffset dt) {
233         final TimeStampedPVCoordinates spv = timeStampedPVCoordinates.shiftedBy(dt);
234         return new AbsolutePVCoordinates(frame, spv);
235     }
236 
237     /** Create a local provider using simply Taylor expansion through {@link #shiftedBy(double)}.
238      * <p>
239      * The time evolution is based on a simple Taylor expansion. It is <em>not</em> intended as a
240      * replacement for proper orbit propagation (it is not even Keplerian!) but should be sufficient
241      * for either small time shifts or coarse accuracy.
242      * </p>
243      * @return provider based on Taylor expansion, for small time shifts around instance date
244      */
245     public PVCoordinatesProvider toTaylorProvider() {
246         return this;
247     }
248 
249     /** Get the frame in which the coordinates are defined.
250      * @return frame in which the coordinates are defined
251      */
252     public Frame getFrame() {
253         return frame;
254     }
255 
256     /** {@inheritDoc} */
257     @Override
258     public AbsoluteDate getDate() {
259         return getPVCoordinates().getDate();
260     }
261 
262     /** Get the TimeStampedPVCoordinates.
263      * @return TimeStampedPVCoordinates
264      */
265     public TimeStampedPVCoordinates getPVCoordinates() {
266         return timeStampedPVCoordinates;
267     }
268 
269     /**
270      * Getter for the acceleration vector.
271      * @return acceleration
272      */
273     public Vector3D getAcceleration() {
274         return timeStampedPVCoordinates.getAcceleration();
275     }
276 
277     /** {@inheritDoc} */
278     @Override
279     public Vector3D getPosition(final AbsoluteDate otherDate, final Frame outputFrame) {
280         final double duration = otherDate.durationFrom(getDate());
281         final Vector3D position = getPosition().add((getVelocity().add(getAcceleration().scalarMultiply(duration / 2))).scalarMultiply(duration));
282 
283         if (outputFrame == frame) {
284             return position;
285         }
286         return frame.getStaticTransformTo(outputFrame, otherDate).transformPosition(position);
287     }
288 
289     /** {@inheritDoc} */
290     @Override
291     @DefaultDataContext
292     public String toString() {
293         return timeStampedPVCoordinates.toString();
294     }
295 }
296 
297 
298