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