1 /* Copyright 2002-2025 Joseph Reed
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 * Joseph Reed 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.utils;
18
19 import java.util.Objects;
20
21 import org.hipparchus.geometry.euclidean.threed.Vector3D;
22 import org.orekit.errors.OrekitException;
23 import org.orekit.errors.OrekitMessages;
24 import org.orekit.frames.Frame;
25 import org.orekit.time.AbsoluteDate;
26
27 /** Aggregate multiple {@link PVCoordinatesProvider} instances together.
28 * <p>
29 * This can be used to describe an aircraft or surface vehicle.
30 * </p>
31 * @author Joe Reed
32 * @since 11.3
33 */
34 public class AggregatedPVCoordinatesProvider implements PVCoordinatesProvider {
35
36 /** Map of provider instances by transition time. */
37 private final TimeSpanMap<PVCoordinatesProvider> pvProvMap;
38
39 /** Earliest date at which {@link #getPVCoordinates(AbsoluteDate, Frame)} will return a valid result. */
40 private final AbsoluteDate minDate;
41
42 /** Latest date at which {@link #getPVCoordinates(AbsoluteDate, Frame)} will return a valid result. */
43 private final AbsoluteDate maxDate;
44
45 /** Class constructor.
46 * <p>
47 * Note the provided {@code map} is used directly. Modification of the
48 * map after calling this constructor may result in undefined behavior.
49 * </p>
50 * @param map the map of {@link PVCoordinatesProvider} instances by time.
51 */
52 public AggregatedPVCoordinatesProvider(final TimeSpanMap<PVCoordinatesProvider> map) {
53 this(map, null, null);
54 }
55
56 /** Class constructor.
57 * <p>
58 * Note the provided {@code map} is used directly. Modification of the
59 * map after calling this constructor may result in undefined behavior.
60 * </p>
61 * @param map the map of {@link PVCoordinatesProvider} instances by time.
62 * @param minDate the earliest valid date, {@code null} if always valid
63 * @param maxDate the latest valid date, {@code null} if always valid
64 */
65 public AggregatedPVCoordinatesProvider(final TimeSpanMap<PVCoordinatesProvider> map,
66 final AbsoluteDate minDate, final AbsoluteDate maxDate) {
67 this.pvProvMap = Objects.requireNonNull(map, "PVCoordinatesProvider map must be non-null");
68 this.minDate = minDate == null ? AbsoluteDate.PAST_INFINITY : minDate;
69 this.maxDate = maxDate == null ? AbsoluteDate.FUTURE_INFINITY : maxDate;
70 }
71
72 /** Get the first date of the range.
73 * @return the first date of the range
74 */
75 public AbsoluteDate getMinDate() {
76 return minDate;
77 }
78
79 /** Get the last date of the range.
80 * @return the last date of the range
81 */
82 public AbsoluteDate getMaxDate() {
83 return maxDate;
84 }
85
86 @Override
87 public Vector3D getPosition(final AbsoluteDate date, final Frame frame) {
88 if (date.isBefore(minDate) || date.isAfter(maxDate)) {
89 throw new OrekitException(OrekitMessages.OUT_OF_RANGE_DATE, date, minDate, maxDate);
90 }
91 return pvProvMap.get(date).getPosition(date, frame);
92 }
93
94 @Override
95 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
96 if (date.isBefore(minDate) || date.isAfter(maxDate)) {
97 throw new OrekitException(OrekitMessages.OUT_OF_RANGE_DATE, date, minDate, maxDate);
98 }
99 return pvProvMap.get(date).getPVCoordinates(date, frame);
100 }
101
102 /**
103 * Builder class for {@link AggregatedPVCoordinatesProvider}.
104 */
105 public static class Builder {
106
107 /** Time span map holding the incremental values. */
108 private final TimeSpanMap<PVCoordinatesProvider> pvProvMap;
109
110 /**
111 * Create a builder using the {@link InvalidPVProvider} as the initial provider.
112 */
113 public Builder() {
114 this(new InvalidPVProvider());
115 }
116
117 /**
118 * Create a builder using the provided initial provider.
119 *
120 * @param initialProvider the inital provider
121 */
122 public Builder(final PVCoordinatesProvider initialProvider) {
123 pvProvMap = new TimeSpanMap<>(initialProvider);
124 }
125
126 /** Add a {@link PVCoordinatesProvider} to the collection.
127 * <p>
128 * The provided date is the transition time, at which this provider will be used.
129 * </p>
130 * @param date the transition date
131 * @param pvProv the provider
132 * @param erasesLater if true, the entry erases all existing transitions that are later than {@code date}
133 * @return this builder instance
134 * @see TimeSpanMap#addValidAfter(Object, AbsoluteDate, boolean)
135 */
136 public Builder addPVProviderAfter(final AbsoluteDate date,
137 final PVCoordinatesProvider pvProv,
138 final boolean erasesLater) {
139 pvProvMap.addValidAfter(pvProv, date, erasesLater);
140 return this;
141 }
142
143 /** Add a {@link PVCoordinatesProvider} to the collection.
144 * <p>
145 * The provided date is the final transition time, before which this provider will be used.
146 * </p>
147 * @param date the transition date
148 * @param pvProv the provider
149 * @param erasesEarlier if true, the entry erases all existing transitions that are earlier than {@code date}
150 * @return this builder instance
151 * @see TimeSpanMap#addValidBefore(Object, AbsoluteDate, boolean)
152 */
153 public Builder addPVProviderBefore(final AbsoluteDate date, final PVCoordinatesProvider pvProv, final boolean erasesEarlier) {
154 pvProvMap.addValidBefore(pvProv, date, erasesEarlier);
155 return this;
156 }
157
158 /** Indicate the date before which the resulting PVCoordinatesProvider is invalid.
159 *
160 * @param firstValidDate first date at which the resuling provider should be valid
161 * @return this instance
162 */
163 public Builder invalidBefore(final AbsoluteDate firstValidDate) {
164 pvProvMap.addValidBefore(new InvalidPVProvider(), firstValidDate, true);
165 return this;
166 }
167
168 /** Indicate the date after which the resulting PVCoordinatesProvider is invalid.
169 *
170 * @param lastValidDate last date at which the resuling provider should be valid
171 * @return this instance
172 */
173 public Builder invalidAfter(final AbsoluteDate lastValidDate) {
174 pvProvMap.addValidAfter(new InvalidPVProvider(), lastValidDate, true);
175 return this;
176 }
177
178 /** Build the aggregated PVCoordinatesProvider.
179 *
180 * @return the new provider instance.
181 */
182 public AggregatedPVCoordinatesProvider build() {
183 AbsoluteDate minDate = null;
184 AbsoluteDate maxDate = null;
185 // check the first span
186 if (pvProvMap.getFirstTransition() != null) {
187 if (pvProvMap.getFirstTransition().getBefore() instanceof InvalidPVProvider) {
188 minDate = pvProvMap.getFirstTransition().getDate();
189 }
190 }
191 if (pvProvMap.getLastTransition() != null) {
192 if (pvProvMap.getLastTransition().getAfter() instanceof InvalidPVProvider) {
193 maxDate = pvProvMap.getLastTransition().getDate();
194 }
195 }
196 return new AggregatedPVCoordinatesProvider(pvProvMap, minDate, maxDate);
197 }
198 }
199
200 /** Implementation of {@link PVCoordinatesProvider} that throws an {@link OrekitException} exception.
201 *
202 */
203 public static class InvalidPVProvider implements PVCoordinatesProvider {
204
205 /** Empty constructor.
206 * <p>
207 * This constructor is not strictly necessary, but it prevents spurious
208 * javadoc warnings with JDK 18 and later.
209 * </p>
210 * @since 12.0
211 */
212 public InvalidPVProvider() {
213 // nothing to do
214 }
215
216 @Override
217 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
218 throw new OrekitException(OrekitMessages.OUT_OF_RANGE_DATE, date);
219 }
220
221 }
222
223 }