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