1   /* Copyright 2002-2024 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 java.util.Collection;
20  import java.util.Map.Entry;
21  import java.util.NavigableMap;
22  import java.util.TreeMap;
23  
24  import org.hipparchus.CalculusFieldElement;
25  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
26  import org.hipparchus.geometry.euclidean.threed.Rotation;
27  import org.orekit.errors.OrekitException;
28  import org.orekit.errors.OrekitMessages;
29  import org.orekit.frames.Frame;
30  import org.orekit.time.AbsoluteDate;
31  import org.orekit.time.FieldAbsoluteDate;
32  import org.orekit.utils.FieldPVCoordinatesProvider;
33  import org.orekit.utils.PVCoordinatesProvider;
34  
35  /**
36   * A {@link BoundedAttitudeProvider} that covers a larger time span from several constituent
37   * attitude providers that cover shorter time spans.
38   *
39   * @author Bryan Cazabonne
40   * @since 10.3
41   */
42  public class AggregateBoundedAttitudeProvider implements BoundedAttitudeProvider {
43  
44      /** Constituent attitude provider. */
45      private final NavigableMap<AbsoluteDate, BoundedAttitudeProvider> providers;
46  
47      /**
48       * Constructor.
49       * @param providers attitude providers that provide the backing data for this instance.
50       *                  There must be at least one attitude provider in the collection.
51       *                  If there are gaps between the {@link BoundedAttitudeProvider#getMaxDate()}
52       *                  of one attitude provider and the {@link BoundedAttitudeProvider#getMinDate()}
53       *                  of the next attitude provider an exception may be thrown by any method of
54       *                  this class at any time. If there are overlaps between the the {@link
55       *                  BoundedAttitudeProvider#getMaxDate()} of one attitude provider and the {@link
56       *                  BoundedAttitudeProvider#getMinDate()} of the next attitude provider then the
57       *                  attitude provider with the latest {@link BoundedAttitudeProvider#getMinDate()}
58       *                  is used.
59       */
60      public AggregateBoundedAttitudeProvider(final Collection<? extends BoundedAttitudeProvider> providers) {
61  
62          // Check if the collection is empty
63          if (providers.isEmpty()) {
64              throw new OrekitException(OrekitMessages.NOT_ENOUGH_ATTITUDE_PROVIDERS);
65          }
66  
67          // Initialize map
68          this.providers = new TreeMap<>();
69  
70          // Loop on providers
71          for (final BoundedAttitudeProvider provider : providers) {
72              // Fill collection
73              this.providers.put(provider.getMinDate(), provider);
74          }
75  
76      }
77  
78      /** {@inheritDoc} */
79      @Override
80      public Attitude getAttitude(final PVCoordinatesProvider pvProv, final AbsoluteDate date,
81                                  final Frame frame) {
82  
83          // Get the attitude provider for the given date
84          final BoundedAttitudeProvider provider = getAttitudeProvider(date);
85  
86          // Build attitude
87          return provider.getAttitude(pvProv, date, frame);
88  
89      }
90  
91      /** {@inheritDoc} */
92      @Override
93      public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
94                                                                          final FieldAbsoluteDate<T> date, final Frame frame) {
95  
96          // Get the attitude provider for the given date
97          final BoundedAttitudeProvider provider = getAttitudeProvider(date.toAbsoluteDate());
98  
99          // Build attitude
100         return provider.getAttitude(pvProv, date, frame);
101 
102     }
103 
104     /** {@inheritDoc} */
105     @Override
106     public Rotation getAttitudeRotation(final PVCoordinatesProvider pvProv, final AbsoluteDate date, final Frame frame) {
107         return getAttitudeProvider(date).getAttitudeRotation(pvProv, date, frame);
108     }
109 
110     /** {@inheritDoc} */
111     @Override
112     public <T extends CalculusFieldElement<T>> FieldRotation<T> getAttitudeRotation(final FieldPVCoordinatesProvider<T> pvProv,
113                                                                                     final FieldAbsoluteDate<T> date,
114                                                                                     final Frame frame) {
115         return getAttitudeProvider(date.toAbsoluteDate()).getAttitudeRotation(pvProv, date, frame);
116     }
117 
118     @Override
119     public AbsoluteDate getMinDate() {
120         return providers.firstEntry().getValue().getMinDate();
121     }
122 
123     /** {@inheritDoc} */
124     @Override
125     public AbsoluteDate getMaxDate() {
126         return providers.lastEntry().getValue().getMaxDate();
127     }
128 
129     /**
130      * Get the attitude provider to use for the given date.
131      * @param date of query
132      * @return attitude provider to use on date.
133      */
134     private BoundedAttitudeProvider getAttitudeProvider(final AbsoluteDate date) {
135         final Entry<AbsoluteDate, BoundedAttitudeProvider> attitudeEntry = providers.floorEntry(date);
136         if (attitudeEntry != null) {
137             return attitudeEntry.getValue();
138         } else {
139             // Let the first attitude provider throw the exception
140             return providers.firstEntry().getValue();
141         }
142     }
143 
144 }