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