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