import { comparatorDistanceUnits } from '@adalo/constants' export interface Coordinate { latitude: number longitude: number } type DistanceUnit = typeof comparatorDistanceUnits[keyof typeof comparatorDistanceUnits] const KMS_PER_MILE = 1.609344 // 1 mi = 5280 ft ~= 5280 ft * (~1852 m/6076.11549 ft) ~= 1609.34400 m (ref: https://web.archive.org/web/20111210164956/http://ts.nist.gov/weightsandmeasures/publications/appxc.cfm) const EARTH_RADIUS_IN_KMS: number = 6378.8 // Source: https://www.geeksforgeeks.org/program-distance-two-points-earth/ function asRadians(degrees: number) { return degrees * (Math.PI / 180) } export function kilometersBetweenLocations( a: Coordinate, b: Coordinate ): number { const { latitude: latA, longitude: lonA } = a const { latitude: latB, longitude: lonB } = b // Haversine Formula // from https://www.movable-type.co.uk/scripts/latlong.html const latARad = asRadians(latA) const latBRad = asRadians(latB) const deltaLatRad = asRadians(latB - latA) const deltaLonRad = asRadians(lonB - lonA) const intermediate = Math.sin(deltaLatRad / 2) * Math.sin(deltaLatRad / 2) + Math.cos(latARad) * Math.cos(latBRad) * Math.sin(deltaLonRad / 2) * Math.sin(deltaLonRad / 2) return ( EARTH_RADIUS_IN_KMS * 2 * Math.atan2(Math.sqrt(intermediate), Math.sqrt(1 - intermediate)) ) } export function asKilometers(value: number, unit: DistanceUnit): number { switch (unit) { case comparatorDistanceUnits.KILOMETERS: // no-op return value case comparatorDistanceUnits.MILES: return value * KMS_PER_MILE default: throw new Error(`Unknown unit: ${unit}`) } } export const convertToMiles = (value: number): number => value / KMS_PER_MILE