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.attitudes;
18  
19  import org.hipparchus.Field;
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
22  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
23  import org.hipparchus.geometry.euclidean.threed.Rotation;
24  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.orekit.frames.FieldTransform;
27  import org.orekit.frames.Frame;
28  import org.orekit.time.FieldAbsoluteDate;
29  import org.orekit.time.FieldTimeShiftable;
30  import org.orekit.time.FieldTimeStamped;
31  import org.orekit.utils.FieldAngularCoordinates;
32  import org.orekit.utils.TimeStampedFieldAngularCoordinates;
33  
34  
35  /** This class handles attitude definition at a given date.
36  
37   * <p>This class represents the rotation between a reference frame and
38   * the satellite frame, as well as the spin of the satellite (axis and
39   * rotation rate).</p>
40   * <p>
41   * The state can be slightly shifted to close dates. This shift is based on
42   * a linear extrapolation for attitude taking the spin rate into account.
43   * It is <em>not</em> intended as a replacement for proper attitude propagation
44   * but should be sufficient for either small time shifts or coarse accuracy.
45   * </p>
46   * <p>The instance <code>Attitude</code> is guaranteed to be immutable.</p>
47   * @see     org.orekit.orbits.Orbit
48   * @see AttitudeProvider
49   * @author V&eacute;ronique Pommier-Maurussane
50   * @param <T> type of the field elements
51   */
52  
53  public class FieldAttitude<T extends CalculusFieldElement<T>>
54      implements FieldTimeStamped<T>, FieldTimeShiftable<FieldAttitude<T>, T> {
55  
56  
57      /** Reference frame. */
58      private final Frame referenceFrame;
59  
60       /** Attitude and spin.  */
61      private final TimeStampedFieldAngularCoordinates<T> orientation;
62  
63      /** Creates a new instance.
64       * @param referenceFrame reference frame from which attitude is defined
65       * @param orientation complete orientation between reference frame and satellite frame,
66       * including rotation rate
67       */
68      public FieldAttitude(final Frame referenceFrame, final TimeStampedFieldAngularCoordinates<T> orientation) {
69          this.referenceFrame = referenceFrame;
70          this.orientation    = orientation;
71      }
72  
73      /** Creates a new instance.
74       * @param date date at which attitude is defined
75       * @param referenceFrame reference frame from which attitude is defined
76       * @param orientation complete orientation between reference frame and satellite frame,
77       * including rotation rate
78       */
79      public FieldAttitude(final FieldAbsoluteDate<T> date, final Frame referenceFrame,
80                           final FieldAngularCoordinates<T> orientation) {
81          this(referenceFrame,
82               new TimeStampedFieldAngularCoordinates<>(date,
83                                                        orientation.getRotation(),
84                                                        orientation.getRotationRate(),
85                                                        orientation.getRotationAcceleration()));
86      }
87  
88      /** Creates a new instance.
89       * @param date date at which attitude is defined
90       * @param referenceFrame reference frame from which attitude is defined
91       * @param attitude rotation between reference frame and satellite frame
92       * @param spin satellite spin (axis and velocity, in <strong>satellite</strong> frame)
93       * @param acceleration satellite rotation acceleration (in <strong>satellite</strong> frame)
94       */
95      public FieldAttitude(final FieldAbsoluteDate<T> date, final Frame referenceFrame,
96                           final FieldRotation<T> attitude, final FieldVector3D<T> spin, final FieldVector3D<T> acceleration) {
97          this(referenceFrame, new TimeStampedFieldAngularCoordinates<>(date, attitude, spin, acceleration));
98      }
99  
100     /** Creates a new instance.
101      * @param date date at which attitude is defined
102      * @param referenceFrame reference frame from which attitude is defined
103      * @param attitude rotation between reference frame and satellite frame
104      * @param spin satellite spin (axis and velocity, in <strong>satellite</strong> frame)
105      * @param acceleration satellite rotation acceleration (in <strong>satellite</strong> frame)
106      * @param field field used by default
107      */
108     public FieldAttitude(final FieldAbsoluteDate<T> date, final Frame referenceFrame,
109                          final Rotation attitude, final Vector3D spin, final Vector3D acceleration, final Field<T> field) {
110         this(referenceFrame, new TimeStampedFieldAngularCoordinates<>(date,
111                                                                       new FieldRotation<>(field, attitude),
112                                                                       new FieldVector3D<>(field, spin),
113                                                                       new FieldVector3D<>(field, acceleration)));
114     }
115 
116     /** Builds an instance for a regular {@link Attitude}.
117      * @param field fields to which the elements belong
118      * @param attitude attitude to convert
119      */
120     public FieldAttitude(final Field<T> field, final Attitude attitude) {
121         this(attitude.getReferenceFrame(), new TimeStampedFieldAngularCoordinates<>(field, attitude.getOrientation()));
122     }
123 
124     /** Get a time-shifted attitude.
125      * <p>
126      * The state can be slightly shifted to close dates. This shift is based on
127      * a linear extrapolation for attitude taking the spin rate into account.
128      * It is <em>not</em> intended as a replacement for proper attitude propagation
129      * but should be sufficient for either small time shifts or coarse accuracy.
130      * </p>
131      * @param dt time shift in seconds
132      * @return a new attitude, shifted with respect to the instance (which is immutable)
133      */
134     public FieldAttitude<T> shiftedBy(final double dt) {
135         return new FieldAttitude<>(referenceFrame, orientation.shiftedBy(dt));
136     }
137 
138     /** Get a time-shifted attitude.
139      * <p>
140      * The state can be slightly shifted to close dates. This shift is based on
141      * a linear extrapolation for attitude taking the spin rate into account.
142      * It is <em>not</em> intended as a replacement for proper attitude propagation
143      * but should be sufficient for either small time shifts or coarse accuracy.
144      * </p>
145      * @param dt time shift in seconds
146      * @return a new attitude, shifted with respect to the instance (which is immutable)
147      */
148     public FieldAttitude<T> shiftedBy(final T dt) {
149         return new FieldAttitude<>(referenceFrame, orientation.shiftedBy(dt));
150     }
151 
152     /** Get a similar attitude with a specific reference frame.
153      * <p>
154      * If the instance reference frame is already the specified one, the instance
155      * itself is returned without any object creation. Otherwise, a new instance
156      * will be created with the specified reference frame. In this case, the
157      * required intermediate rotation and spin between the specified and the
158      * original reference frame will be inserted.
159      * </p>
160      * @param newReferenceFrame desired reference frame for attitude
161      * @return an attitude that has the same orientation and motion as the instance,
162      * but guaranteed to have the specified reference frame
163      */
164     public FieldAttitude<T> withReferenceFrame(final Frame newReferenceFrame) {
165 
166         if (newReferenceFrame == referenceFrame) {
167             // simple case, the instance is already compliant
168             return this;
169         }
170 
171         // we have to take an intermediate rotation into account
172         final FieldTransform<T> t = newReferenceFrame.getTransformTo(referenceFrame, orientation.getDate());
173         return new FieldAttitude<>(orientation.getDate(), newReferenceFrame,
174                                    orientation.getRotation().compose(t.getRotation(), RotationConvention.VECTOR_OPERATOR),
175                                    orientation.getRotationRate().add(orientation.getRotation().applyTo(t.getRotationRate())),
176                                    orientation.getRotationAcceleration().add(orientation.getRotation().applyTo(t.getRotationAcceleration())));
177 
178     }
179 
180     /** Get the date of attitude parameters.
181      * @return date of the attitude parameters
182      */
183     public FieldAbsoluteDate<T> getDate() {
184         return orientation.getDate();
185     }
186 
187     /** Get the reference frame.
188      * @return referenceFrame reference frame from which attitude is defined.
189      */
190     public Frame getReferenceFrame() {
191         return referenceFrame;
192     }
193 
194     /** Get the complete orientation including spin.
195      * @return complete orientation including spin
196      * @see #getRotation()
197      * @see #getSpin()
198      */
199     public TimeStampedFieldAngularCoordinates<T> getOrientation() {
200         return orientation;
201     }
202 
203     /** Get the attitude rotation.
204      * @return attitude satellite rotation from reference frame.
205      * @see #getOrientation()
206      * @see #getSpin()
207      */
208     public FieldRotation<T> getRotation() {
209         return orientation.getRotation();
210     }
211 
212     /** Get the satellite spin.
213      * <p>The spin vector is defined in <strong>satellite</strong> frame.</p>
214      * @return spin satellite spin (axis and velocity).
215      * @see #getOrientation()
216      * @see #getRotation()
217      */
218     public FieldVector3D<T> getSpin() {
219         return orientation.getRotationRate();
220     }
221 
222     /** Get the satellite rotation acceleration.
223      * <p>The rotation acceleration. vector is defined in <strong>satellite</strong> frame.</p>
224      * @return rotation acceleration
225      * @see #getOrientation()
226      * @see #getRotation()
227      */
228     public FieldVector3D<T> getRotationAcceleration() {
229         return orientation.getRotationAcceleration();
230     }
231 
232     /**
233      * Converts to an Attitude instance.
234      * @return Attitude with same properties
235      */
236     public Attitude toAttitude() {
237         return new Attitude(orientation.getDate().toAbsoluteDate(), referenceFrame, orientation.toAngularCoordinates());
238     }
239 
240 }