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.propagation.events;
18  
19  import org.hipparchus.ode.events.Action;
20  import org.orekit.bodies.BodyShape;
21  import org.orekit.bodies.GeodeticPoint;
22  import org.orekit.frames.Frame;
23  import org.orekit.propagation.SpacecraftState;
24  import org.orekit.propagation.events.handlers.EventHandler;
25  import org.orekit.propagation.events.handlers.StopOnDecreasing;
26  
27  /** Finder for satellite altitude crossing events.
28   * <p>This class finds altitude events (i.e. satellite crossing
29   * a predefined altitude level above ground).</p>
30   * <p>The default implementation behavior is to {@link Action#CONTINUE
31   * continue} propagation when ascending and to {@link Action#STOP stop}
32   * propagation when descending. This can be changed by calling
33   * {@link #withHandler(EventHandler)} after construction.</p>
34   * @see org.orekit.propagation.Propagator#addEventDetector(EventDetector)
35   * @author Luc Maisonobe
36   */
37  public class AltitudeDetector extends AbstractDetector<AltitudeDetector> {
38  
39      /** Threshold altitude value (m). */
40      private final double altitude;
41  
42      /** Body shape with respect to which altitude should be evaluated. */
43      private final BodyShape bodyShape;
44  
45      /** Build a new altitude detector.
46       * <p>This simple constructor takes default values for maximal checking
47       *  interval ({@link #DEFAULT_MAX_CHECK}) and convergence threshold
48       * ({@link #DEFAULT_THRESHOLD}).</p>
49       * @param altitude threshold altitude value
50       * @param bodyShape body shape with respect to which altitude should be evaluated
51       */
52      public AltitudeDetector(final double altitude, final BodyShape bodyShape) {
53          this(EventDetectionSettings.DEFAULT_MAX_CHECK, altitude, bodyShape);
54      }
55  
56      /** Build a new altitude detector.
57       * <p>This simple constructor takes default value for convergence threshold
58       * ({@link #DEFAULT_THRESHOLD}).</p>
59       * <p>The maximal interval between altitude checks should
60       * be smaller than the half duration of the minimal pass to handle,
61       * otherwise some short passes could be missed.</p>
62       * @param maxCheck maximal checking interval (s)
63       * @param altitude threshold altitude value (m)
64       * @param bodyShape body shape with respect to which altitude should be evaluated
65       */
66      public AltitudeDetector(final double maxCheck, final double altitude, final BodyShape bodyShape) {
67          this(maxCheck, DEFAULT_THRESHOLD, altitude, bodyShape);
68      }
69  
70      /** Build a new altitude detector.
71       * <p>The maximal interval between altitude checks should
72       * be smaller than the half duration of the minimal pass to handle,
73       * otherwise some short passes could be missed.</p>
74       * <p>The maximal interval between altitude checks should
75       * be smaller than the half duration of the minimal pass to handle,
76       * otherwise some short passes could be missed.</p>
77       * @param maxCheck maximal checking interval (s)
78       * @param threshold convergence threshold (s)
79       * @param altitude threshold altitude value (m)
80       * @param bodyShape body shape with respect to which altitude should be evaluated
81       */
82      public AltitudeDetector(final double maxCheck, final double threshold, final double altitude,
83                              final BodyShape bodyShape) {
84          this(new EventDetectionSettings(maxCheck, threshold, DEFAULT_MAX_ITER), new StopOnDecreasing(),
85                  altitude, bodyShape);
86      }
87  
88      /** Protected constructor with full parameters.
89       * <p>
90       * This constructor is not public as users are expected to use the builder
91       * API with the various {@code withXxx()} methods to set up the instance
92       * in a readable manner without using a huge amount of parameters.
93       * </p>
94       * @param detectionSettings detection settings
95       * @param handler event handler to call at event occurrences
96       * @param altitude threshold altitude value (m)
97       * @param bodyShape body shape with respect to which altitude should be evaluated
98       * @since 13.0
99       */
100     protected AltitudeDetector(final EventDetectionSettings detectionSettings, final EventHandler handler,
101                                final double altitude,
102                                final BodyShape bodyShape) {
103         super(detectionSettings, handler);
104         this.altitude  = altitude;
105         this.bodyShape = bodyShape;
106     }
107 
108     /** {@inheritDoc} */
109     @Override
110     protected AltitudeDetector create(final EventDetectionSettings detectionSettings, final EventHandler newHandler) {
111         return new AltitudeDetector(detectionSettings, newHandler, altitude, bodyShape);
112     }
113 
114     /** Get the threshold altitude value.
115      * @return the threshold altitude value (m)
116      */
117     public double getAltitude() {
118         return altitude;
119     }
120 
121     /** Get the body shape.
122      * @return the body shape
123      */
124     public BodyShape getBodyShape() {
125         return bodyShape;
126     }
127 
128     /** Compute the value of the switching function.
129      * This function measures the difference between the current altitude
130      * and the threshold altitude.
131      * @param s the current state information: date, kinematics, attitude
132      * @return value of the switching function
133      */
134     public double g(final SpacecraftState s) {
135         final Frame bodyFrame      = bodyShape.getBodyFrame();
136         final GeodeticPoint point  = bodyShape.transform(s.getPosition(bodyFrame), bodyFrame, s.getDate());
137         return point.getAltitude() - altitude;
138     }
139 
140 }