1 /* Copyright 2023-2025 Alberto Ferrero
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 * Alberto Ferrero 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.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.util.FastMath;
22 import org.orekit.bodies.FieldGeodeticPoint;
23 import org.orekit.bodies.OneAxisEllipsoid;
24 import org.orekit.propagation.FieldSpacecraftState;
25 import org.orekit.propagation.events.handlers.FieldEventHandler;
26 import org.orekit.propagation.events.handlers.FieldStopOnIncreasing;
27 import org.orekit.propagation.events.intervals.FieldAdaptableInterval;
28
29
30 /** Detector for geographic latitude crossing.
31 * <p>This detector identifies when a spacecraft crosses a fixed
32 * latitude range with respect to a central body.</p>
33 * @author Alberto Ferrero
34 * @since 12.0
35 * @param <T> type of the field elements
36 */
37 public class FieldLatitudeRangeCrossingDetector <T extends CalculusFieldElement<T>>
38 extends FieldAbstractDetector<FieldLatitudeRangeCrossingDetector<T>, T> {
39
40 /**
41 * Body on which the latitude is defined.
42 */
43 private final OneAxisEllipsoid body;
44
45 /**
46 * Fixed latitude to be crossed, lower boundary in radians.
47 */
48 private final double fromLatitude;
49
50 /**
51 * Fixed latitude to be crossed, upper boundary in radians.
52 */
53 private final double toLatitude;
54
55 /**
56 * Sign, to get reversed inclusion latitude range (lower > upper).
57 */
58 private final double sign;
59
60 /**
61 * Build a new detector.
62 * <p>The new instance uses default values for maximal checking interval
63 * ({@link #DEFAULT_MAX_CHECK}) and convergence threshold ({@link
64 * #DEFAULT_THRESHOLD}).</p>
65 * @param field the type of numbers to use.
66 * @param body body on which the latitude is defined
67 * @param fromLatitude latitude to be crossed, lower range boundary
68 * @param toLatitude latitude to be crossed, upper range boundary
69 */
70 public FieldLatitudeRangeCrossingDetector(final Field<T> field,
71 final OneAxisEllipsoid body,
72 final double fromLatitude,
73 final double toLatitude) {
74 this(new FieldEventDetectionSettings<>(field, EventDetectionSettings.getDefaultEventDetectionSettings()),
75 new FieldStopOnIncreasing<>(),
76 body,
77 fromLatitude,
78 toLatitude);
79 }
80
81 /**
82 * Build a detector.
83 *
84 * @param maxCheck maximal checking interval (s)
85 * @param threshold convergence threshold (s)
86 * @param body body on which the latitude is defined
87 * @param fromLatitude latitude to be crossed, lower range boundary
88 * @param toLatitude latitude to be crossed, upper range boundary
89 */
90 public FieldLatitudeRangeCrossingDetector(final T maxCheck, final T threshold,
91 final OneAxisEllipsoid body, final double fromLatitude, final double toLatitude) {
92 this(new FieldEventDetectionSettings<>(FieldAdaptableInterval.of(maxCheck.getReal()), threshold, DEFAULT_MAX_ITER),
93 new FieldStopOnIncreasing<>(), body, fromLatitude, toLatitude);
94 }
95
96 /**
97 * Private constructor with full parameters.
98 * <p>
99 * This constructor is private as users are expected to use the builder
100 * API with the various {@code withXxx()} methods to set up the instance
101 * in a readable manner without using a huge amount of parameters.
102 * </p>
103 *
104 * @param detectionSettings event detection settings
105 * @param handler event handler to call at event occurrences
106 * @param body body on which the latitude is defined
107 * @param fromLatitude latitude to be crossed, lower range boundary
108 * @param toLatitude latitude to be crossed, upper range boundary
109 * @since 13.0
110 */
111 protected FieldLatitudeRangeCrossingDetector(final FieldEventDetectionSettings<T> detectionSettings,
112 final FieldEventHandler<T> handler,
113 final OneAxisEllipsoid body,
114 final double fromLatitude,
115 final double toLatitude) {
116 super(detectionSettings, handler);
117 this.body = body;
118 this.fromLatitude = fromLatitude;
119 this.toLatitude = toLatitude;
120 this.sign = FastMath.signum(toLatitude - fromLatitude);
121 }
122
123 /**
124 * {@inheritDoc}
125 */
126 @Override
127 protected FieldLatitudeRangeCrossingDetector<T> create(final FieldEventDetectionSettings<T> detectionSettings,
128 final FieldEventHandler<T> newHandler) {
129 return new FieldLatitudeRangeCrossingDetector<>(detectionSettings, newHandler,
130 body, fromLatitude, toLatitude);
131 }
132
133 /**
134 * Get the body on which the geographic zone is defined.
135 *
136 * @return body on which the geographic zone is defined
137 */
138 public OneAxisEllipsoid getBody() {
139 return body;
140 }
141
142 /**
143 * Get the fixed latitude range to be crossed (radians), lower boundary.
144 *
145 * @return fixed lower boundary latitude range to be crossed (radians)
146 */
147 public double getFromLatitude() {
148 return fromLatitude;
149 }
150
151 /**
152 * Get the fixed latitude range to be crossed (radians), upper boundary.
153 *
154 * @return fixed lower boundary latitude range to be crossed (radians)
155 */
156 public double getToLatitude() {
157 return toLatitude;
158 }
159
160 /**
161 * Compute the value of the detection function.
162 * <p>
163 * The value is positive if the spacecraft latitude is inside the latitude range.
164 * It is positive if the spacecraft is northward to lower boundary range and southward to upper boundary range,
165 * with respect to the fixed latitude range.
166 * </p>
167 *
168 * @param s the current state information: date, kinematics, attitude
169 * @return positive if spacecraft inside the range
170 */
171 public T g(final FieldSpacecraftState<T> s) {
172
173 // convert state to geodetic coordinates
174 final FieldGeodeticPoint<T> gp = body.transform(s.getPVCoordinates().getPosition(),
175 s.getFrame(), s.getDate());
176
177 // point latitude
178 final T latitude = gp.getLatitude();
179
180 // inside or outside latitude range
181 return latitude.subtract(fromLatitude).multiply(latitude.negate().add(toLatitude)).multiply(sign);
182
183 }
184
185 }