Goal
There are two goals:
- Sort latitude and longitude by distance
- Group the latitude and longitude based on a tolerance
Expected
Latitude and longitude are sorted in order of distance and grouped by tolerance.
Actual
Latitude and longitude are sorted in order of distance but the grouping does not feel right.
What I've tried
I've used the Haversine formula from several StackOverflow answers e.g. example 1, example 2, example 3, and managed to sort the locations by distance (goal #1 - I think ). I attempted to group them using a tolerance via Math.abs(lat - lastLat) < tolerance
but I'm not confident it's working or flexible (goal #2).
Code
const locations = [
{ lat: 77.62279999, lng: 12.95248389 },
{ lat: 77.62517676, lng: 12.95027966 },
{ lat: 77.62753442, lng: 12.93745478 },
{ lat: 77.62217671, lng: 12.93353553 },
];
const distance = (lat1, lon1, lat2, lon2) => {
const radlat1 = (Math.PI * lat1) / 180;
const radlat2 = (Math.PI * lat2) / 180;
const theta = lon1 - lon2;
const radtheta = (Math.PI * theta) / 180;
let dist =
Math.sin(radlat1) * Math.sin(radlat2) +
Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
dist = Math.acos(dist);
dist = (dist * 180) / Math.PI;
dist = dist * 60 * 1.1515;
dist = dist * 1.609344;
return dist;
};
const sortedLocationsByDistance = locations.sort(function (a, b) {
return distance(0, 0, a.lat, a.lng) - distance(0, 0, b.lat, b.lng);
});
console.log('Sorted:', sortedLocationsByDistance);
const groupedLocationsByTolerance = {};
const tolerance = 0.001;
sortedLocationsByDistance.forEach(({ lat, lng }, index) => {
if (
Object.keys(groupedLocationsByTolerance).length &&
Math.abs(lat - sortedLocationsByDistance.slice(-1)[0].lat) < tolerance &&
Math.abs(lng - sortedLocationsByDistance.slice(-1)[0].lng) < tolerance
) {
groupedLocationsByTolerance[Object.keys(groupedLocationsByTolerance).slice(-1)[0]].push({ lat, lng });
return;
}
groupedLocationsByTolerance[index] = groupedLocationsByTolerance[index] || [];
groupedLocationsByTolerance[index].push({ lat, lng });
});
console.log('Grouped:', groupedLocationsByTolerance);