Я знаю, что одним из лучших сценариев для расчета расстояния между двумя точками является VBA-скрипт, который я нашел здесь ....
Теперь я попытался "преобразовать""этот скрипт из VBA в Google Apps Script. Даже я действительно пытался преобразовать это шаг за шагом, но я получаю совершенно другой (неправильный) результат, и я не вижу причины для этого. Что не так с кодом? Я знаю, что есть и другие функции, обеспечивающие результат. Но ни один из них не такой точный, как этот.
function toRad(degree){
return degree * Math.PI / 180;
}
function quadrat(quadrat){
return Math.pow(quadrat,2);
}
function distances(lon1, lat1, lon2, lat2) {
var EPSILON = 0.000000000001;
var low_a = 6378137;
var low_b = 6356752.3142;
var f = 1 / 298.257223563;
var L = toRad((lon2 - lon1));
var U1 = Math.atan((1 - f) * Math.tan(toRad(lat1))); //Atn = Atan!!!
var U2 = Math.atan((1 - f) * Math.tan(toRad(lat2))); //Atn = Atan!!!
var sinU1 = Math.sin(U1);
var cosU1 = Math.cos(U1);
var sinU2 = Math.sin(U2);
var cosU2 = Math.cos(U2);
var lambda = L;
var lambdaP = 2 * Math.PI;
var iterLimit = 100; // can be set as low as 20 if desired.
while ( (Math.abs((lambda - lambdaP)) > EPSILON && iterLimit > 0)){
iterLimit = (iterLimit - 1);
var sinLambda = Math.sin(lambda);
var cosLambda = Math.cos(lambda);
var sinSigma = Math.sqrt( (quadrat((cosU2 * sinLambda)) + quadrat(((cosU1 * sinU2) - (sinU1 * cosU2 * cosLambda)))) );
if (sinSigma == 0){
var distances = 0; //co-incident points
break;
}
var cosSigma = ((sinU1 * sinU2) + (cosU1 * cosU2 * cosLambda));
var sigma = Math.atan2(cosSigma, sinSigma);
var sinAlpha = ((cosU1 * cosU2 * sinLambda) / sinSigma);
var cosSqAlpha = (1 - (sinAlpha * sinAlpha));
if (cosSqAlpha == 0){ //check for a divide by zero
var cos2SigmaM = 0; //2 points on the equator
}
else{
cos2SigmaM = (cosSigma - ((2 * sinU1 * sinU2) / cosSqAlpha));
}
var c = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
lambdaP = lambda;
var P1 = (-1 + (2 * quadrat(cos2SigmaM)));
var P2 = (sigma + (c * sinSigma * (cos2SigmaM + (c * cosSigma * P1))));
lambda = (L + ((1 - c) * (f * sinAlpha * P2)));
}
var uSq = cosSqAlpha * (quadrat(low_a) - quadrat(low_b)) / quadrat(low_b);
P1 = (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
var upper_A = 1 + uSq / 16384 * P1;
var upper_B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
P1 = (-3 + 4 * quadrat(sinSigma)) * (-3 + 4 * quadrat(cos2SigmaM));
P2 = upper_B * sinSigma;
var P3 = (cos2SigmaM + upper_B / 4 * (cosSigma * (-1 + 2 * quadrat(cos2SigmaM)) - upper_B / 6 * cos2SigmaM * P1));
var deltaSigma = P2 * P3;
var S = low_b * upper_A * (sigma - deltaSigma);
var finalresult = +S.toFixed(3);
return finalresult;
}
Кстати ... этот работает, но он не такой точный, как VBA-скрипт.
function distVincenty(lon1, lat1, lon2, lat2) {
var R = 6371000; // radius of the earth in meters, https://en.wikipedia.org/wiki/Earth_radius
var dLon = (lon2-lon1) * Math.PI / 180; // Convert degrees to radians
var dLat = (lat2-lat1) * Math.PI / 180; // Convert degrees to radians
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
// Distance in meters, rounded to an integer.
return d
}