1   /* Copyright 2002-2026 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.propagation.relative.maneuver;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
21  import org.hipparchus.ode.events.Action;
22  import org.orekit.propagation.FieldSpacecraftState;
23  import org.orekit.propagation.events.FieldEventDetector;
24  import org.orekit.propagation.events.handlers.FieldEventHandler;
25  import org.orekit.propagation.relative.FieldRelativeProvider;
26  import org.orekit.time.FieldAbsoluteDate;
27  import org.orekit.utils.FieldArrayDictionary;
28  import org.orekit.utils.FieldDataDictionary;
29  import org.orekit.utils.FieldPVCoordinates;
30  import org.orekit.utils.TimeStampedFieldPVCoordinates;
31  
32  import java.util.Objects;
33  
34  /**
35   * Abstract class for implementing an impulse maneuver for a chaser spacecraft.
36   *
37   * @param <T> type of the field element
38   * @param <P> type of the relative motion provider
39   * @author Romain Cuvillon
40   * @since 14.0
41   */
42  public abstract class FieldAbstractRelativeManeuver<T extends CalculusFieldElement<T>, P extends FieldRelativeProvider<T>>
43                  implements FieldRelativeManeuver<T> {
44  
45      /** Trigger event. */
46      private final FieldEventDetector<T> trigger;
47  
48      /** ΔV vector in the target's LOF. */
49      private final FieldVector3D<T> deltaV;
50  
51      /** True if the propagation is forward in time. */
52      private boolean forward;
53  
54      /** Relative Provider. */
55      private final P relativeProvider;
56  
57      /** Event Handler. */
58      private final FieldEventHandler<T> handler;
59  
60      /**
61       * Creates a new {@link FieldAbstractRelativeManeuver} from an event detector, a ΔV vector, and a
62       * {@link FieldRelativeProvider}.
63       *
64       * @param trigger          Triggering event detector.
65       * @param deltaV           ΔV vector in the local orbital frame of the theory used by the given
66       *                         {@link FieldRelativeProvider}.
67       * @param relativeProvider Relative motion equations provider.
68       */
69      public FieldAbstractRelativeManeuver(final FieldEventDetector<T> trigger, final FieldVector3D<T> deltaV,
70                                           final P relativeProvider) {
71          this.trigger          = trigger;
72          this.deltaV           = deltaV;
73          this.relativeProvider = relativeProvider;
74          this.handler          = new Handler<>();
75      }
76  
77      /** {@inheritDoc} */
78      @Override
79      public void init(final FieldSpacecraftState<T> s0, final FieldAbsoluteDate<T> t) {
80          forward = t.durationFrom(s0.getDate()).getReal() >= 0;
81          getDetector().init(s0, t);
82      }
83  
84      /** {@inheritDoc} */
85      @Override
86      public FieldEventDetector<T> getDetector() {
87          return trigger;
88      }
89  
90      /**
91       * Getter for the forward boolean.
92       *
93       * @return forward boolean
94       */
95      public boolean getForward() {
96          return forward;
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public FieldVector3D<T> getDeltaV() {
102         return deltaV;
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public P getRelativeProvider() {
108         return this.relativeProvider;
109     }
110 
111     /** {@inheritDoc} */
112     @Override
113     public FieldEventHandler<T> getHandler() {
114         return handler;
115     }
116 
117     /**
118      * Local handler.
119      * <p>
120      * Apply the maneuver to the chaser S/C in the additional state.
121      * </p>
122      */
123     private static class Handler<T extends CalculusFieldElement<T>> implements FieldEventHandler<T> {
124 
125         /** {@inheritDoc} */
126         @Override
127         public Action eventOccurred(final FieldSpacecraftState<T> s, final FieldEventDetector<T> detector,
128                                     final boolean increasing) {
129             final FieldAbstractRelativeManeuver<T, ?> im = (FieldAbstractRelativeManeuver<T, ?>) detector;
130             final Action underlyingAction =
131                             im.getDetector().getHandler().eventOccurred(s, im.getDetector(), increasing);
132             return (underlyingAction == Action.STOP) ? Action.RESET_STATE : Action.CONTINUE;
133         }
134 
135         /** {@inheritDoc} */
136         @Override
137         public FieldSpacecraftState<T> resetState(final FieldEventDetector<T> detector,
138                                                   final FieldSpacecraftState<T> oldState) {
139             final FieldAbstractRelativeManeuver<T, ?> maneuver = (FieldAbstractRelativeManeuver<T, ?>) detector;
140 
141             // Get velocity increment from maneuver
142             final FieldVector3D<T> deltaV = maneuver.getDeltaV();
143             final double sign = maneuver.getForward() ? +1 : -1;
144 
145             // Apply increment to velocity of the chaser
146             final T[] chaserPV = oldState.getAdditionalState(maneuver.getRelativeProvider().getName());
147             chaserPV[3] = chaserPV[3].add(deltaV.getX().multiply(sign));
148             chaserPV[4] = chaserPV[4].add(deltaV.getY().multiply(sign));
149             chaserPV[5] = chaserPV[5].add(deltaV.getZ().multiply(sign));
150 
151             // Reset the equations provider with the new chaser state
152             maneuver.getRelativeProvider().setInitialChaserPVTLof(
153                             new TimeStampedFieldPVCoordinates<>(oldState.getDate(), new FieldPVCoordinates<>(
154                                             new FieldVector3D<>(chaserPV[0], chaserPV[1], chaserPV[2]),
155                                             new FieldVector3D<>(chaserPV[3], chaserPV[4], chaserPV[5]))));
156 
157             // Pack everything in a new state
158             FieldSpacecraftState<T> newState =
159                             new FieldSpacecraftState<>(oldState.getOrbit(), oldState.getAttitude()).withMass(
160                                             oldState.getMass());
161 
162             // Reset the TrueAnomaly of the spacecraft to the current true anomaly if YA is used / do nothing if CW.
163             maneuver.resetTrueAnomalyAtManeuver(oldState.getOrbit());
164 
165             // Add additional equations
166             for (final FieldDataDictionary<T>.Entry entry : oldState.getAdditionalDataValues().getData()) {
167                 if (!Objects.equals(entry.getKey(), maneuver.getRelativeProvider().getName())) {
168                     newState = newState.addAdditionalData(entry.getKey(), entry.getValue());
169                 } else {
170                     // Use modified chaser PV if the additional state is the currently used provider
171                     newState = newState.addAdditionalData(maneuver.getRelativeProvider().getName(), chaserPV);
172                 }
173             }
174 
175             // Add additional equations' derivatives
176             for (final FieldArrayDictionary<T>.Entry entry : oldState.getAdditionalStatesDerivatives().getData()) {
177                 newState = newState.addAdditionalStateDerivative(entry.getKey(), entry.getValue());
178             }
179 
180             return newState;
181         }
182     }
183 }