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