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