diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2019-05-21 14:21:27 +0100 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2019-05-27 15:42:41 +0100 |
| commit | 7b566da6fe21883f096ae7d20259ae86015da69f (patch) | |
| tree | 01376a01412e06e8c3b762b04c3e03ee0f0a5d32 | |
| parent | aa87c0817d15d3b146d37157ba7ec559f63736e7 (diff) | |
| download | mullvadvpn-7b566da6fe21883f096ae7d20259ae86015da69f.tar.xz mullvadvpn-7b566da6fe21883f096ae7d20259ae86015da69f.zip | |
Add distance calculations to Location
| -rw-r--r-- | mullvad-types/src/location.rs | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/mullvad-types/src/location.rs b/mullvad-types/src/location.rs index 1c59c0d416..514ce35809 100644 --- a/mullvad-types/src/location.rs +++ b/mullvad-types/src/location.rs @@ -15,6 +15,42 @@ pub struct Location { pub longitude: f64, } +const RAIDUS_OF_EARTH: f64 = 6372.8; + +impl Location { + pub fn distance_from(&self, other: &Location) -> f64 { + haversine_dist_deg( + self.latitude, + self.longitude, + other.latitude, + other.longitude, + ) + } +} + +/// Takes input as latitude and longitude degrees. +fn haversine_dist_deg(lat: f64, lon: f64, other_lat: f64, other_lon: f64) -> f64 { + haversine_dist_rad( + lat.to_radians(), + lon.to_radians(), + other_lat.to_radians(), + other_lon.to_radians(), + ) +} +/// Implemented as per https://en.wikipedia.org/wiki/Haversine_formula and https://rosettacode.org/wiki/Haversine_formula#Rust +/// Takes input as radians, outputs kilometers. +fn haversine_dist_rad(lat: f64, lon: f64, other_lat: f64, other_lon: f64) -> f64 { + let d_lat = lat - other_lat; + let d_lon = lon - other_lon; + // Computing the haversine between two points + let haversine = + (d_lat / 2.0).sin().powi(2) + (d_lon / 2.0).sin().powi(2) * lat.cos() * other_lat.cos(); + + // using the haversine to compute the distance between two points + haversine.sqrt().asin() * 2.0 * RAIDUS_OF_EARTH +} + + /// The response from the am.i.mullvad.net location service. #[derive(Debug, Deserialize)] pub struct AmIMullvad { @@ -57,3 +93,26 @@ impl From<AmIMullvad> for GeoIpLocation { } } } + +#[cfg(test)] +mod tests { + #[test] + fn test_haversine_dist_deg() { + use super::haversine_dist_deg; + assert_eq!( + haversine_dist_deg(36.12, -86.67, 33.94, -118.4), + 2887.2599506071111 + ); + assert_eq!( + haversine_dist_deg(90.0, 5.0, 90.0, 79.0), + 0.0000000000004696822692507987 + ); + assert_eq!(haversine_dist_deg(0.0, 0.0, 0.0, 0.0), 0.0); + assert_eq!(haversine_dist_deg(49.0, 12.0, 49.0, 12.0), 0.0); + assert_eq!(haversine_dist_deg(6.0, 27.0, 7.0, 27.0), 111.22634257109462); + assert_eq!( + haversine_dist_deg(0.0, 179.5, 0.0, -179.5), + 111.22634257109495 + ); + } +} |
