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