1   /* Copyright 2022-2025 Luc Maisonobe
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.propagation.sampling;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.stream.Collectors;
22  
23  import org.hipparchus.util.FastMath;
24  import org.orekit.propagation.SpacecraftState;
25  import org.orekit.time.AbsoluteDate;
26  
27  /**
28   * This class wraps an object implementing {@link MultiSatFixedStepHandler}
29   * into a {@link MultiSatStepHandler}.
30  
31   * <p>It mirrors the <code>StepNormalizer</code> interface from <a
32   * href="https://hipparchus.org/">Hipparchus</a> but
33   * provides a space-dynamics interface to the methods.</p>
34   * @author Luc Maisonobe
35   * @since 12.0
36   */
37  public class MultisatStepNormalizer implements MultiSatStepHandler {
38  
39      /** Fixed time step. */
40      private double h;
41  
42      /** Underlying fixed step handler. */
43      private MultiSatFixedStepHandler handler;
44  
45      /** Last State vectors. */
46      private List<SpacecraftState> lastStates;
47  
48      /** Integration direction indicator. */
49      private boolean forward;
50  
51      /** Simple constructor.
52       * @param h fixed time step (sign is not used)
53       * @param handler fixed time step handler to wrap
54       */
55      public MultisatStepNormalizer(final double h, final MultiSatFixedStepHandler handler) {
56          this.h          = FastMath.abs(h);
57          this.handler    = handler;
58          this.lastStates = null;
59          this.forward    = true;
60      }
61  
62      /** Get the fixed time step.
63       * @return fixed time step
64       */
65      public double getFixedTimeStep() {
66          return h;
67      }
68  
69      /** Get the underlying fixed step handler.
70       * @return underlying fixed step handler
71       */
72      public MultiSatFixedStepHandler getFixedStepHandler() {
73          return handler;
74      }
75  
76      /** {@inheritDoc} */
77      public void init(final List<SpacecraftState> s0, final AbsoluteDate t) {
78          lastStates = new ArrayList<>(s0);
79          forward    = true;
80          handler.init(s0, t, h);
81      }
82  
83      /** {@inheritDoc} */
84      public void handleStep(final List<OrekitStepInterpolator> interpolators) {
85  
86          if (lastStates == null) {
87              // initialize lastState in the first step case
88              lastStates = interpolators.stream().map(OrekitStepInterpolator::getPreviousState).collect(Collectors.toList());
89          }
90  
91          // take the propagation direction into account
92          double step = h;
93          forward = interpolators.get(0).isForward();
94          if (!forward) {
95              step = -h;
96          }
97  
98  
99          // use the interpolator to push fixed steps events to the underlying handler
100         AbsoluteDate nextTime = lastStates.get(0).getDate().shiftedBy(step);
101         boolean nextInStep = forward ^ nextTime.compareTo(interpolators.get(0).getCurrentState().getDate()) > 0;
102         while (nextInStep) {
103 
104             // output the stored previous step
105             handler.handleStep(lastStates);
106 
107             // store the next step
108             final AbsoluteDate time = nextTime;
109             lastStates = interpolators.stream().map(i -> i.getInterpolatedState(time)).collect(Collectors.toList());
110 
111             // prepare next iteration
112             nextTime = nextTime.shiftedBy(step);
113             nextInStep = forward ^ nextTime.compareTo(interpolators.get(0).getCurrentState().getDate()) > 0;
114 
115         }
116 
117     }
118 
119     /** {@inheritDoc} */
120     @Override
121     public void finish(final List<SpacecraftState> finalStates) {
122 
123         // there will be no more steps,
124         // the stored one should be handled now
125         handler.handleStep(lastStates);
126 
127         // and the final state handled too
128         handler.finish(finalStates);
129 
130     }
131 
132 }