TimeSpanMap.java
- /* Copyright 2002-2018 CS Systèmes d'Information
- * Licensed to CS Systèmes d'Information (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.utils;
- import java.util.Collections;
- import java.util.NavigableSet;
- import java.util.SortedSet;
- import java.util.TreeSet;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.ChronologicalComparator;
- import org.orekit.time.TimeStamped;
- /** Container for objects that apply to spans of time.
- * @param <T> Type of the data.
- * @author Luc Maisonobe
- * @since 7.1
- */
- public class TimeSpanMap<T> {
- /** Container for the data. */
- private final NavigableSet<Transition<T>> data;
- /** Create a map containing a single object, initially valid throughout the timeline.
- * <p>
- * The real validity of this first entry will be truncated as other
- * entries are either {@link #addValidBefore(Object, AbsoluteDate)
- * added before} it or {@link #addValidAfter(Object, AbsoluteDate)
- * added after} it.
- * </p>
- * @param entry entry (initially valid throughout the timeline)
- */
- public TimeSpanMap(final T entry) {
- data = new TreeSet<Transition<T>>(new ChronologicalComparator());
- data.add(new Transition<T>(AbsoluteDate.J2000_EPOCH, entry, entry));
- }
- /** Add an entry valid before a limit date.
- * <p>
- * As an entry is valid, it truncates the validity of the neighboring
- * entries already present in the map.
- * </p>
- * <p>
- * The transition dates should be entered only once, either
- * by a call to this method or by a call to {@link #addValidAfter(Object,
- * AbsoluteDate)}. Repeating a transition date will lead to unexpected
- * result and is not supported.
- * </p>
- * @param entry entry to add
- * @param latestValidityDate date before which the entry is valid
- * (must be different from <em>all</em> dates already used for transitions)
- */
- public void addValidBefore(final T entry, final AbsoluteDate latestValidityDate) {
- if (data.size() == 1) {
- final Transition<T> single = data.first();
- if (single.getBefore() == single.getAfter()) {
- // the single entry was a dummy one, without a real transition
- // we replace it entirely
- data.clear();
- data.add(new Transition<T>(latestValidityDate, entry, single.getAfter()));
- return;
- }
- }
- final Transition<T> previous =
- data.floor(new Transition<T>(latestValidityDate, entry, null));
- if (previous == null) {
- // the new transition will be the first one
- data.add(new Transition<T>(latestValidityDate, entry, data.first().getBefore()));
- } else {
- // the new transition will be after the previous one
- data.remove(previous);
- data.add(new Transition<T>(previous.date, previous.getBefore(), entry));
- data.add(new Transition<T>(latestValidityDate, entry, previous.getAfter()));
- }
- }
- /** Add an entry valid after a limit date.
- * <p>
- * As an entry is valid, it truncates the validity of the neighboring
- * entries already present in the map.
- * </p>
- * <p>
- * The transition dates should be entered only once, either
- * by a call to this method or by a call to {@link #addValidBefore(Object,
- * AbsoluteDate)}. Repeating a transition date will lead to unexpected
- * result and is not supported.
- * </p>
- * @param entry entry to add
- * @param earliestValidityDate date after which the entry is valid
- * (must be different from <em>all</em> dates already used for transitions)
- */
- public void addValidAfter(final T entry, final AbsoluteDate earliestValidityDate) {
- if (data.size() == 1) {
- final Transition<T> single = data.first();
- if (single.getBefore() == single.getAfter()) {
- // the single entry was a dummy one, without a real transition
- // we replace it entirely
- data.clear();
- data.add(new Transition<T>(earliestValidityDate, single.getBefore(), entry));
- return;
- }
- }
- final Transition<T> next =
- data.ceiling(new Transition<T>(earliestValidityDate, entry, null));
- if (next == null) {
- // the new transition will be the last one
- data.add(new Transition<T>(earliestValidityDate, data.last().getAfter(), entry));
- } else {
- // the new transition will be before the next one
- data.remove(next);
- data.add(new Transition<T>(earliestValidityDate, next.getBefore(), entry));
- data.add(new Transition<T>(next.date, entry, next.getAfter()));
- }
- }
- /** Get the entry valid at a specified date.
- * @param date date at which the entry must be valid
- * @return valid entry at specified date
- */
- public T get(final AbsoluteDate date) {
- final Transition<T> previous = data.floor(new Transition<T>(date, null, null));
- if (previous == null) {
- // there are no transition before the specified date
- // return the first valid entry
- return data.first().getBefore();
- } else {
- return previous.getAfter();
- }
- }
- /** Extract a range of the map.
- * <p>
- * The object returned will be a new independent instance that will contain
- * only the transitions that lie in the specified range.
- * </p>
- * <p>
- * Consider for example a map containing objects O₀ valid before t₁, O₁ valid
- * between t₁ and t₂, O₂ valid between t₂ and t₃, O₃ valid between t₃ and t₄,
- * and O₄ valid after t₄. then calling this method with a {@code start}
- * date between t₁ and t₂ and a {@code end} date between t₃ and t₄
- * will result in a new map containing objects O₁ valid before t₂, O₂
- * valid between t₂ and t₃, and O₃ valid after t₃. The validity of O₁
- * is therefore extended in the past, and the validity of O₃ is extended
- * in the future.
- * </p>
- * @param start earliest date at which a transition is included in the range
- * (may be set to {@link AbsoluteDate#PAST_INFINITY} to keep all early transitions)
- * @param end latest date at which a transition is included in the r
- * (may be set to {@link AbsoluteDate#FUTURE_INFINITY} to keep all late transitions)
- * @return a new instance with all transitions restricted to the specified range
- * @since 9.2
- */
- public TimeSpanMap<T> extractRange(final AbsoluteDate start, final AbsoluteDate end) {
- final NavigableSet<Transition<T>> inRange = data.subSet(new Transition<T>(start, null, null), true,
- new Transition<T>(end, null, null), true);
- if (inRange.isEmpty()) {
- // there are no transitions at all in the range
- // we need to pick up the only valid object
- return new TimeSpanMap<>(get(start));
- }
- final TimeSpanMap<T> range = new TimeSpanMap<>(inRange.first().before);
- for (final Transition<T> transition : inRange) {
- range.addValidAfter(transition.after, transition.getDate());
- }
- return range;
- }
- /** Get an unmodifiable view of the sorted transitions.
- * @return unmodifiable view of the sorted transitions
- */
- public SortedSet<Transition<T>> getTransitions() {
- return Collections.unmodifiableSortedSet(data);
- }
- /** Local class holding transition times. */
- public static class Transition<S> implements TimeStamped {
- /** Transition date. */
- private final AbsoluteDate date;
- /** Entry valid before the transition. */
- private final S before;
- /** Entry valid after the transition. */
- private final S after;
- /** Simple constructor.
- * @param date transition date
- * @param before entry valid before the transition
- * @param after entry valid after the transition
- */
- private Transition(final AbsoluteDate date, final S before, final S after) {
- this.date = date;
- this.before = before;
- this.after = after;
- }
- /** Get the transition date.
- * @return transition date
- */
- @Override
- public AbsoluteDate getDate() {
- return date;
- }
- /** Get the entry valid before transition.
- * @return entry valid before transition
- */
- public S getBefore() {
- return before;
- }
- /** Get the entry valid after transition.
- * @return entry valid after transition
- */
- public S getAfter() {
- return after;
- }
- }
- }