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