coordist
Version:
Calculate distance between two points as on geoid as on flat surface (cartesian coordinate system)
177 lines (148 loc) • 5.15 kB
JavaScript
/**
* Coordist module designated to calculate distance between two point as on geoid (WGS84 format) as on flat surface.
*
* This is a port of php class from domino for node.js
* Original link: http://phpclub.ru/talk/threads/%D1%80%D0%B0%D1%81%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D0%B5-%D0%BC%D0%B5%D0%B6%D0%B4%D1%83-%D0%B4%D0%B2%D1%83%D0%BC%D1%8F-%D1%82%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8-%D0%B7%D0%B5%D0%BC%D0%BB%D0%B8-%D0%B2-gps-%D0%BA%D0%BE%D0%BE%D1%80%D0%B4%D0%B8%D0%BD%D0%B0%D1%82%D0%B0%D1%85-%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%B0-wgs84.54170/
*
* Ported by LIAL (https://github.com/lial/)
*/
var majorAxis = 6378137.0; // meters
var minorAxis = 6356752.3142; // meters
var majorAxisSquare = 40680631590769; // meters, Math.pow(majorAxis, 2)
var minorAxisSquare = 40408299984087; // meters, math.pow(minorAxis, 2)
/**
* Calculate distance between two point on surface
*
* @param Object coord1 First coordinate
* @param Object coord2 Second coordinate
* @param Bool isCartesian Is surface flat (yes - cartesian coordinate, no - geoid)
*
* @var coordX {lat, lng, alt}
* @var lat - latitude (широта)
* @var lng - longitude (долгота)
* @var alt - altitude (высота над уровнем моря)
*
* @return Number
*/
function distance(coord1, coord2, isCartesian) {
if (isCartesian) {
//Just for convenience for flat surface
if (coord1.x != undefined) coord1.lat = coord1.x;
if (coord1.y != undefined) coord1.lng = coord1.y;
if (coord2.x != undefined) coord2.lat = coord2.x;
if (coord2.y != undefined) coord2.lng = coord2.y;
return Math.sqrt(Math.pow((coord1.lat - coord2.lat), 2) + Math.pow((coord1.lng - coord2.lng), 2));
}
true_angle_1 = getTrueAngle(coord1);
true_angle_2 = getTrueAngle(coord2);
point_radius_1 = getPointRadius(coord1, true_angle_1);
point_radius_2 = getPointRadius(coord2, true_angle_2);
earth_point_1_x = point_radius_1 * Math.cos(Deg2Rad(true_angle_1));
earth_point_1_y = point_radius_1 * Math.sin(Deg2Rad(true_angle_1));
earth_point_2_x = point_radius_2 * Math.cos(Deg2Rad(true_angle_2));
earth_point_2_y = point_radius_2 * Math.sin(Deg2Rad(true_angle_2));
var x = distance(
{lat: earth_point_1_x, lng: earth_point_1_y},
{lat: earth_point_2_x, lng: earth_point_2_y},
true
);
var y = Math.PI * ((earth_point_1_x + earth_point_2_x) / 360) * (coord1.lng - coord2.lng);
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
}
/**
* Return decimal value of angle
*
* @param Number deg Value in degrees
* @param Number min Value in minutes
* @param Number sec Value in seconds
*
* @return Number
*/
function getDecimalDegree(deg, min, sec) {
if (min == undefined) min = 0;
if (sec == undefined) sec = 0;
return deg < 0 ?
(Math.abs(deg) + Math.abs(min) / 60 + Math.absabs(sec) / 3600) * -1 :
Math.absabs(deg) + Math.absabs(min) / 60 + Math.absabs(sec) / 3600;
}
/**
* Determine true angle for point on surface
*
* @param Object point Point on surface
*
* @var point {lat, lng, alt}
* @var lat - latitude (широта)
* @var lng - longitude (долгота)
* @var alt - altitude (высота над уровнем моря)
*
* @return Number
*/
function getTrueAngle(point) {
return Math.atan((minorAxisSquare / majorAxisSquare) * Math.tan(Deg2Rad(point.lat))) * 180 / Math.PI;
}
/**
* Determine radius of small circle (radius between meridians)
*
* @param Object point Point on surface
* @param Number trueAngle True angle for point
*
* @var point {lat, lng, alt}
* @var lat - latitude (широта)
* @var lng - longitude (долгота)
* @var alt - altitude (высота над уровнем моря)
*
* @return Number
*/
function getPointRadius(point, trueAngle) {
//If no altitude defined, will assume that point has no altitude
if (point.alt == undefined) point.alt = 0;
return point.alt + 1 / Math.sqrt(
Math.pow(Math.cos(Deg2Rad(trueAngle)), 2) / majorAxisSquare +
Math.pow(Math.sin(Deg2Rad(trueAngle)), 2) / minorAxisSquare
);
}
/**
* Returns latitude name
*
* @param Number lat Latitude in degrees
*
* @return String | Boolean
*/
function checkLatitude(lat) {
if (lat >= 0 && lat <= 90) {
return 'north';
} else if (lat >= -90 && lat <= 0) {
return 'south';
}
return false;
}
/**
* Returns longitude name
*
* @param Number lng Longitude in degrees
*
* @return String | Boolean
*/
function checkLongitude(lng) {
if (lng >= 0 && lng <= 180) {
return 'east';
} else if(lng >= -180 && lng <= 0) {
return 'west';
}
return false;
}
/**
* Converts degrees to radians
*
* @param Number value Value in degrees
*
* @return Number
*/
function Deg2Rad(value) {
return value * (Math.PI / 180);
}
module.exports.distance = distance;
module.exports.getDecimalDegree = getDecimalDegree;
module.exports.checkLatitude = checkLatitude;
module.exports.checkLongitude = checkLongitude;
module.exports.Deg2Rad = Deg2Rad;