1 /* Copyright 2002-2025 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.utils;
18
19 import java.util.Collections;
20 import java.util.NavigableSet;
21 import java.util.SortedSet;
22 import java.util.TreeSet;
23
24 import org.orekit.time.FieldAbsoluteDate;
25 import org.orekit.time.TimeStamped;
26 import org.hipparchus.Field;
27 import org.hipparchus.CalculusFieldElement;
28 import org.orekit.time.AbsoluteDate;
29 import org.orekit.time.ChronologicalComparator;
30
31 /** Container for objects that apply to spans of time.
32
33 * @param <T> Type of the data.
34 * @param <D> type of the field elements
35
36 * @author Luc Maisonobe
37 * @since 7.1
38 */
39 public class FieldTimeSpanMap<T, D extends CalculusFieldElement<D>> {
40
41 /** Container for the data. */
42 private final NavigableSet<Transition<T, D>> data;
43
44 /**Field.*/
45 private final Field<D> field;
46
47 /** Create a map containing a single object, initially valid throughout the timeline.
48 * <p>
49 * The real validity of this first entry will be truncated as other
50 * entries are either {@link #addValidBefore(Object, FieldAbsoluteDate)
51 * added before} it or {@link #addValidAfter(Object, FieldAbsoluteDate)
52 * added after} it.
53 * </p>
54 * @param entry entry (initially valid throughout the timeline)
55 * @param field_n field used by default.
56 */
57 public FieldTimeSpanMap(final T entry, final Field<D> field_n) {
58 data = new TreeSet<>(new ChronologicalComparator());
59 field = field_n;
60 data.add(new Transition<>(FieldAbsoluteDate.getArbitraryEpoch(field), entry, entry));
61 }
62
63 /** Add an entry valid before a limit date.
64 * <p>
65 * As an entry is valid, it truncates the validity of the neighboring
66 * entries already present in the map.
67 * </p>
68 * <p>
69 * The transition dates should be entered only once, either
70 * by a call to this method or by a call to {@link #addValidAfter(Object,
71 * FieldAbsoluteDate)}. Repeating a transition date will lead to unexpected
72 * result and is not supported.
73 * </p>
74 * @param entry entry to add
75 * @param latestValidityDate date before which the entry is valid
76 * (sould be different from <em>all</em> dates already used for transitions)
77 */
78 public void addValidBefore(final T entry, final FieldAbsoluteDate<D> latestValidityDate) {
79
80 if (data.size() == 1) {
81 final Transition<T, D> single = data.first();
82 if (single.getBefore() == single.getAfter()) {
83 // the single entry was a dummy one, without a real transition
84 // we replace it entirely
85 data.clear();
86 data.add(new Transition<>(latestValidityDate, entry, single.getAfter()));
87 return;
88 }
89 }
90
91 final Transition<T, D> previous =
92 data.floor(new Transition<>(latestValidityDate, entry, null));
93 if (previous == null) {
94 // the new transition will be the first one
95 data.add(new Transition<>(latestValidityDate, entry, data.first().getBefore()));
96 } else {
97 // the new transition will be after the previous one
98 data.remove(previous);
99 data.add(new Transition<>(previous.date, previous.getBefore(), entry));
100 data.add(new Transition<>(latestValidityDate, entry, previous.getAfter()));
101 }
102
103 }
104
105 /** Add an entry valid after a limit date.
106 * <p>
107 * As an entry is valid, it truncates the validity of the neighboring
108 * entries already present in the map.
109 * </p>
110 * <p>
111 * The transition dates should be entered only once, either
112 * by a call to this method or by a call to {@link #addValidBefore(Object,
113 * FieldAbsoluteDate)}. Repeating a transition date will lead to unexpected
114 * result and is not supported.
115 * </p>
116 * @param entry entry to add
117 * @param earliestValidityDate date after which the entry is valid
118 * (sould be different from <em>all</em> dates already used for transitions)
119 */
120 public void addValidAfter(final T entry, final FieldAbsoluteDate<D> earliestValidityDate) {
121
122 if (data.size() == 1) {
123 final Transition<T, D> single = data.first();
124 if (single.getBefore() == single.getAfter()) {
125 // the single entry was a dummy one, without a real transition
126 // we replace it entirely
127 data.clear();
128 data.add(new Transition<>(earliestValidityDate, single.getBefore(), entry));
129 return;
130 }
131 }
132
133 final Transition<T, D> next =
134 data.ceiling(new Transition<>(earliestValidityDate, entry, null));
135 if (next == null) {
136 // the new transition will be the last one
137 data.add(new Transition<>(earliestValidityDate, data.last().getAfter(), entry));
138 } else {
139 // the new transition will be before the next one
140 data.remove(next);
141 data.add(new Transition<>(earliestValidityDate, next.getBefore(), entry));
142 data.add(new Transition<>(next.date, entry, next.getAfter()));
143 }
144
145 }
146
147 /** Get the entry valid at a specified date.
148 * @param date date at which the entry must be valid
149 * @return valid entry at specified date
150 */
151 public T get(final FieldAbsoluteDate<D> date) {
152 final Transition<T, D> previous = data.floor(new Transition<>(date, null, null));
153 if (previous == null) {
154 // there are no transition before the specified date
155 // return the first valid entry
156 return data.first().getBefore();
157 } else {
158 return previous.getAfter();
159 }
160 }
161
162 /** Get an unmodifiable view of the sorted transitions.
163 * @return unmodifiable view of the sorted transitions
164 */
165 public SortedSet<Transition<T, D>> getTransitions() {
166 return Collections.unmodifiableSortedSet(data);
167 }
168
169 /** Local class holding transition times.
170 * @param <D> type of the field elements
171 * @param <S> type of the data
172 */
173 public static class Transition<S, D extends CalculusFieldElement<D>> implements TimeStamped {
174
175 /** Transition date. */
176 private final FieldAbsoluteDate<D> date;
177
178 /** Entry valid before the transition. */
179 private final S before;
180
181 /** Entry valid after the transition. */
182 private final S after;
183
184 /** Simple constructor.
185 * @param date transition date
186 * @param before entry valid before the transition
187 * @param after entry valid after the transition
188 */
189 private Transition(final FieldAbsoluteDate<D> date, final S before, final S after) {
190 this.date = date;
191 this.before = before;
192 this.after = after;
193 }
194
195 /** Get the transition field absolute date.
196 * @return transition date
197 */
198 public FieldAbsoluteDate<D> getAbsoluteDate() {
199 return date;
200 }
201 /** Get the transition absolute date.
202 * @return transition date
203 */
204
205 public AbsoluteDate getDate() {
206 return date.toAbsoluteDate();
207 }
208 /** Get the entry valid before transition.
209 * @return entry valid before transition
210 */
211 public S getBefore() {
212 return before;
213 }
214
215 /** Get the entry valid after transition.
216 * @return entry valid after transition
217 */
218 public S getAfter() {
219 return after;
220 }
221
222 }
223
224
225
226 }