1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.ionosphere.nequick;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.util.FastMath;
21 import org.hipparchus.util.FieldSinCos;
22 import org.orekit.bodies.FieldGeodeticPoint;
23
24
25
26
27
28
29 class FieldRay<T extends CalculusFieldElement<T>> {
30
31
32 private static final double THRESHOLD = 1.0e-10;
33
34
35
36
37 private final T recH;
38
39
40
41
42 private final T satH;
43
44
45 private final T s1;
46
47
48 private final T s2;
49
50
51 private final T rp;
52
53
54 private final T latP;
55
56
57 private final T lonP;
58
59
60 private final FieldSinCos<T> scLatP;
61
62
63 private final T sinAzP;
64
65
66 private final T cosAzP;
67
68
69
70
71
72
73
74 FieldRay(final FieldGeodeticPoint<T> recP, final FieldGeodeticPoint<T> satP) {
75
76
77 this.recH = recP.getAltitude();
78 this.satH = satP.getAltitude();
79 final T r1 = recH.add(NeQuickModel.RE);
80 final T r2 = satH.add(NeQuickModel.RE);
81
82
83 final T pi = r1.getPi();
84 final T lat1 = recP.getLatitude();
85 final T lat2 = satP.getLatitude();
86 final T lon1 = recP.getLongitude();
87 final T lon2 = satP.getLongitude();
88 final FieldSinCos<T> scLatSat = FastMath.sinCos(lat2);
89 final FieldSinCos<T> scLatRec = FastMath.sinCos(lat1);
90 final FieldSinCos<T> scLon21 = FastMath.sinCos(lon2.subtract(lon1));
91
92
93
94
95
96 final T cosD = FastMath.min(r1.getField().getOne(),
97 scLatRec.sin().multiply(scLatSat.sin()).
98 add(scLatRec.cos().multiply(scLatSat.cos()).multiply(scLon21.cos())));
99 final T sinDSinM = scLatSat.cos().multiply(scLon21.sin());
100 final T sinDCosM = scLatSat.sin().multiply(scLatRec.cos()).subtract(scLatSat.cos().multiply(scLatRec.sin()).multiply(scLon21.cos()));
101 final T sinD = FastMath.sqrt(sinDSinM.multiply(sinDSinM).add(sinDCosM.multiply(sinDCosM)));
102 final T u = r2.multiply(sinD);
103 final T v = r2.multiply(cosD).subtract(r1);
104 final T inv = FastMath.sqrt(u.multiply(u).add(v.multiply(v))).reciprocal();
105 final T sinZ = u.multiply(inv);
106 final T cosZ = v.multiply(inv);
107
108
109 this.rp = r1.multiply(sinZ);
110
111
112 if (FastMath.abs(FastMath.abs(lat1).subtract(pi.multiply(0.5)).getReal()) < THRESHOLD) {
113
114
115 this.latP = FastMath.copySign(FastMath.atan2(u, v), lat1);
116
117
118 this.lonP = lon2.add(pi);
119
120 } else if (FastMath.abs(sinZ.getReal()) < THRESHOLD) {
121
122
123 this.latP = recP.getLatitude();
124 this.lonP = recP.getLongitude();
125
126 } else {
127
128
129 final T sinAz = FastMath.sin(lon2.subtract(lon1)).multiply(scLatSat.cos()).divide(sinD);
130 final T cosAz = scLatSat.sin().subtract(cosD.multiply(scLatRec.sin())).
131 divide(sinD.multiply(scLatRec.cos()));
132 final T sinLatP = scLatRec.sin().multiply(sinZ).
133 subtract(scLatRec.cos().multiply(cosZ).multiply(cosAz));
134 final T cosLatP = FastMath.sqrt(sinLatP.multiply(sinLatP).negate().add(1.0));
135 this.latP = FastMath.atan2(sinLatP, cosLatP);
136
137
138 if (cosLatP.getReal() < THRESHOLD) {
139 this.lonP = cosLatP.getField().getZero();
140 } else {
141 final T sinLonP = sinAz.negate().multiply(cosZ).divide(cosLatP);
142 final T cosLonP = sinZ.subtract(scLatRec.sin().multiply(sinLatP)).
143 divide(scLatRec.cos().multiply(cosLatP));
144 this.lonP = FastMath.atan2(sinLonP, cosLonP).add(lon1);
145 }
146
147 }
148
149
150 this.scLatP = FastMath.sinCos(latP);
151
152 if (FastMath.abs(FastMath.abs(latP).subtract(pi.multiply(0.5)).getReal()) < THRESHOLD || FastMath.abs(
153 sinZ.getReal()) < THRESHOLD) {
154
155 this.sinAzP = pi.getField().getZero();
156 this.cosAzP = FastMath.copySign(pi.getField().getOne(), latP).negate();
157 } else {
158 final FieldSinCos<T> scLon = FastMath.sinCos(lon2.subtract(lonP));
159
160 final FieldSinCos<T> scPsi = FastMath.sinCos(greatCircleAngle(scLatSat, scLon));
161
162 this.sinAzP = scLatSat.cos().multiply(scLon.sin()).divide(scPsi.sin());
163 this.cosAzP = scLatSat.sin().subtract(scLatP.sin().multiply(scPsi.cos())).
164 divide(scLatP.cos().multiply(scPsi.sin()));
165 }
166
167
168 this.s1 = FastMath.sqrt(r1.multiply(r1).subtract(rp.multiply(rp)));
169 this.s2 = FastMath.sqrt(r2.multiply(r2).subtract(rp.multiply(rp)));
170 }
171
172
173
174
175
176
177 public T getRecH() {
178 return recH;
179 }
180
181
182
183
184
185
186 public T getSatH() {
187 return satH;
188 }
189
190
191
192
193
194
195 public T getS1() {
196 return s1;
197 }
198
199
200
201
202
203
204 public T getS2() {
205 return s2;
206 }
207
208
209
210
211
212
213 public T getRadius() {
214 return rp;
215 }
216
217
218
219
220
221
222 public T getLatitude() {
223 return latP;
224 }
225
226
227
228
229
230
231
232 public FieldSinCos<T> getScLat() {
233 return scLatP;
234 }
235
236
237
238
239
240
241 public T getLongitude() {
242 return lonP;
243 }
244
245
246
247
248
249
250 public T getSineAz() {
251 return sinAzP;
252 }
253
254
255
256
257
258
259 public T getCosineAz() {
260 return cosAzP;
261 }
262
263
264
265
266
267
268
269
270
271
272
273 private T greatCircleAngle(final FieldSinCos<T> scLat, final FieldSinCos<T> scLon) {
274 if (FastMath.abs(FastMath.abs(latP).getReal() - 0.5 * FastMath.PI) < THRESHOLD) {
275 return FastMath.abs(FastMath.asin(scLat.sin()).subtract(latP));
276 } else {
277 final T cosPhi = scLatP.sin().multiply(scLat.sin()).
278 add(scLatP.cos().multiply(scLat.cos()).multiply(scLon.cos()));
279 final T sinPhi = FastMath.sqrt(cosPhi.multiply(cosPhi).negate().add(1.0));
280 return FastMath.atan2(sinPhi, cosPhi);
281 }
282 }
283
284 }