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.time;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.util.FastMath;
23  
24  /** Selector generating a continuous stream of dates separated by a constant step.
25   * <p>
26   * The dates can be aligned to whole steps in some time scale. So for example
27   * if a step of 60s is used and the alignment time scale is set to
28   * {@link org.orekit.time.TimeScales#getUTC() UTC}, dates will be selected
29   * at whole minutes in UTC time.
30   * </p>
31   * <p>
32   * BEWARE! This class stores internally the last selected dates, so it is <em>neither</em>
33   * reusable across several {@link org.orekit.estimation.measurements.generation.EventBasedScheduler
34   * fixed step} or {@link org.orekit.estimation.measurements.generation.ContinuousScheduler
35   * continuous} schedulers, <em>nor</em> thread-safe. A separate selector should be used for each
36   * scheduler and for each thread in multi-threading context.
37   * </p>
38   * @author Luc Maisonobe
39   * @since 9.3
40   */
41  public class FixedStepSelector implements DatesSelector {
42  
43      /** Step between two consecutive dates. */
44      private final double step;
45  
46      /** Alignment time scale (null is alignment is not needed). */
47      private final TimeScale alignmentTimeScale;
48  
49      /** Last selected date. */
50      private AbsoluteDate last;
51  
52      /** Simple constructor.
53       * @param step step between two consecutive dates (s)
54       * @param alignmentTimeScale alignment time scale (null is alignment is not needed)
55       */
56      public FixedStepSelector(final double step, final TimeScale alignmentTimeScale) {
57          this.step               = step;
58          this.alignmentTimeScale = alignmentTimeScale;
59          this.last               = null;
60      }
61  
62      /** {@inheritDoc} */
63      @Override
64      public List<AbsoluteDate> selectDates(final AbsoluteDate start, final AbsoluteDate end) {
65  
66          final double sign = FastMath.copySign(1, end.durationFrom(start));
67          final List<AbsoluteDate> selected = new ArrayList<>();
68  
69          final boolean reset = last == null || sign * start.durationFrom(last) > step;
70          for (AbsoluteDate next = reset ? start : last.shiftedBy(sign * step);
71               sign * next.durationFrom(end) <= 0;
72               next = last.shiftedBy(sign * step)) {
73  
74              if (alignmentTimeScale != null) {
75                  // align date to time scale
76                  final double t  = next.getComponents(alignmentTimeScale).getTime().getSecondsInLocalDay();
77                  final double dt = step * FastMath.round(t / step) - t;
78                  next = next.shiftedBy(dt);
79              }
80  
81              if (sign * next.durationFrom(start) >= 0) {
82                  if (sign * next.durationFrom(end) <= 0) {
83                      // the date is within range, select it
84                      selected.add(next);
85                  } else {
86                      // we have exceeded date range
87                      break;
88                  }
89              }
90              last = next;
91  
92          }
93  
94          return selected;
95  
96      }
97  
98  }