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.util.FastMath;
20 import org.hipparchus.util.MathUtils;
21
22
23
24
25
26
27 public class LoxodromeArc extends Loxodrome {
28
29
30 private static final double LATITUDE_THRESHOLD = 1e-6;
31
32
33 private static final int MAX_ITER = 50;
34
35
36 private final GeodeticPoint endPoint;
37
38
39 private final double deltaLon;
40
41
42 private double distance = -1;
43
44
45
46
47
48
49 public LoxodromeArc(final GeodeticPoint point, final GeodeticPoint endPoint, final OneAxisEllipsoid body) {
50 this(point, endPoint, body, (point.getAltitude() + endPoint.getAltitude()) / 2.);
51 }
52
53
54
55
56
57
58
59 public LoxodromeArc(final GeodeticPoint point, final GeodeticPoint endPoint, final OneAxisEllipsoid body,
60 final double altitude) {
61 super(point, body.azimuthBetweenPoints(point, endPoint), body, altitude);
62 this.endPoint = endPoint;
63 this.deltaLon = MathUtils.normalizeAngle(endPoint.getLongitude(), point.getLongitude()) -
64 point.getLongitude();
65 }
66
67
68
69
70
71 public GeodeticPoint getFinalPoint() {
72 return this.endPoint;
73 }
74
75
76
77
78
79 public double getDistance() {
80 if (distance >= 0) {
81 return distance;
82 }
83
84
85 final double ptLat = getPoint().getLatitude();
86 final double sinLat = FastMath.sin(ptLat);
87 final double eccSinLatSq = getBody().getEccentricitySquared() * sinLat * sinLat;
88
89
90 final double t1 = 1. - getBody().getEccentricitySquared();
91 final double t2 = 1. - eccSinLatSq;
92 final double t3 = FastMath.sqrt(t2);
93
94 final double semiMajorAxis = getBody().getEquatorialRadius() + getAltitude();
95
96 final double meridianCurve = (semiMajorAxis * t1) / (t2 * t3);
97
98 if (FastMath.abs(endPoint.getLatitude() - ptLat) < LATITUDE_THRESHOLD) {
99 distance = (semiMajorAxis / t3) * FastMath.abs(FastMath.cos(ptLat) * deltaLon);
100 }
101 else {
102 final double eccSq34 = 0.75 * getBody().getEccentricitySquared();
103 final double halfEccSq34 = eccSq34 / 2.;
104 final double t6 = 1. / (1. - eccSq34);
105 final double t7 = t1 * semiMajorAxis / meridianCurve;
106
107 final double t8 = ptLat + t6 *
108 (t7 * (endPoint.getLatitude() - ptLat) + halfEccSq34 * FastMath.sin(ptLat * 2.));
109 final double t9 = halfEccSq34 * t6;
110
111 double guess = 0;
112 double lat = endPoint.getLatitude();
113 for (int i = 0; i < MAX_ITER; i++) {
114 guess = lat;
115 lat = t8 - t9 * FastMath.sin(2. * guess);
116
117 if (FastMath.abs(lat - guess) < LATITUDE_THRESHOLD) {
118 break;
119 }
120 }
121
122 final double azimuth = FastMath.atan2(deltaLon,
123 getBody().geodeticToIsometricLatitude(lat) - getBody().geodeticToIsometricLatitude(ptLat));
124 distance = meridianCurve * FastMath.abs((lat - ptLat) / FastMath.cos(azimuth));
125 }
126
127 return distance;
128 }
129
130
131
132
133
134
135 public GeodeticPoint calculatePointAlongArc(final double fraction) {
136 if (fraction == 0.) {
137 return getPoint();
138 }
139 else if (fraction == 1.) {
140 return getFinalPoint();
141 }
142 else {
143 final double d = getDistance() * fraction;
144 return this.pointAtDistance(d);
145 }
146 }
147 }