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.analysis.differentiation.DerivativeStructure;
22 import org.hipparchus.geometry.euclidean.oned.Vector1D;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.hipparchus.geometry.euclidean.threed.Line;
25 import org.hipparchus.geometry.euclidean.threed.Vector3D;
26 import org.hipparchus.geometry.euclidean.twod.Vector2D;
27 import org.hipparchus.util.FastMath;
28 import org.hipparchus.util.MathArrays;
29 import org.orekit.errors.OrekitException;
30 import org.orekit.frames.Frame;
31 import org.orekit.frames.Transform;
32 import org.orekit.time.AbsoluteDate;
33 import org.orekit.utils.PVCoordinates;
34 import org.orekit.utils.TimeStampedPVCoordinates;
35
36
37
38
39
40
41
42
43
44
45
46 public class OneAxisEllipsoid extends Ellipsoid implements BodyShape {
47
48
49 private static final long serialVersionUID = 20130518L;
50
51
52 private final Frame bodyFrame;
53
54
55 private final double ae2;
56
57
58 private final double f;
59
60
61 private final double e2;
62
63
64 private final double g;
65
66
67 private final double g2;
68
69
70 private double angularThreshold;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public OneAxisEllipsoid(final double ae, final double f,
90 final Frame bodyFrame) {
91 super(bodyFrame, ae, ae, ae * (1.0 - f));
92 this.f = f;
93 this.ae2 = ae * ae;
94 this.e2 = f * (2.0 - f);
95 this.g = 1.0 - f;
96 this.g2 = g * g;
97 setAngularThreshold(1.0e-12);
98 this.bodyFrame = bodyFrame;
99 }
100
101
102
103
104
105
106
107
108
109
110 public void setAngularThreshold(final double angularThreshold) {
111 this.angularThreshold = angularThreshold;
112 }
113
114
115
116
117 public double getEquatorialRadius() {
118 return getA();
119 }
120
121
122
123
124 public double getFlattening() {
125 return f;
126 }
127
128
129 public Frame getBodyFrame() {
130 return bodyFrame;
131 }
132
133
134 public GeodeticPoint getIntersectionPoint(final Line line, final Vector3D close,
135 final Frame frame, final AbsoluteDate date)
136 throws OrekitException {
137
138
139 final Transform frameToBodyFrame = frame.getTransformTo(bodyFrame, date);
140 final Line lineInBodyFrame = frameToBodyFrame.transformLine(line);
141 final Vector3D closeInBodyFrame = frameToBodyFrame.transformPosition(close);
142 final double closeAbscissa = lineInBodyFrame.toSubSpace(closeInBodyFrame).getX();
143
144
145 final Vector3D point = lineInBodyFrame.getOrigin();
146 final double x = point.getX();
147 final double y = point.getY();
148 final double z = point.getZ();
149 final double z2 = z * z;
150 final double r2 = x * x + y * y;
151
152 final Vector3D direction = lineInBodyFrame.getDirection();
153 final double dx = direction.getX();
154 final double dy = direction.getY();
155 final double dz = direction.getZ();
156 final double cz2 = dx * dx + dy * dy;
157
158
159
160 final double a = 1.0 - e2 * cz2;
161 final double b = -(g2 * (x * dx + y * dy) + z * dz);
162 final double c = g2 * (r2 - ae2) + z2;
163 final double b2 = b * b;
164 final double ac = a * c;
165 if (b2 < ac) {
166 return null;
167 }
168 final double s = FastMath.sqrt(b2 - ac);
169 final double k1 = (b < 0) ? (b - s) / a : c / (b + s);
170 final double k2 = c / (a * k1);
171
172
173 final double k =
174 (FastMath.abs(k1 - closeAbscissa) < FastMath.abs(k2 - closeAbscissa)) ? k1 : k2;
175 final Vector3D intersection = lineInBodyFrame.toSpace(new Vector1D(k));
176 final double ix = intersection.getX();
177 final double iy = intersection.getY();
178 final double iz = intersection.getZ();
179
180 final double lambda = FastMath.atan2(iy, ix);
181 final double phi = FastMath.atan2(iz, g2 * FastMath.sqrt(ix * ix + iy * iy));
182 return new GeodeticPoint(phi, lambda, 0.0);
183
184 }
185
186
187 public Vector3D transform(final GeodeticPoint point) {
188 final double longitude = point.getLongitude();
189 final double cLambda = FastMath.cos(longitude);
190 final double sLambda = FastMath.sin(longitude);
191 final double latitude = point.getLatitude();
192 final double cPhi = FastMath.cos(latitude);
193 final double sPhi = FastMath.sin(latitude);
194 final double h = point.getAltitude();
195 final double n = getA() / FastMath.sqrt(1.0 - e2 * sPhi * sPhi);
196 final double r = (n + h) * cPhi;
197 return new Vector3D(r * cLambda, r * sLambda, (g2 * n + h) * sPhi);
198 }
199
200
201
202
203
204 public PVCoordinates transform(final FieldGeodeticPoint<DerivativeStructure> point) {
205
206 final DerivativeStructure latitude = point.getLatitude();
207 final DerivativeStructure longitude = point.getLongitude();
208 final DerivativeStructure altitude = point.getAltitude();
209
210 final DerivativeStructure cLambda = longitude.cos();
211 final DerivativeStructure sLambda = longitude.sin();
212 final DerivativeStructure cPhi = latitude.cos();
213 final DerivativeStructure sPhi = latitude.sin();
214 final DerivativeStructure n = sPhi.multiply(sPhi).multiply(e2).subtract(1.0).negate().sqrt().reciprocal().multiply(getA());
215 final DerivativeStructure r = n.add(altitude).multiply(cPhi);
216
217 return new PVCoordinates(new FieldVector3D<DerivativeStructure>(r.multiply(cLambda),
218 r.multiply(sLambda),
219 sPhi.multiply(altitude.add(n.multiply(g2)))));
220 }
221
222
223 public Vector3D projectToGround(final Vector3D point, final AbsoluteDate date, final Frame frame)
224 throws OrekitException {
225
226
227 final Transform toBody = frame.getTransformTo(bodyFrame, date);
228 final Vector3D p = toBody.transformPosition(point);
229 final double z = p.getZ();
230 final double r = FastMath.hypot(p.getX(), p.getY());
231
232
233 final Ellipse meridian = new Ellipse(Vector3D.ZERO,
234 new Vector3D(p.getX() / r, p.getY() / r, 0),
235 Vector3D.PLUS_K,
236 getA(), getC(), bodyFrame);
237
238
239 final Vector3D groundPoint = meridian.toSpace(meridian.projectToEllipse(new Vector2D(r, z)));
240
241
242 return toBody.getInverse().transformPosition(groundPoint);
243
244 }
245
246
247 public TimeStampedPVCoordinates projectToGround(final TimeStampedPVCoordinates pv, final Frame frame)
248 throws OrekitException {
249
250
251 final Transform toBody = frame.getTransformTo(bodyFrame, pv.getDate());
252 final TimeStampedPVCoordinates pvInBodyFrame = toBody.transformPVCoordinates(pv);
253 final Vector3D p = pvInBodyFrame.getPosition();
254 final double r = FastMath.hypot(p.getX(), p.getY());
255
256
257 final Vector3D meridian = new Vector3D(p.getX() / r, p.getY() / r, 0);
258 final Ellipse firstPrincipalCurvature =
259 new Ellipse(Vector3D.ZERO, meridian, Vector3D.PLUS_K, getA(), getC(), bodyFrame);
260
261
262 final TimeStampedPVCoordinates gpFirst = firstPrincipalCurvature.projectToEllipse(pvInBodyFrame);
263 final Vector3D gpP = gpFirst.getPosition();
264 final double gr = MathArrays.linearCombination(gpP.getX(), meridian.getX(),
265 gpP.getY(), meridian.getY());
266 final double gz = gpP.getZ();
267
268
269 final Vector3D east = new Vector3D(-meridian.getY(), meridian.getX(), 0);
270 final Vector3D zenith = new Vector3D(gr * getC() / getA(), meridian, gz * getA() / getC(), Vector3D.PLUS_K).normalize();
271 final Vector3D north = Vector3D.crossProduct(zenith, east);
272
273
274 final Ellipse secondPrincipalCurvature = getPlaneSection(gpP, north);
275 final TimeStampedPVCoordinates gpSecond = secondPrincipalCurvature.projectToEllipse(pvInBodyFrame);
276
277 final Vector3D gpV = gpFirst.getVelocity().add(gpSecond.getVelocity());
278 final Vector3D gpA = gpFirst.getAcceleration().add(gpSecond.getAcceleration());
279
280
281 final TimeStampedPVCoordinates groundPV =
282 new TimeStampedPVCoordinates(pv.getDate(), gpP, gpV, gpA);
283
284
285 return toBody.getInverse().transformPVCoordinates(groundPV);
286
287 }
288
289
290 public GeodeticPoint transform(final Vector3D point, final Frame frame, final AbsoluteDate date)
291 throws OrekitException {
292
293
294 final Vector3D pointInBodyFrame = frame.getTransformTo(bodyFrame, date).transformPosition(point);
295 final double r2 = pointInBodyFrame.getX() * pointInBodyFrame.getX() +
296 pointInBodyFrame.getY() * pointInBodyFrame.getY();
297 final double r = FastMath.sqrt(r2);
298 final double z = pointInBodyFrame.getZ();
299
300
301 final Ellipse meridian = new Ellipse(Vector3D.ZERO,
302 new Vector3D(pointInBodyFrame.getX() / r, pointInBodyFrame.getY() / r, 0),
303 Vector3D.PLUS_K,
304 getA(), getC(), bodyFrame);
305
306
307 final Vector2D ellipsePoint = meridian.projectToEllipse(new Vector2D(r, z));
308
309
310 final double dr = r - ellipsePoint.getX();
311 final double dz = z - ellipsePoint.getY();
312 final double insideIfNegative = g2 * (r2 - ae2) + z * z;
313
314 return new GeodeticPoint(FastMath.atan2(ellipsePoint.getY(), g2 * ellipsePoint.getX()),
315 FastMath.atan2(pointInBodyFrame.getY(), pointInBodyFrame.getX()),
316 FastMath.copySign(FastMath.hypot(dr, dz), insideIfNegative));
317
318 }
319
320
321
322
323
324
325
326
327
328 public FieldGeodeticPoint<DerivativeStructure> transform(final PVCoordinates point,
329 final Frame frame, final AbsoluteDate date)
330 throws OrekitException {
331
332
333 final Transform toBody = frame.getTransformTo(bodyFrame, date);
334 final PVCoordinates pointInBodyFrame = toBody.transformPVCoordinates(point);
335 final FieldVector3D<DerivativeStructure> p = pointInBodyFrame.toDerivativeStructureVector(2);
336 final DerivativeStructure pr2 = p.getX().multiply(p.getX()).add(p.getY().multiply(p.getY()));
337 final DerivativeStructure pr = pr2.sqrt();
338 final DerivativeStructure pz = p.getZ();
339
340
341 final TimeStampedPVCoordinates groundPoint = projectToGround(new TimeStampedPVCoordinates(date, pointInBodyFrame),
342 bodyFrame);
343 final FieldVector3D<DerivativeStructure> gp = groundPoint.toDerivativeStructureVector(2);
344 final DerivativeStructure gpr2 = gp.getX().multiply(gp.getX()).add(gp.getY().multiply(gp.getY()));
345 final DerivativeStructure gpr = gpr2.sqrt();
346 final DerivativeStructure gpz = gp.getZ();
347
348
349 final DerivativeStructure dr = pr.subtract(gpr);
350 final DerivativeStructure dz = pz.subtract(gpz);
351 final double insideIfNegative = g2 * (pr2.getReal() - ae2) + pz.getReal() * pz.getReal();
352
353 return new FieldGeodeticPoint<DerivativeStructure>(DerivativeStructure.atan2(gpz, gpr.multiply(g2)),
354 DerivativeStructure.atan2(p.getY(), p.getX()),
355 DerivativeStructure.hypot(dr, dz).copySign(insideIfNegative));
356 }
357
358
359
360
361
362
363
364
365 private Object writeReplace() {
366 return new DataTransferObject(getA(), f, bodyFrame, angularThreshold);
367 }
368
369
370 private static class DataTransferObject implements Serializable {
371
372
373 private static final long serialVersionUID = 20130518L;
374
375
376 private final double ae;
377
378
379 private final double f;
380
381
382 private final Frame bodyFrame;
383
384
385 private final double angularThreshold;
386
387
388
389
390
391
392
393 DataTransferObject(final double ae, final double f,
394 final Frame bodyFrame, final double angularThreshold) {
395 this.ae = ae;
396 this.f = f;
397 this.bodyFrame = bodyFrame;
398 this.angularThreshold = angularThreshold;
399 }
400
401
402
403
404
405 private Object readResolve() {
406 final OneAxisEllipsoid ellipsoid = new OneAxisEllipsoid(ae, f, bodyFrame);
407 ellipsoid.setAngularThreshold(angularThreshold);
408 return ellipsoid;
409 }
410
411 }
412
413 }