1 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
2 |
|
3 | /**
|
4 | * @copyright 2013 Sonia Keys
|
5 | * @copyright 2016 commenthol
|
6 | * @license MIT
|
7 | * @module globe
|
8 | */
|
9 | /**
|
10 | * Globe: Chapter 11, The Earth's Globe.
|
11 | *
|
12 | * Globe contains functions concerning the surface of the Earth idealized as
|
13 | * an ellipsoid of revolution.
|
14 | */
|
15 |
|
16 | /**
|
17 | * Ellipsoid represents an ellipsoid of revolution. */
|
18 | export var Ellipsoid = function () {
|
19 | /**
|
20 | * @param {number} radius - equatorial radius
|
21 | * @param {number} flat - ellipsiod flattening
|
22 | */
|
23 | function Ellipsoid(radius, flat) {
|
24 | _classCallCheck(this, Ellipsoid);
|
25 |
|
26 | this.radius = radius;
|
27 | this.flat = flat;
|
28 | }
|
29 |
|
30 | /** A is a common identifier for equatorial radius. */
|
31 |
|
32 |
|
33 | Ellipsoid.prototype.A = function A() {
|
34 | return this.radius;
|
35 | };
|
36 |
|
37 | /** B is a common identifier for polar radius. */
|
38 |
|
39 |
|
40 | Ellipsoid.prototype.B = function B() {
|
41 | return this.radius * (1 - this.flat);
|
42 | };
|
43 |
|
44 | /** eccentricity of a meridian. */
|
45 |
|
46 |
|
47 | Ellipsoid.prototype.eccentricity = function eccentricity() {
|
48 | return Math.sqrt((2 - this.flat) * this.flat);
|
49 | };
|
50 |
|
51 | /**
|
52 | * parallaxConstants computes parallax constants ρ sin φ′ and ρ cos φ′.
|
53 | *
|
54 | * Arguments are geographic latitude φ in radians and height h
|
55 | * in meters above the ellipsoid.
|
56 | *
|
57 | * @param {number} φ - geographic latitude in radians
|
58 | * @param {number} h - height in meters above the ellipsoid
|
59 | * @return {number[]} [ρ sin φ′, ρ cos φ] parallax constants
|
60 | */
|
61 |
|
62 |
|
63 | Ellipsoid.prototype.parallaxConstants = function parallaxConstants(φ, h) {
|
64 | var boa = 1 - this.flat;
|
65 | var su = Math.sin(Math.atan(boa * Math.tan(φ)));
|
66 | var cu = Math.cos(Math.atan(boa * Math.tan(φ)));
|
67 | var s = Math.sin(φ);
|
68 | var c = Math.cos(φ);
|
69 | var hoa = h * 1e-3 / this.radius;
|
70 | // (s, c float)
|
71 | return [su * boa + hoa * s, cu + hoa * c];
|
72 | };
|
73 |
|
74 | /**
|
75 | * rho is distance from Earth center to a point on the ellipsoid.
|
76 | *
|
77 | * Result unit is fraction of the equatorial radius.
|
78 | * @param {number} φ - geographic latitude in radians
|
79 | * @returns {number} // TODO
|
80 | */
|
81 |
|
82 |
|
83 | Ellipsoid.prototype.rho = function rho(φ) {
|
84 | // Magic numbers...
|
85 | return 0.9983271 + 0.0016764 * Math.cos(2 * φ) - 0.0000035 * Math.cos(4 * φ);
|
86 | };
|
87 |
|
88 | /**
|
89 | * radiusAtLatitude returns the radius of the circle that is the parallel of
|
90 | * latitude at φ.
|
91 | *
|
92 | * Result unit is Km.
|
93 | *
|
94 | * @param {number} φ
|
95 | * @return {number} radius in km
|
96 | */
|
97 |
|
98 |
|
99 | Ellipsoid.prototype.radiusAtLatitude = function radiusAtLatitude(φ) {
|
100 | var s = Math.sin(φ);
|
101 | var c = Math.cos(φ);
|
102 | return this.A() * c / Math.sqrt(1 - (2 - this.flat) * this.flat * s * s);
|
103 | };
|
104 |
|
105 | /**
|
106 | * radiusOfCurvature of meridian at latitude φ.
|
107 | *
|
108 | * Result unit is Km.
|
109 | *
|
110 | * @param {number} φ
|
111 | * @return {number} radius in km
|
112 | */
|
113 |
|
114 |
|
115 | Ellipsoid.prototype.radiusOfCurvature = function radiusOfCurvature(φ) {
|
116 | var s = Math.sin(φ);
|
117 | var e2 = (2 - this.flat) * this.flat;
|
118 | return this.A() * (1 - e2) / Math.pow(1 - e2 * s * s, 1.5);
|
119 | };
|
120 |
|
121 | /**
|
122 | * distance is distance between two points measured along the surface
|
123 | * of an ellipsoid.
|
124 | *
|
125 | * Accuracy is much better than that of approxAngularDistance or
|
126 | * approxLinearDistance.
|
127 | *
|
128 | * Result unit is Km.
|
129 | *
|
130 | * @param {Coords} c1
|
131 | * @param {Coords} c2
|
132 | * @return {number} radius in km
|
133 | */
|
134 |
|
135 |
|
136 | Ellipsoid.prototype.distance = function distance(c1, c2) {
|
137 | // From AA, ch 11, p 84.
|
138 | var _sincos = sincos2((c1.lat + c2.lat) / 2),
|
139 | s2f = _sincos[0],
|
140 | c2f = _sincos[1];
|
141 |
|
142 | var _sincos2 = sincos2((c1.lat - c2.lat) / 2),
|
143 | s2g = _sincos2[0],
|
144 | c2g = _sincos2[1];
|
145 |
|
146 | var _sincos3 = sincos2((c1.lon - c2.lon) / 2),
|
147 | s2λ = _sincos3[0],
|
148 | c2λ = _sincos3[1];
|
149 |
|
150 | var s = s2g * c2λ + c2f * s2λ;
|
151 | var c = c2g * c2λ + s2f * s2λ;
|
152 | var ω = Math.atan(Math.sqrt(s / c));
|
153 | var r = Math.sqrt(s * c) / ω;
|
154 | var d = 2 * ω * this.radius;
|
155 | var h1 = (3 * r - 1) / (2 * c);
|
156 | var h2 = (3 * r + 1) / (2 * s);
|
157 | return d * (1 + this.flat * (h1 * s2f * c2g - h2 * c2f * s2g));
|
158 | };
|
159 |
|
160 | return Ellipsoid;
|
161 | }();
|
162 |
|
163 | /** IAU 1976 values. Radius in Km. */
|
164 | export var Earth76 = new Ellipsoid(6378.14, 1 / 298.257);
|
165 |
|
166 | /**
|
167 | * RotationRate1996_5 is the rotational angular velocity of the Earth
|
168 | * with respect to the stars at the epoch 1996.5.
|
169 | *
|
170 | * Unit is radian/second.
|
171 | */
|
172 | export var RotationRate1996_5 = 7.292114992e-5; // eslint-disable-line camelcase
|
173 |
|
174 | /**
|
175 | * oneDegreeOfLongitude returns the length of one degree of longitude.
|
176 | *
|
177 | * Argument `rp` is the radius in Km of a circle that is a parallel of latitude
|
178 | * (as returned by Ellipsoid.radiusAtLatitude.)
|
179 | * Result is distance in Km along one degree of the circle.
|
180 | *
|
181 | * @param {number} rp
|
182 | * @return {number} distance in Km
|
183 | */
|
184 | export function oneDegreeOfLongitude(rp) {
|
185 | return rp * Math.PI / 180;
|
186 | }
|
187 |
|
188 | /**
|
189 | * oneDegreeOfLatitude returns the length of one degree of latitude.
|
190 | *
|
191 | * Argument `rm` is the radius in Km of curvature along a meridian.
|
192 | * (as returned by Ellipsoid.radiusOfCurvature.)
|
193 | * Result is distance in Km along one degree of the meridian.
|
194 | *
|
195 | * @param {number} rm
|
196 | * @return {number} distance in Km
|
197 | */
|
198 | export function oneDegreeOfLatitude(rm) {
|
199 | return rm * Math.PI / 180;
|
200 | }
|
201 |
|
202 | /**
|
203 | * geocentricLatitudeDifference returns geographic latitude - geocentric
|
204 | * latitude (φ - φ′) with given geographic latitude (φ).
|
205 | *
|
206 | * Units are radians.
|
207 | * @param {number} φ
|
208 | * @returns {number} difference in Deg
|
209 | */
|
210 | export function geocentricLatitudeDifference(φ) {
|
211 | // This appears to be an approximation with hard coded magic numbers.
|
212 | // No explanation is given in the text. The ellipsoid is not specified.
|
213 | // Perhaps the approximation works well enough for all ellipsoids?
|
214 | return (692.73 * Math.sin(2 * φ) - 1.16 * Math.sin(4 * φ)) * Math.PI / (180 * 3600);
|
215 | }
|
216 |
|
217 | /**
|
218 | * Coord represents geographic coordinates on the Earth.
|
219 | *
|
220 | * Longitude is measured positively westward from the Greenwich meridian.
|
221 | */
|
222 | export var Coord =
|
223 | /**
|
224 | * @param {number} lat - latitude (φ) in radians
|
225 | * @param {number} lon - longitude (ψ, or L) in radians (measured positively westward)
|
226 | */
|
227 | function Coord() {
|
228 | var lat = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
229 | var lon = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
230 |
|
231 | _classCallCheck(this, Coord);
|
232 |
|
233 | this.lat = lat;
|
234 | this.lon = lon;
|
235 | };
|
236 |
|
237 | /**
|
238 | * approxAngularDistance returns the cosine of the angle between two points.
|
239 | *
|
240 | * The accuracy deteriorates at small angles.
|
241 | *
|
242 | * @param {Coord} p1 - Point 1
|
243 | * @param {Coord} p2 - Point 2
|
244 | * @returns {number} cosine `cos` of the angle between two points.
|
245 | * Use `d = Math.acos(cos)` to obtain geocentric angular distance in radians
|
246 | */
|
247 | export function approxAngularDistance(p1, p2) {
|
248 | var s1 = Math.sin(p1.lat);
|
249 | var c1 = Math.cos(p1.lat);
|
250 | var s2 = Math.sin(p2.lat);
|
251 | var c2 = Math.cos(p2.lat);
|
252 | return s1 * s2 + c1 * c2 * Math.cos(p1.lon - p2.lon);
|
253 | }
|
254 |
|
255 | /**
|
256 | * approxLinearDistance computes a distance across the surface of the Earth.
|
257 | *
|
258 | * Approximating the Earth as a sphere, the function takes a geocentric angular
|
259 | * distance in radians and returns the corresponding linear distance in Km.
|
260 | *
|
261 | * @param {number} d - geocentric angular distance in radians
|
262 | * @returns linear distance in Km
|
263 | */
|
264 | export function approxLinearDistance(d) {
|
265 | return 6371 * d;
|
266 | }
|
267 |
|
268 | /**
|
269 | * @private
|
270 | */
|
271 | function sincos2(x) {
|
272 | var s = Math.sin(x);
|
273 | var c = Math.cos(x);
|
274 | return [s * s, c * c];
|
275 | }
|
276 |
|
277 | export default {
|
278 | Ellipsoid: Ellipsoid,
|
279 | Earth76: Earth76,
|
280 | RotationRate1996_5: RotationRate1996_5,
|
281 | oneDegreeOfLongitude: oneDegreeOfLongitude,
|
282 | oneDegreeOfLatitude: oneDegreeOfLatitude,
|
283 | geocentricLatitudeDifference: geocentricLatitudeDifference,
|
284 | Coord: Coord,
|
285 | approxAngularDistance: approxAngularDistance,
|
286 | approxLinearDistance: approxLinearDistance
|
287 | }; |
\ | No newline at end of file |