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