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.frames.TopocentricFrame;
21 import org.orekit.models.AtmosphericRefractionModel;
22 import org.orekit.propagation.SpacecraftState;
23 import org.orekit.propagation.events.handlers.EventHandler;
24 import org.orekit.propagation.events.handlers.StopOnDecreasing;
25 import org.orekit.propagation.events.intervals.AdaptableInterval;
26 import org.orekit.utils.ElevationMask;
27 import org.orekit.utils.TrackingCoordinates;
28
29
30 /**
31 * Finder for satellite raising/setting events that allows for the
32 * setting of azimuth and/or elevation bounds or a ground azimuth/elevation
33 * mask input. Each calculation be configured to use atmospheric refraction
34 * as well.
35 * <p>The default implementation behavior is to {@link Action#CONTINUE continue}
36 * propagation at raising and to {@link Action#STOP stop} propagation
37 * at setting. This can be changed by calling
38 * {@link #withHandler(EventHandler)} after construction.</p>
39 * @author Hank Grabowski
40 * @since 6.1
41 */
42 public class ElevationDetector extends AbstractTopocentricDetector<ElevationDetector> {
43
44 /** Elevation mask used for calculations, if defined. */
45 private final ElevationMask elevationMask;
46
47 /** Minimum elevation value used if mask is not defined. */
48 private final double minElevation;
49
50 /** Atmospheric Model used for calculations, if defined. */
51 private final AtmosphericRefractionModel refractionModel;
52
53 /**
54 * Creates an instance of Elevation detector based on passed in topocentric frame
55 * and the minimum elevation angle.
56 * <p>
57 * uses default values for maximal checking interval ({@link #DEFAULT_MAX_CHECK})
58 * and convergence threshold ({@link #DEFAULT_THRESHOLD}).</p>
59 * @param topo reference to a topocentric model
60 * @see #withConstantElevation(double)
61 * @see #withElevationMask(ElevationMask)
62 * @see #withRefraction(AtmosphericRefractionModel)
63 */
64 public ElevationDetector(final TopocentricFrame topo) {
65 this(DEFAULT_MAX_CHECK, DEFAULT_THRESHOLD, topo);
66 }
67
68 /**
69 * Creates an instance of Elevation detector based on passed in topocentric frame
70 * and overrides of default maximal checking interval and convergence threshold values.
71 * @param maxCheck maximum checking interval (s)
72 * @param threshold maximum convergence threshold (s)
73 * @param topo reference to a topocentric model
74 * @see #withConstantElevation(double)
75 * @see #withElevationMask(ElevationMask)
76 * @see #withRefraction(AtmosphericRefractionModel)
77 */
78 public ElevationDetector(final double maxCheck, final double threshold,
79 final TopocentricFrame topo) {
80 this(AdaptableInterval.of(maxCheck), threshold, topo);
81 }
82
83 /**
84 * Creates an instance of Elevation detector based on passed in topocentric frame
85 * and overrides of default maximal checking interval and convergence threshold values.
86 * @param maxCheck maximum checking adaptable interval
87 * @param threshold maximum convergence threshold (s)
88 * @param topo reference to a topocentric model
89 * @see org.orekit.propagation.events.intervals.ElevationDetectionAdaptableIntervalFactory
90 * @see #withConstantElevation(double)
91 * @see #withElevationMask(ElevationMask)
92 * @see #withRefraction(AtmosphericRefractionModel)
93 * @since 12.1
94 */
95 public ElevationDetector(final AdaptableInterval maxCheck, final double threshold,
96 final TopocentricFrame topo) {
97 this(new EventDetectionSettings(maxCheck, threshold, DEFAULT_MAX_ITER), new StopOnDecreasing(),
98 0.0, null, null, topo);
99 }
100
101 /** Protected constructor with full parameters.
102 * <p>
103 * This constructor is not public as users are expected to use the builder
104 * API with the various {@code withXxx()} methods to set up the instance
105 * in a readable manner without using a huge amount of parameters.
106 * </p>
107 * @param detectionSettings event detection settings
108 * @param handler event handler to call at event occurrences
109 * @param minElevation minimum elevation in radians (rad)
110 * @param mask reference to elevation mask
111 * @param refractionModel reference to refraction model
112 * @param topo reference to a topocentric model
113 * @since 13.0
114 */
115 protected ElevationDetector(final EventDetectionSettings detectionSettings, final EventHandler handler,
116 final double minElevation, final ElevationMask mask,
117 final AtmosphericRefractionModel refractionModel,
118 final TopocentricFrame topo) {
119 super(detectionSettings, handler, topo);
120 this.minElevation = minElevation;
121 this.elevationMask = mask;
122 this.refractionModel = refractionModel;
123 }
124
125 /** {@inheritDoc} */
126 @Override
127 protected ElevationDetector create(final EventDetectionSettings detectionSettings, final EventHandler newHandler) {
128 return new ElevationDetector(detectionSettings, newHandler,
129 minElevation, elevationMask, refractionModel, getTopocentricFrame());
130 }
131
132 /**
133 * Returns the currently configured elevation mask.
134 * @return elevation mask
135 * (null if instance has been configured with {@link #withConstantElevation(double)}
136 * @see #withElevationMask(ElevationMask)
137 */
138 public ElevationMask getElevationMask() {
139 return this.elevationMask;
140 }
141
142 /**
143 * Returns the currently configured minimum valid elevation value.
144 * @return minimum elevation value
145 * ({@code Double.NaN} if instance has been configured with {@link #withElevationMask(ElevationMask)}
146 * @see #withConstantElevation(double)
147 */
148 public double getMinElevation() {
149 return this.minElevation;
150 }
151
152 /**
153 * Returns the currently configured refraction model.
154 * @return refraction model
155 * @see #withRefraction(AtmosphericRefractionModel)
156 */
157 public AtmosphericRefractionModel getRefractionModel() {
158 return this.refractionModel;
159 }
160
161 /** Compute the value of the switching function.
162 * This function measures the difference between the current elevation
163 * (and azimuth if necessary) and the reference mask or minimum value.
164 * @param s the current state information: date, kinematics, attitude
165 * @return value of the switching function
166 */
167 @Override
168 public double g(final SpacecraftState s) {
169
170 final TrackingCoordinates tc = getTopocentricFrame().getTrackingCoordinates(s.getPosition(), s.getFrame(), s.getDate());
171
172 final double calculatedElevation;
173 if (refractionModel != null) {
174 calculatedElevation = tc.getElevation() + refractionModel.getRefraction(tc.getElevation());
175 } else {
176 calculatedElevation = tc.getElevation();
177 }
178
179 if (elevationMask != null) {
180 return calculatedElevation - elevationMask.getElevation(tc.getAzimuth());
181 } else {
182 return calculatedElevation - minElevation;
183 }
184
185 }
186
187 /**
188 * Setup the minimum elevation for detection.
189 * <p>
190 * This will override an elevation mask if it has been configured as such previously.
191 * </p>
192 * @param newMinElevation minimum elevation for visibility in radians (rad)
193 * @return a new detector with updated configuration (the instance is not changed)
194 * @see #getMinElevation()
195 * @since 6.1
196 */
197 public ElevationDetector withConstantElevation(final double newMinElevation) {
198 return new ElevationDetector(getDetectionSettings(), getHandler(),
199 newMinElevation, null, refractionModel, getTopocentricFrame());
200 }
201
202 /**
203 * Setup the elevation mask for detection using the passed in mask object.
204 * @param newElevationMask elevation mask to use for the computation
205 * @return a new detector with updated configuration (the instance is not changed)
206 * @since 6.1
207 * @see #getElevationMask()
208 */
209 public ElevationDetector withElevationMask(final ElevationMask newElevationMask) {
210 return new ElevationDetector(getDetectionSettings(), getHandler(),
211 Double.NaN, newElevationMask, refractionModel, getTopocentricFrame());
212 }
213
214 /**
215 * Setup the elevation detector to use an atmospheric refraction model in its
216 * calculations.
217 * <p>
218 * To disable the refraction when copying an existing elevation
219 * detector, call this method with a null argument.
220 * </p>
221 * @param newRefractionModel refraction model to use for the computation
222 * @return a new detector with updated configuration (the instance is not changed)
223 * @since 6.1
224 * @see #getRefractionModel()
225 */
226 public ElevationDetector withRefraction(final AtmosphericRefractionModel newRefractionModel) {
227 return new ElevationDetector(getDetectionSettings(), getHandler(),
228 minElevation, elevationMask, newRefractionModel, getTopocentricFrame());
229 }
230
231 }