1   /* Copyright 2002-2018 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.NotSerializableException;
20  import java.io.Serializable;
21  import java.util.List;
22  import java.util.stream.Collectors;
23  
24  import org.hipparchus.RealFieldElement;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitInternalError;
27  import org.orekit.errors.OrekitMessages;
28  import org.orekit.frames.FieldTransform;
29  import org.orekit.frames.Frame;
30  import org.orekit.frames.LOFType;
31  import org.orekit.frames.Transform;
32  import org.orekit.time.AbsoluteDate;
33  import org.orekit.time.FieldAbsoluteDate;
34  import org.orekit.utils.AngularDerivativesFilter;
35  import org.orekit.utils.FieldPVCoordinates;
36  import org.orekit.utils.FieldPVCoordinatesProvider;
37  import org.orekit.utils.ImmutableTimeStampedCache;
38  import org.orekit.utils.PVCoordinates;
39  import org.orekit.utils.PVCoordinatesProvider;
40  import org.orekit.utils.TimeStampedAngularCoordinates;
41  import org.orekit.utils.TimeStampedFieldAngularCoordinates;
42  
43  /**
44   * This class handles an attitude provider interpolating from a predefined table
45   * containing offsets from a Local Orbital Frame.
46   * <p>Instances of this class are guaranteed to be immutable.</p>
47   * @see LofOffset
48   * @see TabulatedProvider
49   * @author Luc Maisonobe
50   * @since 7.1
51   */
52  public class TabulatedLofOffset implements AttitudeProvider {
53  
54  
55      /** Serializable UID. */
56      private static final long serialVersionUID = 20151211L;
57  
58      /** Inertial frame with respect to which orbit should be computed. */
59      private final Frame inertialFrame;
60  
61      /** Type of Local Orbital Frame. */
62      private LOFType type;
63  
64      /** Cached attitude table. */
65      private final transient ImmutableTimeStampedCache<TimeStampedAngularCoordinates> table;
66  
67      /** Filter for derivatives from the sample to use in interpolation. */
68      private final AngularDerivativesFilter filter;
69  
70      /** Creates new instance.
71       * @param inertialFrame inertial frame with respect to which orbit should be computed
72       * @param type type of Local Orbital Frame
73       * @param table tabulated attitudes
74       * @param n number of attitude to use for interpolation
75       * @param filter filter for derivatives from the sample to use in interpolation
76       * @exception OrekitException if inertialFrame is not a pseudo-inertial frame
77       */
78      public TabulatedLofOffset(final Frame inertialFrame, final LOFType type,
79                                final List<TimeStampedAngularCoordinates> table,
80                                final int n, final AngularDerivativesFilter filter)
81          throws OrekitException {
82          if (!inertialFrame.isPseudoInertial()) {
83              throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME,
84                                        inertialFrame.getName());
85          }
86          this.inertialFrame = inertialFrame;
87          this.type          = type;
88          this.table         = new ImmutableTimeStampedCache<TimeStampedAngularCoordinates>(n, table);
89          this.filter        = filter;
90      }
91  
92      /** Get an unmodifiable view of the tabulated attitudes.
93       * @return unmodifiable view of the tabulated attitudes
94       */
95      public List<TimeStampedAngularCoordinates> getTable() {
96          return table.getAll();
97      }
98  
99      /** {@inheritDoc} */
100     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
101                                 final AbsoluteDate date, final Frame frame)
102         throws OrekitException {
103 
104         // get attitudes sample on which interpolation will be performed
105         final List<TimeStampedAngularCoordinates> sample = table.getNeighbors(date).collect(Collectors.toList());
106 
107         // interpolate
108         final TimeStampedAngularCoordinates interpolated =
109                 TimeStampedAngularCoordinates.interpolate(date, filter, sample);
110 
111         // construction of the local orbital frame, using PV from inertial frame
112         final PVCoordinates pv = pvProv.getPVCoordinates(date, inertialFrame);
113         final Transform inertialToLof = type.transformFromInertial(date, pv);
114 
115         // take into account the specified start frame (which may not be an inertial one)
116         final Transform frameToInertial = frame.getTransformTo(inertialFrame, date);
117         final Transform frameToLof      = new Transform(date, frameToInertial, inertialToLof);
118 
119         // compose with interpolated rotation
120         return new Attitude(date, frame,
121                             interpolated.addOffset(frameToLof.getAngular()));
122     }
123 
124     /** {@inheritDoc} */
125     public <T extends RealFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
126                                                                         final FieldAbsoluteDate<T> date,
127                                                                         final Frame frame)
128         throws OrekitException {
129 
130         // get attitudes sample on which interpolation will be performed
131         final List<TimeStampedFieldAngularCoordinates<T>> sample =
132                         table.
133                         getNeighbors(date.toAbsoluteDate()).
134                         map(ac -> new TimeStampedFieldAngularCoordinates<>(date.getField(), ac)).
135                         collect(Collectors.toList());
136 
137         // interpolate
138         final TimeStampedFieldAngularCoordinates<T> interpolated =
139                 TimeStampedFieldAngularCoordinates.interpolate(date, filter, sample);
140 
141         // construction of the local orbital frame, using PV from inertial frame
142         final FieldPVCoordinates<T> pv = pvProv.getPVCoordinates(date, inertialFrame);
143         final FieldTransform<T> inertialToLof = type.transformFromInertial(date, pv);
144 
145         // take into account the specified start frame (which may not be an inertial one)
146         final FieldTransform<T> frameToInertial = frame.getTransformTo(inertialFrame, date);
147         final FieldTransform<T> frameToLof      = new FieldTransform<>(date, frameToInertial, inertialToLof);
148 
149         // compose with interpolated rotation
150         return new FieldAttitude<>(date, frame,
151                                    interpolated.addOffset(frameToLof.getAngular()));
152     }
153 
154     /** Replace the instance with a data transfer object for serialization.
155      * @return data transfer object that will be serialized
156      * @exception NotSerializableException if the state mapper cannot be serialized (typically for DSST propagator)
157      */
158     private Object writeReplace() throws NotSerializableException {
159         return new DataTransferObject(inertialFrame, type, table.getAll(), table.getNeighborsSize(), filter);
160     }
161 
162     /** Internal class used only for serialization. */
163     private static class DataTransferObject implements Serializable {
164 
165         /** Serializable UID. */
166         private static final long serialVersionUID = 20151211L;
167 
168         /** Inertial frame with respect to which orbit should be computed. */
169         private final Frame inertialFrame;
170 
171         /** Type of Local Orbital Frame. */
172         private LOFType type;
173 
174         /** Cached attitude table. */
175         private final List<TimeStampedAngularCoordinates> list;
176 
177         /** Number of attitude to use for interpolation. */
178         private final int n;
179 
180         /** Filter for derivatives from the sample to use in interpolation. */
181         private final AngularDerivativesFilter filter;
182 
183         /** Simple constructor.
184          * @param inertialFrame inertial frame with respect to which orbit should be computed
185          * @param type type of Local Orbital Frame
186          * @param list tabulated attitudes
187          * @param n number of attitude to use for interpolation
188          * @param filter filter for derivatives from the sample to use in interpolation
189          */
190         DataTransferObject(final Frame inertialFrame, final LOFType type,
191                            final List<TimeStampedAngularCoordinates> list,
192                            final int n, final AngularDerivativesFilter filter) {
193             this.inertialFrame = inertialFrame;
194             this.type          = type;
195             this.list          = list;
196             this.n             = n;
197             this.filter        = filter;
198         }
199 
200         /** Replace the deserialized data transfer object with a {@link TabulatedLofOffset}.
201          * @return replacement {@link TabulatedLofOffset}
202          */
203         private Object readResolve() {
204             try {
205                 return new TabulatedLofOffset(inertialFrame, type, list, n, filter);
206             } catch (OrekitException oe) {
207                 // this should never happen
208                 throw new OrekitInternalError(oe);
209             }
210         }
211 
212     }
213 
214 }