1   /* Copyright 2002-2015 CS Systèmes d'Information
2    * Licensed to CS Systèmes d'Information (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 java.io.Serializable;
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.List;
23  
24  import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
25  import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
26  import org.orekit.errors.OrekitException;
27  import org.orekit.frames.Frame;
28  import org.orekit.frames.Transform;
29  import org.orekit.time.AbsoluteDate;
30  import org.orekit.time.TimeInterpolable;
31  import org.orekit.time.TimeShiftable;
32  import org.orekit.time.TimeStamped;
33  import org.orekit.utils.AngularCoordinates;
34  import org.orekit.utils.AngularDerivativesFilter;
35  import org.orekit.utils.TimeStampedAngularCoordinates;
36  
37  
38  /** This class handles attitude definition at a given date.
39  
40   * <p>This class represents the rotation between a reference frame and
41   * the satellite frame, as well as the spin of the satellite (axis and
42   * rotation rate).</p>
43   * <p>
44   * The state can be slightly shifted to close dates. This shift is based on
45   * a linear extrapolation for attitude taking the spin rate into account.
46   * It is <em>not</em> intended as a replacement for proper attitude propagation
47   * but should be sufficient for either small time shifts or coarse accuracy.
48   * </p>
49   * <p>The instance <code>Attitude</code> is guaranteed to be immutable.</p>
50   * @see     org.orekit.orbits.Orbit
51   * @see AttitudeProvider
52   * @author V&eacute;ronique Pommier-Maurussane
53   */
54  
55  public class Attitude
56      implements TimeStamped, TimeShiftable<Attitude>, TimeInterpolable<Attitude>, Serializable {
57  
58      /** Serializable UID. */
59      private static final long serialVersionUID = 20140611L;
60  
61      /** Reference frame. */
62      private final Frame referenceFrame;
63  
64       /** Attitude and spin.  */
65      private final TimeStampedAngularCoordinates orientation;
66  
67      /** Creates a new instance.
68       * @param referenceFrame reference frame from which attitude is defined
69       * @param orientation complete orientation between reference frame and satellite frame,
70       * including rotation rate
71       */
72      public Attitude(final Frame referenceFrame, final TimeStampedAngularCoordinates orientation) {
73          this.referenceFrame = referenceFrame;
74          this.orientation    = orientation;
75      }
76  
77      /** Creates a new instance.
78       * @param date date at which attitude is defined
79       * @param referenceFrame reference frame from which attitude is defined
80       * @param orientation complete orientation between reference frame and satellite frame,
81       * including rotation rate
82       */
83      public Attitude(final AbsoluteDate date, final Frame referenceFrame,
84                      final AngularCoordinates orientation) {
85          this(referenceFrame,
86               new TimeStampedAngularCoordinates(date,
87                                                 orientation.getRotation(),
88                                                 orientation.getRotationRate(),
89                                                 orientation.getRotationAcceleration()));
90      }
91  
92      /** Creates a new instance.
93       * @param date date at which attitude is defined
94       * @param referenceFrame reference frame from which attitude is defined
95       * @param attitude rotation between reference frame and satellite frame
96       * @param spin satellite spin (axis and velocity, in <strong>satellite</strong> frame)
97       * @param acceleration satellite rotation acceleration (in <strong>satellite</strong> frame)
98       */
99      public Attitude(final AbsoluteDate date, final Frame referenceFrame,
100                     final Rotation attitude, final Vector3D spin, final Vector3D acceleration) {
101         this(referenceFrame, new TimeStampedAngularCoordinates(date, attitude, spin, acceleration));
102     }
103 
104     /** Get a time-shifted attitude.
105      * <p>
106      * The state can be slightly shifted to close dates. This shift is based on
107      * a linear extrapolation for attitude taking the spin rate into account.
108      * It is <em>not</em> intended as a replacement for proper attitude propagation
109      * but should be sufficient for either small time shifts or coarse accuracy.
110      * </p>
111      * @param dt time shift in seconds
112      * @return a new attitude, shifted with respect to the instance (which is immutable)
113      */
114     public Attitude shiftedBy(final double dt) {
115         return new Attitude(referenceFrame, orientation.shiftedBy(dt));
116     }
117 
118     /** Get a similar attitude with a specific reference frame.
119      * <p>
120      * If the instance reference frame is already the specified one, the instance
121      * itself is returned without any object creation. Otherwise, a new instance
122      * will be created with the specified reference frame. In this case, the
123      * required intermediate rotation and spin between the specified and the
124      * original reference frame will be inserted.
125      * </p>
126      * @param newReferenceFrame desired reference frame for attitude
127      * @return an attitude that has the same orientation and motion as the instance,
128      * but guaranteed to have the specified reference frame
129      * @exception OrekitException if conversion between reference frames fails
130      */
131     public Attitude withReferenceFrame(final Frame newReferenceFrame)
132         throws OrekitException {
133 
134         if (newReferenceFrame == referenceFrame) {
135             // simple case, the instance is already compliant
136             return this;
137         }
138 
139         // we have to take an intermediate rotation into account
140         final Transform t = newReferenceFrame.getTransformTo(referenceFrame, orientation.getDate());
141         return new Attitude(orientation.getDate(), newReferenceFrame,
142                             orientation.getRotation().applyTo(t.getRotation()),
143                             orientation.getRotationRate().add(orientation.getRotation().applyTo(t.getRotationRate())),
144                             orientation.getRotationAcceleration().add(orientation.getRotation().applyTo(t.getRotationAcceleration())));
145 
146     }
147 
148     /** Get the date of attitude parameters.
149      * @return date of the attitude parameters
150      */
151     public AbsoluteDate getDate() {
152         return orientation.getDate();
153     }
154 
155     /** Get the reference frame.
156      * @return referenceFrame reference frame from which attitude is defined.
157      */
158     public Frame getReferenceFrame() {
159         return referenceFrame;
160     }
161 
162     /** Get the complete orientation including spin.
163      * @return complete orientation including spin
164      * @see #getRotation()
165      * @see #getSpin()
166      */
167     public TimeStampedAngularCoordinates getOrientation() {
168         return orientation;
169     }
170 
171     /** Get the attitude rotation.
172      * @return attitude satellite rotation from reference frame.
173      * @see #getOrientation()
174      * @see #getSpin()
175      */
176     public Rotation getRotation() {
177         return orientation.getRotation();
178     }
179 
180     /** Get the satellite spin.
181      * <p>The spin vector is defined in <strong>satellite</strong> frame.</p>
182      * @return spin satellite spin (axis and velocity).
183      * @see #getOrientation()
184      * @see #getRotation()
185      */
186     public Vector3D getSpin() {
187         return orientation.getRotationRate();
188     }
189 
190     /** Get the satellite rotation acceleration.
191      * <p>The rotation acceleration. vector is defined in <strong>satellite</strong> frame.</p>
192      * @return rotation acceleration
193      * @see #getOrientation()
194      * @see #getRotation()
195      */
196     public Vector3D getRotationAcceleration() {
197         return orientation.getRotationAcceleration();
198     }
199 
200     /** {@inheritDoc}
201      * <p>
202      * The interpolated instance is created by polynomial Hermite interpolation
203      * on Rodrigues vector ensuring rotation rate remains the exact derivative of rotation.
204      * </p>
205      * <p>
206      * As this implementation of interpolation is polynomial, it should be used only
207      * with small samples (about 10-20 points) in order to avoid <a
208      * href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's phenomenon</a>
209      * and numerical problems (including NaN appearing).
210      * </p>
211      * @exception OrekitException if the number of point is too small for interpolating
212      */
213     public Attitude interpolate(final AbsoluteDate interpolationDate, final Collection<Attitude> sample)
214         throws OrekitException {
215         final List<TimeStampedAngularCoordinates> datedPV =
216                 new ArrayList<TimeStampedAngularCoordinates>(sample.size());
217         for (final Attitude attitude : sample) {
218             datedPV.add(attitude.orientation);
219         }
220         final TimeStampedAngularCoordinates interpolated =
221                 TimeStampedAngularCoordinates.interpolate(interpolationDate, AngularDerivativesFilter.USE_RR, datedPV);
222         return new Attitude(referenceFrame, interpolated);
223     }
224 
225 }