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.data.DataContext;
24  import org.orekit.frames.Frame;
25  import org.orekit.time.AbsoluteDate;
26  import org.orekit.time.TimeOffset;
27  import org.orekit.time.TimeScale;
28  import org.orekit.time.TimeStamped;
29  
30  /** {@link TimeStamped time-stamped} version of {@link PVCoordinates}.
31   * <p>Instances of this class are guaranteed to be immutable.</p>
32   * @author Luc Maisonobe
33   * @since 7.0
34   */
35  public class TimeStampedPVCoordinates extends PVCoordinates implements TimeStamped {
36  
37      /** The date. */
38      private final AbsoluteDate date;
39  
40      /** Builds a TimeStampedPVCoordinates pair.
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 TimeStampedPVCoordinates(final AbsoluteDate date,
47                                      final Vector3D position, final Vector3D velocity, final Vector3D acceleration) {
48          super(position, velocity, acceleration);
49          this.date = date;
50      }
51  
52      /**
53       * Build from position and velocity. Acceleration is set to zero.
54       *
55       * @param date coordinates date
56       * @param position the position vector (m)
57       * @param velocity the velocity vector (m/s)
58       */
59      public TimeStampedPVCoordinates(final AbsoluteDate date,
60                                      final Vector3D position,
61                                      final Vector3D velocity) {
62          this(date, position, velocity, Vector3D.ZERO);
63      }
64  
65      /**
66       * Build from position velocity acceleration coordinates.
67       *
68       * @param date coordinates date
69       * @param pv position velocity, and acceleration coordinates, in meters and seconds.
70       */
71      public TimeStampedPVCoordinates(final AbsoluteDate date, final PVCoordinates pv) {
72          this(date, pv.getPosition(), pv.getVelocity(), pv.getAcceleration());
73      }
74  
75      /** Multiplicative constructor
76       * <p>Build a TimeStampedPVCoordinates from another one and a scale factor.</p>
77       * <p>The TimeStampedPVCoordinates built will be a * pv</p>
78       * @param date date of the built coordinates
79       * @param a scale factor
80       * @param pv base (unscaled) PVCoordinates
81       */
82      public TimeStampedPVCoordinates(final AbsoluteDate date,
83                                      final double a, final PVCoordinates pv) {
84          super(new Vector3D(a, pv.getPosition()),
85                new Vector3D(a, pv.getVelocity()),
86                new Vector3D(a, pv.getAcceleration()));
87          this.date = date;
88      }
89  
90      /** Subtractive constructor
91       * <p>Build a relative TimeStampedPVCoordinates from a start and an end position.</p>
92       * <p>The TimeStampedPVCoordinates built will be end - start.</p>
93       * @param date date of the built coordinates
94       * @param start Starting PVCoordinates
95       * @param end ending PVCoordinates
96       */
97      public TimeStampedPVCoordinates(final AbsoluteDate date,
98                                      final PVCoordinates start, final PVCoordinates end) {
99          super(end.getPosition().subtract(start.getPosition()),
100               end.getVelocity().subtract(start.getVelocity()),
101               end.getAcceleration().subtract(start.getAcceleration()));
102         this.date = date;
103     }
104 
105     /** Linear constructor
106      * <p>Build a TimeStampedPVCoordinates from two other ones and corresponding scale factors.</p>
107      * <p>The TimeStampedPVCoordinates built will be a1 * u1 + a2 * u2</p>
108      * @param date date of the built coordinates
109      * @param a1 first scale factor
110      * @param pv1 first base (unscaled) PVCoordinates
111      * @param a2 second scale factor
112      * @param pv2 second base (unscaled) PVCoordinates
113      */
114     public TimeStampedPVCoordinates(final AbsoluteDate date,
115                                     final double a1, final PVCoordinates pv1,
116                                     final double a2, final PVCoordinates pv2) {
117         super(new Vector3D(a1, pv1.getPosition(),     a2, pv2.getPosition()),
118               new Vector3D(a1, pv1.getVelocity(),     a2, pv2.getVelocity()),
119               new Vector3D(a1, pv1.getAcceleration(), a2, pv2.getAcceleration()));
120         this.date = date;
121     }
122 
123     /** Linear constructor
124      * <p>Build a TimeStampedPVCoordinates from three other ones and corresponding scale factors.</p>
125      * <p>The TimeStampedPVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
126      * @param date date of the built coordinates
127      * @param a1 first scale factor
128      * @param pv1 first base (unscaled) PVCoordinates
129      * @param a2 second scale factor
130      * @param pv2 second base (unscaled) PVCoordinates
131      * @param a3 third scale factor
132      * @param pv3 third base (unscaled) PVCoordinates
133      */
134     public TimeStampedPVCoordinates(final AbsoluteDate date,
135                                     final double a1, final PVCoordinates pv1,
136                                     final double a2, final PVCoordinates pv2,
137                                     final double a3, final PVCoordinates pv3) {
138         super(new Vector3D(a1, pv1.getPosition(),     a2, pv2.getPosition(),     a3, pv3.getPosition()),
139               new Vector3D(a1, pv1.getVelocity(),     a2, pv2.getVelocity(),     a3, pv3.getVelocity()),
140               new Vector3D(a1, pv1.getAcceleration(), a2, pv2.getAcceleration(), a3, pv3.getAcceleration()));
141         this.date = date;
142     }
143 
144     /** Linear constructor
145      * <p>Build a TimeStampedPVCoordinates from four other ones and corresponding scale factors.</p>
146      * <p>The TimeStampedPVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
147      * @param date date of the built coordinates
148      * @param a1 first scale factor
149      * @param pv1 first base (unscaled) PVCoordinates
150      * @param a2 second scale factor
151      * @param pv2 second base (unscaled) PVCoordinates
152      * @param a3 third scale factor
153      * @param pv3 third base (unscaled) PVCoordinates
154      * @param a4 fourth scale factor
155      * @param pv4 fourth base (unscaled) PVCoordinates
156      */
157     public TimeStampedPVCoordinates(final AbsoluteDate date,
158                                     final double a1, final PVCoordinates pv1,
159                                     final double a2, final PVCoordinates pv2,
160                                     final double a3, final PVCoordinates pv3,
161                                     final double a4, final PVCoordinates pv4) {
162         super(new Vector3D(a1, pv1.getPosition(),     a2, pv2.getPosition(),     a3, pv3.getPosition(),     a4, pv4.getPosition()),
163               new Vector3D(a1, pv1.getVelocity(),     a2, pv2.getVelocity(),     a3, pv3.getVelocity(),     a4, pv4.getVelocity()),
164               new Vector3D(a1, pv1.getAcceleration(), a2, pv2.getAcceleration(), a3, pv3.getAcceleration(), a4, pv4.getAcceleration()));
165         this.date = date;
166     }
167 
168     /** Builds a TimeStampedPVCoordinates triplet from  a {@link FieldVector3D}&lt;{@link Derivative}&gt;.
169      * <p>
170      * The vector components must have time as their only derivation parameter and
171      * have consistent derivation orders.
172      * </p>
173      * @param date date of the built coordinates
174      * @param p vector with time-derivatives embedded within the coordinates
175      * @param <U> type of the derivative
176      */
177     public <U extends Derivative<U>> TimeStampedPVCoordinates(final AbsoluteDate date, final FieldVector3D<U> p) {
178         super(p);
179         this.date = date;
180     }
181 
182     /** {@inheritDoc} */
183     public AbsoluteDate getDate() {
184         return date;
185     }
186 
187     /** Get a time-shifted state.
188      * <p>
189      * The state can be slightly shifted to close dates. This shift is based on
190      * a simple Taylor expansion. It is <em>not</em> intended as a replacement for
191      * proper orbit propagation (it is not even Keplerian!) but should be sufficient
192      * for either small time shifts or coarse accuracy.
193      * </p>
194      * @param dt time shift in seconds
195      * @return a new state, shifted with respect to the instance (which is immutable)
196      */
197     @Override
198     public TimeStampedPVCoordinates shiftedBy(final double dt) {
199         final PVCoordinates spv = super.shiftedBy(dt);
200         return new TimeStampedPVCoordinates(date.shiftedBy(dt),
201                                             spv.getPosition(), spv.getVelocity(), spv.getAcceleration());
202     }
203 
204     /** Get a time-shifted state.
205      * <p>
206      * The state can be slightly shifted to close dates. This shift is based on
207      * a simple Taylor expansion. It is <em>not</em> intended as a replacement for
208      * proper orbit propagation (it is not even Keplerian!) but should be sufficient
209      * for either small time shifts or coarse accuracy.
210      * </p>
211      * @param dt time shift
212      * @return a new state, shifted with respect to the instance (which is immutable)
213      * @since 13.0
214      */
215     @Override
216     public TimeStampedPVCoordinates shiftedBy(final TimeOffset dt) {
217         final PVCoordinates spv = super.shiftedBy(dt);
218         return new TimeStampedPVCoordinates(date.shiftedBy(dt),
219                                             spv.getPosition(), spv.getVelocity(), spv.getAcceleration());
220     }
221 
222     /** Create a local provider using simply Taylor expansion through {@link #shiftedBy(double)}.
223      * <p>
224      * The time evolution is based on a simple Taylor expansion. It is <em>not</em> intended as a
225      * replacement for proper orbit propagation (it is not even Keplerian!) but should be sufficient
226      * for either small time shifts or coarse accuracy.
227      * </p>
228      * @param instanceFrame frame in which the instance is defined
229      * @return provider based on Taylor expansion, for small time shifts around instance date
230      */
231     public PVCoordinatesProvider toTaylorProvider(final Frame instanceFrame) {
232         return new ShiftingPVCoordinatesProvider(this, instanceFrame);
233     }
234 
235     /** Return a string representation of this date, position, velocity, and acceleration.
236      *
237      * <p>This method uses the {@link DataContext#getDefault() default data context}.
238      *
239      * @return string representation of this.
240      */
241     @Override
242     @DefaultDataContext
243     public String toString() {
244         return toString(DataContext.getDefault().getTimeScales().getUTC());
245     }
246 
247     /**
248      * Return a string representation of this date, position, velocity, and acceleration.
249      *
250      * @param utc time scale used to print the date.
251      * @return string representation of this.
252      */
253     public String toString(final TimeScale utc) {
254         final String comma = ", ";
255         return new StringBuilder().append('{').
256                                   append(date.toString(utc)).append(", P(").
257                                   append(getPosition().getX()).append(comma).
258                                   append(getPosition().getY()).append(comma).
259                                   append(getPosition().getZ()).append("), V(").
260                                   append(getVelocity().getX()).append(comma).
261                                   append(getVelocity().getY()).append(comma).
262                                   append(getVelocity().getZ()).append("), A(").
263                                   append(getAcceleration().getX()).append(comma).
264                                   append(getAcceleration().getY()).append(comma).
265                                   append(getAcceleration().getZ()).append(")}").toString();
266     }
267 
268 }