1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.bodies;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
21 import org.hipparchus.geometry.euclidean.twod.FieldVector2D;
22 import org.hipparchus.util.FastMath;
23 import org.hipparchus.util.FieldSinCos;
24 import org.orekit.frames.Frame;
25 import org.orekit.utils.TimeStampedFieldPVCoordinates;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public class FieldEllipse<T extends CalculusFieldElement<T>> {
42
43
44 private static final double ANGULAR_THRESHOLD = 1.0e-12;
45
46
47 private final FieldVector3D<T> center;
48
49
50 private final FieldVector3D<T> u;
51
52
53 private final FieldVector3D<T> v;
54
55
56 private final T a;
57
58
59 private final T b;
60
61
62 private final Frame frame;
63
64
65 private final T a2;
66
67
68 private final T b2;
69
70
71 private final T e2;
72
73
74 private final T g;
75
76
77 private final T g2;
78
79
80 private final T evoluteFactorX;
81
82
83 private final T evoluteFactorY;
84
85
86
87
88
89
90
91
92
93 public FieldEllipse(final FieldVector3D<T> center, final FieldVector3D<T> u,
94 final FieldVector3D<T> v, final T a, final T b,
95 final Frame frame) {
96 this.center = center;
97 this.u = u;
98 this.v = v;
99 this.a = a;
100 this.b = b;
101 this.frame = frame;
102 this.a2 = a.square();
103 this.g = b.divide(a);
104 this.g2 = g.multiply(g);
105 this.e2 = g2.negate().add(1);
106 this.b2 = b.square();
107 this.evoluteFactorX = a2.subtract(b2).divide(a2.square());
108 this.evoluteFactorY = b2.subtract(a2).divide(b2.square());
109 }
110
111
112
113
114 public FieldVector3D<T> getCenter() {
115 return center;
116 }
117
118
119
120
121 public FieldVector3D<T> getU() {
122 return u;
123 }
124
125
126
127
128 public FieldVector3D<T> getV() {
129 return v;
130 }
131
132
133
134
135 public T getA() {
136 return a;
137 }
138
139
140
141
142 public T getB() {
143 return b;
144 }
145
146
147
148
149 public Frame getFrame() {
150 return frame;
151 }
152
153
154
155
156
157 public FieldVector3D<T> pointAt(final T theta) {
158 final FieldSinCos<T> scTheta = FastMath.sinCos(theta);
159 return toSpace(new FieldVector2D<>(a.multiply(scTheta.cos()), b.multiply(scTheta.sin())));
160 }
161
162
163
164
165
166
167 public FieldVector3D<T> toSpace(final FieldVector2D<T> p) {
168 return new FieldVector3D<>(a.getField().getOne(), center, p.getX(), u, p.getY(), v);
169 }
170
171
172
173
174
175
176 public FieldVector2D<T> toPlane(final FieldVector3D<T> p) {
177 final FieldVector3D<T> delta = p.subtract(center);
178 return new FieldVector2D<>(FieldVector3D.dotProduct(delta, u), FieldVector3D.dotProduct(delta, v));
179 }
180
181
182
183
184
185 public FieldVector2D<T> projectToEllipse(final FieldVector2D<T> p) {
186
187 final T x = FastMath.abs(p.getX());
188 final T y = p.getY();
189
190 if (x.getReal() <= ANGULAR_THRESHOLD * FastMath.abs(y.getReal())) {
191
192
193 final T osculatingRadius = a2.divide(b);
194 final T evoluteCuspZ = FastMath.copySign(a.multiply(e2).divide(g), y.negate());
195 final T deltaZ = y.subtract(evoluteCuspZ);
196 final T ratio = osculatingRadius.divide(FastMath.hypot(deltaZ, x));
197 return new FieldVector2D<>(FastMath.copySign(ratio.multiply(x), p.getX()),
198 evoluteCuspZ.add(ratio.multiply(deltaZ)));
199 }
200
201 if (FastMath.abs(y.getReal()) <= ANGULAR_THRESHOLD * x.getReal()) {
202
203
204 final T osculatingRadius = b2.divide(a);
205 final T evoluteCuspR = a.multiply(e2);
206 final T deltaR = x.subtract(evoluteCuspR);
207 if (deltaR.getReal() >= 0) {
208
209
210 final T ratio = osculatingRadius.divide(FastMath.hypot(y, deltaR));
211 return new FieldVector2D<>(FastMath.copySign(evoluteCuspR.add(ratio.multiply(deltaR)), p.getX()),
212 ratio.multiply(y));
213 }
214
215
216
217 final T rEllipse = x.divide(e2);
218 return new FieldVector2D<>(FastMath.copySign(rEllipse, p.getX()),
219 FastMath.copySign(g.multiply(FastMath.sqrt(a2.subtract(rEllipse.multiply(rEllipse)))), y));
220
221 } else {
222
223
224 T omegaX = a.multiply(e2);
225 T omegaY = a.getField().getZero();
226
227 T projectedX = x;
228 T projectedY = y;
229 double deltaX = Double.POSITIVE_INFINITY;
230 double deltaY = Double.POSITIVE_INFINITY;
231 int count = 0;
232 final double threshold = ANGULAR_THRESHOLD * ANGULAR_THRESHOLD * a2.getReal();
233 while ((deltaX * deltaX + deltaY * deltaY) > threshold && count++ < 100) {
234
235
236 final T dx = x.subtract(omegaX);
237 final T dy = y.subtract(omegaY);
238 final T alpha = b2.multiply(dx).multiply(dx).add(a2.multiply(dy).multiply(dy));
239 final T betaPrime = b2.multiply(omegaX).multiply(dx).add(a2.multiply(omegaY).multiply(dy));
240 final T gamma = b2.multiply(omegaX).multiply(omegaX).add(a2.multiply(omegaY).multiply(omegaY)).subtract(a2.multiply(b2));
241 final T deltaPrime = a.linearCombination(betaPrime, betaPrime, alpha.negate(), gamma);
242 final T ratio = (betaPrime.getReal() <= 0) ?
243 FastMath.sqrt(deltaPrime).subtract(betaPrime).divide(alpha) :
244 gamma.negate().divide(FastMath.sqrt(deltaPrime).add(betaPrime));
245 final T previousX = projectedX;
246 final T previousY = projectedY;
247 projectedX = omegaX.add(ratio.multiply(dx));
248 projectedY = omegaY.add(ratio.multiply(dy));
249
250
251 omegaX = evoluteFactorX.multiply(projectedX).multiply(projectedX).multiply(projectedX);
252 omegaY = evoluteFactorY.multiply(projectedY).multiply(projectedY).multiply(projectedY);
253
254
255 deltaX = projectedX.subtract(previousX).getReal();
256 deltaY = projectedY.subtract(previousY).getReal();
257
258 }
259 return new FieldVector2D<>(FastMath.copySign(projectedX, p.getX()), projectedY);
260 }
261 }
262
263
264
265
266
267 public TimeStampedFieldPVCoordinates<T> projectToEllipse(final TimeStampedFieldPVCoordinates<T> pv) {
268
269
270 final FieldVector2D<T>p2D = toPlane(pv.getPosition());
271 final FieldVector2D<T>e2D = projectToEllipse(p2D);
272
273
274 final T fx = a2.negate().multiply(e2D.getY());
275 final T fy = b2.multiply(e2D.getX());
276 final T f2 = fx.square().add(fy.square());
277 final T f = FastMath.sqrt(f2);
278 final FieldVector2D<T>tangent = new FieldVector2D<>(fx.divide(f), fy.divide(f));
279
280
281 final FieldVector2D<T>normal = new FieldVector2D<>(tangent.getY().negate(), tangent.getX());
282
283
284 final T x2 = e2D.getX().multiply(e2D.getX());
285 final T y2 = e2D.getY().multiply(e2D.getY());
286 final T eX = evoluteFactorX.multiply(x2);
287 final T eY = evoluteFactorY.multiply(y2);
288 final T omegaX = eX.multiply(e2D.getX());
289 final T omegaY = eY.multiply(e2D.getY());
290
291
292 final T rho = FastMath.hypot(e2D.getX().subtract(omegaX), e2D.getY().subtract(omegaY));
293 final T d = FastMath.hypot(p2D.getX().subtract(omegaX), p2D.getY().subtract(omegaY));
294 final T projectionRatio = rho.divide(d);
295
296
297 final FieldVector2D<T>pDot2D = new FieldVector2D<>(FieldVector3D.dotProduct(pv.getVelocity(), u),
298 FieldVector3D.dotProduct(pv.getVelocity(), v));
299 final T pDotTangent = pDot2D.dotProduct(tangent);
300 final T pDotNormal = pDot2D.dotProduct(normal);
301 final T eDotTangent = projectionRatio.multiply(pDotTangent);
302 final FieldVector2D<T>eDot2D = new FieldVector2D<>(eDotTangent, tangent);
303 final FieldVector2D<T>tangentDot = new FieldVector2D<>(a2.multiply(b2).
304 multiply(e2D.getX().multiply(eDot2D.getY()).
305 subtract(e2D.getY().multiply(eDot2D.getX()))).
306 divide(f2),
307 normal);
308
309
310 final T omegaXDot = eX.multiply(eDotTangent).multiply(tangent.getX()).multiply(3);
311 final T omegaYDot = eY.multiply(eDotTangent).multiply(tangent.getY()).multiply(3);
312
313
314 final T voz = omegaXDot.multiply(tangent.getY()).subtract(omegaYDot.multiply(tangent.getX()));
315 final T vsz = pDotNormal.negate();
316 final T projectionRatioDot = rho.subtract(d).multiply(voz).subtract(rho.multiply(vsz)).divide(d.multiply(d));
317
318
319 final FieldVector2D<T>pDotDot2D = new FieldVector2D<>(FieldVector3D.dotProduct(pv.getAcceleration(), u),
320 FieldVector3D.dotProduct(pv.getAcceleration(), v));
321 final T pDotDotTangent = pDotDot2D.dotProduct(tangent);
322 final T pDotTangentDot = pDot2D.dotProduct(tangentDot);
323 final T eDotDotTangent = projectionRatio.multiply(pDotDotTangent.add(pDotTangentDot)).
324 add(projectionRatioDot.multiply(pDotTangent));
325 final FieldVector2D<T>eDotDot2D = new FieldVector2D<>(eDotDotTangent, tangent, eDotTangent, tangentDot);
326
327
328 final FieldVector3D<T> e3D = toSpace(e2D);
329 final FieldVector3D<T> eDot3D = new FieldVector3D<>(eDot2D.getX(), u, eDot2D.getY(), v);
330 final FieldVector3D<T> eDotDot3D = new FieldVector3D<>(eDotDot2D.getX(), u, eDotDot2D.getY(), v);
331
332 return new TimeStampedFieldPVCoordinates<>(pv.getDate(), e3D, eDot3D, eDotDot3D);
333
334 }
335
336
337
338
339
340 public FieldVector2D<T> getCenterOfCurvature(final FieldVector2D<T> point) {
341 final FieldVector2D<T>projected = projectToEllipse(point);
342 return new FieldVector2D<>(evoluteFactorX.multiply(projected.getX()).multiply(projected.getX()).multiply(projected.getX()),
343 evoluteFactorY.multiply(projected.getY()).multiply(projected.getY()).multiply(projected.getY()));
344 }
345
346 }