'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /** * @copyright 2013 Sonia Keys * @copyright 2016 commenthol * @license MIT * @module globe */ /** * Globe: Chapter 11, The Earth's Globe. * * Globe contains functions concerning the surface of the Earth idealized as * an ellipsoid of revolution. */ /** * Ellipsoid represents an ellipsoid of revolution. */ class Ellipsoid { /** * @param {number} radius - equatorial radius * @param {number} flat - ellipsiod flattening */ constructor (radius, flat) { this.radius = radius; this.flat = flat; } /** A is a common identifier for equatorial radius. */ A () { return this.radius } /** B is a common identifier for polar radius. */ B () { return this.radius * (1 - this.flat) } /** eccentricity of a meridian. */ eccentricity () { return Math.sqrt((2 - this.flat) * this.flat) } /** * parallaxConstants computes parallax constants ρ sin φ′ and ρ cos φ′. * * Arguments are geographic latitude φ in radians and height h * in meters above the ellipsoid. * * @param {number} φ - geographic latitude in radians * @param {number} h - height in meters above the ellipsoid * @return {number[]} [ρ sin φ′, ρ cos φ] parallax constants [ρsφ, ρcφ] */ parallaxConstants (φ, h) { const boa = 1 - this.flat; const su = Math.sin(Math.atan(boa * Math.tan(φ))); const cu = Math.cos(Math.atan(boa * Math.tan(φ))); const s = Math.sin(φ); const c = Math.cos(φ); const hoa = h * 1e-3 / this.radius; // (s, c float) const ρsφ = su * boa + hoa * s; const ρcφ = cu + hoa * c; return [ρsφ, ρcφ] } /** * rho is distance from Earth center to a point on the ellipsoid. * * Result unit is fraction of the equatorial radius. * @param {number} φ - geographic latitude in radians * @returns {number} // TODO */ rho (φ) { // Magic numbers... return 0.9983271 + 0.0016764 * Math.cos(2 * φ) - 0.0000035 * Math.cos(4 * φ) } /** * radiusAtLatitude returns the radius of the circle that is the parallel of * latitude at φ. * * Result unit is Km. * * @param {number} φ * @return {number} radius in km */ radiusAtLatitude (φ) { const s = Math.sin(φ); const c = Math.cos(φ); return this.A() * c / Math.sqrt(1 - (2 - this.flat) * this.flat * s * s) } /** * radiusOfCurvature of meridian at latitude φ. * * Result unit is Km. * * @param {number} φ * @return {number} radius in km */ radiusOfCurvature (φ) { const s = Math.sin(φ); const e2 = (2 - this.flat) * this.flat; return this.A() * (1 - e2) / Math.pow(1 - e2 * s * s, 1.5) } /** * distance is distance between two points measured along the surface * of an ellipsoid. * * Accuracy is much better than that of approxAngularDistance or * approxLinearDistance. * * Result unit is Km. * * @param {Coord} c1 * @param {Coord} c2 * @return {number} radius in km */ distance (c1, c2) { // From AA, ch 11, p 84. const [s2f, c2f] = sincos2((c1.lat + c2.lat) / 2); const [s2g, c2g] = sincos2((c1.lat - c2.lat) / 2); const [s2λ, c2λ] = sincos2((c1.lon - c2.lon) / 2); const s = s2g * c2λ + c2f * s2λ; const c = c2g * c2λ + s2f * s2λ; const ω = Math.atan(Math.sqrt(s / c)); const r = Math.sqrt(s * c) / ω; const d = 2 * ω * this.radius; const h1 = (3 * r - 1) / (2 * c); const h2 = (3 * r + 1) / (2 * s); return d * (1 + this.flat * (h1 * s2f * c2g - h2 * c2f * s2g)) } } /** IAU 1976 values. Radius in Km. */ const Earth76 = new Ellipsoid(6378.14, 1 / 298.257); /** * RotationRate1996_5 is the rotational angular velocity of the Earth * with respect to the stars at the epoch 1996.5. * * Unit is radian/second. */ const RotationRate1996_5 = 7.292114992e-5; // eslint-disable-line camelcase /** * oneDegreeOfLongitude returns the length of one degree of longitude. * * Argument `rp` is the radius in Km of a circle that is a parallel of latitude * (as returned by Ellipsoid.radiusAtLatitude.) * Result is distance in Km along one degree of the circle. * * @param {number} rp * @return {number} distance in Km */ function oneDegreeOfLongitude (rp) { return rp * Math.PI / 180 } /** * oneDegreeOfLatitude returns the length of one degree of latitude. * * Argument `rm` is the radius in Km of curvature along a meridian. * (as returned by Ellipsoid.radiusOfCurvature.) * Result is distance in Km along one degree of the meridian. * * @param {number} rm * @return {number} distance in Km */ function oneDegreeOfLatitude (rm) { return rm * Math.PI / 180 } /** * geocentricLatitudeDifference returns geographic latitude - geocentric * latitude (φ - φ′) with given geographic latitude (φ). * * Units are radians. * @param {number} φ * @returns {number} difference in Deg */ function geocentricLatitudeDifference (φ) { // This appears to be an approximation with hard coded magic numbers. // No explanation is given in the text. The ellipsoid is not specified. // Perhaps the approximation works well enough for all ellipsoids? return (692.73 * Math.sin(2 * φ) - 1.16 * Math.sin(4 * φ)) * Math.PI / (180 * 3600) } /** * Coord represents geographic coordinates on the Earth. * * Longitude is measured positively westward from the Greenwich meridian. */ class Coord { /** * @param {number} lat - latitude (φ) in radians * @param {number} lon - longitude (ψ, or L) in radians (measured positively westward) */ constructor (lat = 0, lon = 0) { this.lat = lat; this.lon = lon; } } /** * approxAngularDistance returns the cosine of the angle between two points. * * The accuracy deteriorates at small angles. * * @param {Coord} p1 - Point 1 * @param {Coord} p2 - Point 2 * @returns {number} cosine `cos` of the angle between two points. * Use `d = Math.acos(cos)` to obtain geocentric angular distance in radians */ function approxAngularDistance (p1, p2) { const s1 = Math.sin(p1.lat); const c1 = Math.cos(p1.lat); const s2 = Math.sin(p2.lat); const c2 = Math.cos(p2.lat); return s1 * s2 + c1 * c2 * Math.cos(p1.lon - p2.lon) } /** * approxLinearDistance computes a distance across the surface of the Earth. * * Approximating the Earth as a sphere, the function takes a geocentric angular * distance in radians and returns the corresponding linear distance in Km. * * @param {number} d - geocentric angular distance in radians * @returns linear distance in Km */ function approxLinearDistance (d) { return 6371 * d } /** * @private */ function sincos2 (x) { const s = Math.sin(x); const c = Math.cos(x); return [s * s, c * c] } var globe = { Ellipsoid, Earth76, // eslint-disable-next-line camelcase RotationRate1996_5, oneDegreeOfLongitude, oneDegreeOfLatitude, geocentricLatitudeDifference, Coord, approxAngularDistance, approxLinearDistance }; exports.Coord = Coord; exports.Earth76 = Earth76; exports.Ellipsoid = Ellipsoid; exports.RotationRate1996_5 = RotationRate1996_5; exports.approxAngularDistance = approxAngularDistance; exports.approxLinearDistance = approxLinearDistance; exports["default"] = globe; exports.geocentricLatitudeDifference = geocentricLatitudeDifference; exports.oneDegreeOfLatitude = oneDegreeOfLatitude; exports.oneDegreeOfLongitude = oneDegreeOfLongitude;