1   /* Copyright 2002-2021 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.files.general;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.concurrent.ConcurrentHashMap;
24  
25  import org.orekit.attitudes.BoundedAttitudeProvider;
26  import org.orekit.attitudes.FixedFrameBuilder;
27  import org.orekit.attitudes.TabulatedProvider;
28  import org.orekit.errors.OrekitIllegalArgumentException;
29  import org.orekit.errors.OrekitMessages;
30  import org.orekit.frames.Frame;
31  import org.orekit.propagation.SpacecraftState;
32  import org.orekit.time.AbsoluteDate;
33  import org.orekit.utils.AngularDerivativesFilter;
34  import org.orekit.utils.TimeStampedAngularCoordinates;
35  
36  /**
37   * A class for encapsulating Orekit propagators within an {@link AttitudeEphemerisFile}
38   * complaint object that makes for easy serialization to external ephemeris
39   * formats like AEM.
40   *
41   * @author Raphaël Fermé
42   * @since 10.3
43   *
44   */
45  public class OrekitAttitudeEphemerisFile
46      implements AttitudeEphemerisFile<TimeStampedAngularCoordinates,
47                                       OrekitAttitudeEphemerisFile.OrekitAttitudeEphemerisSegment> {
48  
49      /** Hashmap of satellite ephemeris. **/
50      private final Map<String, OrekitSatelliteAttitudeEphemeris> satellites;
51  
52      /**
53       * Standard default constructor.
54       */
55      public OrekitAttitudeEphemerisFile() {
56          this.satellites = new ConcurrentHashMap<>();
57      }
58  
59      /** {@inheritDoc} */
60      @Override
61      public Map<String, OrekitSatelliteAttitudeEphemeris> getSatellites() {
62          return Collections.unmodifiableMap(satellites);
63      }
64  
65      /**
66       * Adds a new satellite to this object.
67       *
68       * @param id
69       *            ID to use for this satellite
70       * @return the new satellite object
71       */
72      public OrekitSatelliteAttitudeEphemeris addSatellite(final String id) {
73          final OrekitSatelliteAttitudeEphemeris newSat = new OrekitSatelliteAttitudeEphemeris(id);
74          this.satellites.put(id, newSat);
75          return newSat;
76      }
77  
78      /**
79       * Inner class of {@link OrekitAttitudeEphemerisFile} that defines the
80       * {@link OrekitSatelliteAttitudeEphemeris} corresponding object for this ephemeris type.
81       *
82       */
83      public static class OrekitSatelliteAttitudeEphemeris
84          implements SatelliteAttitudeEphemeris<TimeStampedAngularCoordinates,
85                                                OrekitAttitudeEphemerisFile.OrekitAttitudeEphemerisSegment> {
86  
87          /** Default interpolation sample size if it is not specified. **/
88          public static final String DEFAULT_INTERPOLATION_METHOD = "LINEAR";
89  
90          /** Default interpolation sample size if it is not specified. **/
91          public static final int DEFAULT_INTERPOLATION_SIZE = 2;
92  
93          /** ID of the space object encapsulated here. **/
94          private final String id;
95  
96          /** Earliest date of this file. **/
97          private AbsoluteDate startDate;
98  
99          /** Latest date of this file. **/
100         private AbsoluteDate stopDate;
101 
102         /** List of segments in the file. **/
103         private final List<OrekitAttitudeEphemerisSegment> segments;
104 
105         /**
106          * Standard constructor for building the satellite Ephemeris object.
107          *
108          * @param id
109          *            the ID of the space object for this data
110          */
111         public OrekitSatelliteAttitudeEphemeris(final String id) {
112             this.id = id;
113             this.segments = new ArrayList<>();
114         }
115 
116         /** {@inheritDoc} */
117         @Override
118         public String getId() {
119             return id;
120         }
121 
122         /** {@inheritDoc} */
123         @Override
124         public List<OrekitAttitudeEphemerisSegment> getSegments() {
125             return Collections.unmodifiableList(this.segments);
126         }
127 
128         /** {@inheritDoc} */
129         @Override
130         public AbsoluteDate getStart() {
131             return this.startDate;
132         }
133 
134         /** {@inheritDoc} */
135         @Override
136         public AbsoluteDate getStop() {
137             return this.stopDate;
138         }
139 
140         /**
141          * Injects pre-computed satellite states into this attitude ephemeris file
142          * object, returning the generated {@link OrekitAttitudeEphemerisSegment} that
143          * has been stored internally.
144          *
145          * @param states
146          *          a list of {@link SpacecraftState} that will comprise this
147          *          new unit
148          * @param interpolationMethod
149          *          the interpolation method that should be used when processed
150          *          by another system
151          * @param interpolationSamples
152          *          the number of interpolation samples that should be used
153          *          when processed by another system
154          * @param availableDerivatives derivatives to use for interpolation
155          * @return the generated {@link OrekitAttitudeEphemerisSegment}
156          */
157         public OrekitAttitudeEphemerisSegment addNewSegment(final List<SpacecraftState> states,
158                                                             final String interpolationMethod,
159                                                             final int interpolationSamples,
160                                                             final AngularDerivativesFilter availableDerivatives) {
161             final int minimumSampleSize = 2;
162             if (states == null || states.size() == 0) {
163                 throw new OrekitIllegalArgumentException(OrekitMessages.NULL_ARGUMENT, "states");
164             }
165 
166             if (interpolationSamples < minimumSampleSize) {
167                 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA_FOR_INTERPOLATION,
168                         interpolationSamples);
169             }
170 
171             final AbsoluteDate start = states.get(0).getDate();
172             final AbsoluteDate stop = states.get(states.size() - 1).getDate();
173 
174             if (this.startDate == null || start.compareTo(this.startDate) < 0) {
175                 this.startDate = start;
176             }
177 
178             if (this.stopDate == null || stop.compareTo(this.stopDate) > 0) {
179                 this.stopDate = stop;
180             }
181 
182             final List<TimeStampedAngularCoordinates> attitudeDataLines = new ArrayList<>();
183             for (SpacecraftState state : states) {
184                 attitudeDataLines.add(state.getAttitude().getOrientation());
185             }
186 
187             final OrekitAttitudeEphemerisSegment newSeg =
188                             new OrekitAttitudeEphemerisSegment(attitudeDataLines, interpolationMethod, interpolationSamples,
189                                                                states.get(0).getFrame(), availableDerivatives);
190             this.segments.add(newSeg);
191             return newSeg;
192         }
193     }
194 
195     public static class OrekitAttitudeEphemerisSegment
196         implements AttitudeEphemerisFile.AttitudeEphemerisSegment<TimeStampedAngularCoordinates> {
197 
198         /** List of attitude data lines. */
199         private List<TimeStampedAngularCoordinates> attitudeDataLines;
200 
201         /** The interpolation method to be used. */
202         private String interpolationMethod;
203 
204         /** The number of interpolation samples. */
205         private int interpolationSamples;
206 
207         /** Enumerate for selecting which derivatives to use in {@link #attitudeDataLines} interpolation. */
208         private AngularDerivativesFilter availableDerivatives;
209 
210         /** Reference frame from which attitude is defined. */
211         private Frame referenceFrame;
212 
213         /**
214          * Constructor for OrekitAttitudeEphemerisSegment.
215          *
216          * @param attitudeDataLines
217          *          attitude data lines for this segment.
218          * @param interpolationMethod
219          *          the interpolation method to use.
220          * @param interpolationSamples
221          *          the number of samples to use during interpolation.
222          * @param referenceFrame
223          *          reference frame from which the attitude is defined
224          * @param availableDerivatives derivatives to use for interpolation
225          */
226         public OrekitAttitudeEphemerisSegment(final List<TimeStampedAngularCoordinates> attitudeDataLines,
227                                               final String interpolationMethod,
228                                               final int interpolationSamples,
229                                               final Frame referenceFrame,
230                                               final AngularDerivativesFilter availableDerivatives) {
231             this.attitudeDataLines    = attitudeDataLines;
232             this.interpolationMethod  = interpolationMethod;
233             this.interpolationSamples = interpolationSamples;
234             this.referenceFrame       = referenceFrame;
235             this.availableDerivatives = availableDerivatives;
236         }
237 
238         /** {@inheritDoc} */
239         @Override
240         public List<TimeStampedAngularCoordinates> getAngularCoordinates() {
241             return Collections.unmodifiableList(attitudeDataLines);
242         }
243 
244         /** {@inheritDoc} */
245         @Override
246         public Frame getReferenceFrame() {
247             return referenceFrame;
248         }
249 
250         /** {@inheritDoc} */
251         @Override
252         public AbsoluteDate getStart() {
253             return attitudeDataLines.get(0).getDate();
254         }
255 
256         /** {@inheritDoc} */
257         @Override
258         public AbsoluteDate getStop() {
259             return attitudeDataLines.get(attitudeDataLines.size() - 1).getDate();
260         }
261 
262         /** {@inheritDoc} */
263         @Override
264         public String getInterpolationMethod() {
265             return interpolationMethod;
266         }
267 
268         /** {@inheritDoc} */
269         @Override
270         public int getInterpolationSamples() {
271             return interpolationSamples;
272         }
273 
274         /** {@inheritDoc} */
275         @Override
276         public AngularDerivativesFilter getAvailableDerivatives() {
277             return availableDerivatives;
278         }
279 
280         /** {@inheritDoc} */
281         @Override
282         public BoundedAttitudeProvider getAttitudeProvider() {
283             return new TabulatedProvider(getAngularCoordinates(),
284                                          getInterpolationSamples(), getAvailableDerivatives(),
285                                          getStart(), getStop(),
286                                          new FixedFrameBuilder(getReferenceFrame()));
287         }
288 
289     }
290 
291 }