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.events;
18  
19  import org.orekit.errors.OrekitException;
20  import org.orekit.errors.OrekitMessages;
21  import org.orekit.propagation.SpacecraftState;
22  import org.orekit.propagation.events.functions.EventFunction;
23  import org.orekit.propagation.events.handlers.EventHandler;
24  import org.orekit.propagation.events.intervals.AdaptableInterval;
25  import org.orekit.time.AbsoluteDate;
26  
27  /** Common parts shared by several events finders.
28   * It should only be implemented by detectors able to accept any handler.
29   * @param <T> type of the detector
30   * @see org.orekit.propagation.Propagator#addEventDetector(EventDetector)
31   * @author Luc Maisonobe
32   */
33  public abstract class AbstractDetector<T extends AbstractDetector<T>> implements EventDetector {
34  
35      /** Default maximum checking interval (s). */
36      public static final double DEFAULT_MAX_CHECK = EventDetectionSettings.DEFAULT_MAX_CHECK;
37  
38      /** Default convergence threshold (s). */
39      public static final double DEFAULT_THRESHOLD = EventDetectionSettings.DEFAULT_THRESHOLD;
40  
41      /** Default maximum number of iterations in the event time search. */
42      public static final int DEFAULT_MAX_ITER = EventDetectionSettings.DEFAULT_MAX_ITER;
43  
44      /** Detection settings. */
45      private final EventDetectionSettings eventDetectionSettings;
46  
47      /** Handler for event overrides. */
48      private final EventHandler handler;
49  
50      /** Default event function. */
51      private final EventFunction defaultEventFunction;
52  
53      /** Propagation direction. */
54      private boolean forward = true;
55  
56      /** Build a new instance.
57       * @param maxCheck maximum checking interval, must be strictly positive (s)
58       * @param threshold convergence threshold (s)
59       * @param maxIter maximum number of iterations in the event time search
60       * @param handler event handler to call at event occurrences
61       */
62      protected AbstractDetector(final double maxCheck, final double threshold, final int maxIter,
63                                 final EventHandler handler) {
64          this(new EventDetectionSettings(maxCheck, threshold, maxIter), handler);
65      }
66  
67      /** Build a new instance.
68       * @param detectionSettings event detection settings
69       * @param handler event handler to call at event occurrences
70       * @since 12.2
71       */
72      protected AbstractDetector(final EventDetectionSettings detectionSettings, final EventHandler handler) {
73          checkStrictlyPositive(detectionSettings.getThreshold());
74          this.eventDetectionSettings = detectionSettings;
75          this.handler   = handler;
76          this.defaultEventFunction = this::g;
77      }
78  
79      /** Build a new instance.
80       * @param eventFunction event function
81       * @param detectionSettings event detection settings
82       * @param handler event handler to call at event occurrences
83       * @since 14.0
84       */
85      protected AbstractDetector(final EventFunction eventFunction,
86                                 final EventDetectionSettings detectionSettings,
87                                 final EventHandler handler) {
88          checkStrictlyPositive(detectionSettings.getThreshold());
89          this.eventDetectionSettings = detectionSettings;
90          this.handler   = handler;
91          this.defaultEventFunction = eventFunction;
92      }
93  
94      /**
95       * Check if propagation is forward or not.
96       * @param state initial state
97       * @param targetDate target propagation date
98       * @return forward flag
99       * @since 13.0
100      */
101     public static boolean checkIfForward(final SpacecraftState state, final AbsoluteDate targetDate) {
102         return targetDate.durationFrom(state.getDate()) >= 0.0;
103     }
104 
105     /** Check value is strictly positive.
106      * @param value value to check
107      * @exception OrekitException if value is not strictly positive
108      * @since 11.2
109      */
110     private void checkStrictlyPositive(final double value) throws OrekitException {
111         if (value <= 0.0) {
112             throw new OrekitException(OrekitMessages.NOT_STRICTLY_POSITIVE, value);
113         }
114     }
115 
116     /**
117      * {@inheritDoc}
118      *
119      * <p> This implementation sets the direction of propagation and initializes the event
120      * handler. If a subclass overrides this method it should call {@code
121      * super.init(s0, t)}.
122      */
123     @Override
124     public void init(final SpacecraftState s0,
125                      final AbsoluteDate t) {
126         EventDetector.super.init(s0, t);
127         forward = checkIfForward(s0, t);
128     }
129 
130     @Override
131     public EventFunction getEventFunction() {
132         return defaultEventFunction;
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public EventDetectionSettings getDetectionSettings() {
138         return eventDetectionSettings;
139     }
140 
141     /**
142      * Set up the maximum checking interval.
143      * <p>
144      * This will override a maximum checking interval if it has been configured previously.
145      * </p>
146      * @param newMaxCheck maximum checking interval (s)
147      * @return a new detector with updated configuration (the instance is not changed)
148      * @since 6.1
149      */
150     public T withMaxCheck(final double newMaxCheck) {
151         return withMaxCheck(AdaptableInterval.of(newMaxCheck));
152     }
153 
154     /**
155      * Set up the maximum checking interval.
156      * <p>
157      * This will override a maximum checking interval if it has been configured previously.
158      * </p>
159      * @param newMaxCheck maximum checking interval (s)
160      * @return a new detector with updated configuration (the instance is not changed)
161      * @since 12.0
162      */
163     public T withMaxCheck(final AdaptableInterval newMaxCheck) {
164         return withDetectionSettings(new EventDetectionSettings(newMaxCheck, getThreshold(), getMaxIterationCount()));
165     }
166 
167     /**
168      * Set up the maximum number of iterations in the event time search.
169      * <p>
170      * This will override a number of iterations if it has been configured previously.
171      * </p>
172      * @param newMaxIter maximum number of iterations in the event time search
173      * @return a new detector with updated configuration (the instance is not changed)
174      * @since 6.1
175      */
176     public T withMaxIter(final int newMaxIter) {
177         return withDetectionSettings(new EventDetectionSettings(getMaxCheckInterval(), getThreshold(), newMaxIter));
178     }
179 
180     /**
181      * Set up the convergence threshold.
182      * <p>
183      * This will override a convergence threshold if it has been configured previously.
184      * </p>
185      * @param newThreshold convergence threshold (s)
186      * @return a new detector with updated configuration (the instance is not changed)
187      * @since 6.1
188      */
189     public T withThreshold(final double newThreshold) {
190         return withDetectionSettings(new EventDetectionSettings(getMaxCheckInterval(), newThreshold, getMaxIterationCount()));
191     }
192 
193     /**
194      * Set up the event detection settings.
195      * <p>
196      * This will override settings previously configured.
197      * </p>
198      * @param newSettings new event detection settings
199      * @return a new detector with updated configuration (the instance is not changed)
200      * @since 12.2
201      */
202     public T withDetectionSettings(final EventDetectionSettings newSettings) {
203         return create(new EventDetectionSettings(newSettings.getMaxCheckInterval(), newSettings.getThreshold(), newSettings.getMaxIterationCount()),
204                 getHandler());
205     }
206 
207     /**
208      * Set up the event handler to call at event occurrences.
209      * <p>
210      * This will override a handler if it has been configured previously.
211      * </p>
212      * @param newHandler event handler to call at event occurrences
213      * @return a new detector with updated configuration (the instance is not changed)
214      * @since 6.1
215      */
216     public T withHandler(final EventHandler newHandler) {
217         return create(getDetectionSettings(), newHandler);
218     }
219 
220     /** {@inheritDoc} */
221     @Override
222     public EventHandler getHandler() {
223         return handler;
224     }
225 
226     /** Build a new instance.
227      * @param detectionSettings detection settings
228      * @param newHandler event handler to call at event occurrences
229      * @return a new instance of the appropriate sub-type
230      * @since 12.2
231      */
232     protected abstract T create(EventDetectionSettings detectionSettings, EventHandler newHandler);
233 
234     /** Check if the current propagation is forward or backward.
235      * @return true if the current propagation is forward
236      * @since 7.2
237      */
238     public boolean isForward() {
239         return forward;
240     }
241 
242 }