Расстояние по дуге большого круга - От длины хорды
Вот элегантное решение, использующее шаблон разработки стратегии; Надеюсь, он достаточно читабельный.
TwoPointsDistanceCalculatorStrategy.js :
module.exports = () =>
class TwoPointsDistanceCalculatorStrategy {
constructor() {}
calculateDistance({ point1Coordinates, point2Coordinates }) {}
};
GreatCircleTwoPointsDistanceCalculatorStrategy.js:
module.exports = ({ TwoPointsDistanceCalculatorStrategy }) =>
class GreatCircleTwoPointsDistanceCalculatorStrategy extends TwoPointsDistanceCalculatorStrategy {
constructor() {
super();
}
/**
* Following the algorithm documented here:
* https://en.wikipedia.org/wiki/Great-circle_distance#Computational_formulas
*
* @param {object} inputs
* @param {array} inputs.point1Coordinates
* @param {array} inputs.point2Coordinates
*
* @returns {decimal} distance in kelometers
*/
calculateDistance({ point1Coordinates, point2Coordinates }) {
const convertDegreesToRadians = require('../convert-degrees-to-radians');
const EARTH_RADIUS = 6371; // in kelometers
const [lat1 = 0, lon1 = 0] = point1Coordinates;
const [lat2 = 0, lon2 = 0] = point2Coordinates;
const radianLat1 = convertDegreesToRadians({ degrees: lat1 });
const radianLon1 = convertDegreesToRadians({ degrees: lon1 });
const radianLat2 = convertDegreesToRadians({ degrees: lat2 });
const radianLon2 = convertDegreesToRadians({ degrees: lon2 });
const centralAngle = _computeCentralAngle({
lat1: radianLat1, lon1: radianLon1,
lat2: radianLat2, lon2: radianLon2,
});
const distance = EARTH_RADIUS * centralAngle;
return distance;
}
};
/**
*
* @param {object} inputs
* @param {decimal} inputs.lat1
* @param {decimal} inputs.lon1
* @param {decimal} inputs.lat2
* @param {decimal} inputs.lon2
*
* @returns {decimal} centralAngle
*/
function _computeCentralAngle({ lat1, lon1, lat2, lon2 }) {
const chordLength = _computeChordLength({ lat1, lon1, lat2, lon2 });
const centralAngle = 2 * Math.asin(chordLength / 2);
return centralAngle;
}
/**
*
* @param {object} inputs
* @param {decimal} inputs.lat1
* @param {decimal} inputs.lon1
* @param {decimal} inputs.lat2
* @param {decimal} inputs.lon2
*
* @returns {decimal} chordLength
*/
function _computeChordLength({ lat1, lon1, lat2, lon2 }) {
const { sin, cos, pow, sqrt } = Math;
const ΔX = cos(lat2) * cos(lon2) - cos(lat1) * cos(lon1);
const ΔY = cos(lat2) * sin(lon2) - cos(lat1) * sin(lon1);
const ΔZ = sin(lat2) - sin(lat1);
const ΔXSquare = pow(ΔX, 2);
const ΔYSquare = pow(ΔY, 2);
const ΔZSquare = pow(ΔZ, 2);
const chordLength = sqrt(ΔXSquare + ΔYSquare + ΔZSquare);
return chordLength;
}
конвертировано градусов к radians.js:
module.exports = function convertDegreesToRadians({ degrees }) {
return degrees * Math.PI / 180;
};
Это расстояние по Большому кругу - от длины хорды, задокументированной здесь .