summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2019-05-21 14:21:27 +0100
committerEmīls Piņķis <emils@mullvad.net>2019-05-27 15:42:41 +0100
commit7b566da6fe21883f096ae7d20259ae86015da69f (patch)
tree01376a01412e06e8c3b762b04c3e03ee0f0a5d32
parentaa87c0817d15d3b146d37157ba7ec559f63736e7 (diff)
downloadmullvadvpn-7b566da6fe21883f096ae7d20259ae86015da69f.tar.xz
mullvadvpn-7b566da6fe21883f096ae7d20259ae86015da69f.zip
Add distance calculations to Location
-rw-r--r--mullvad-types/src/location.rs59
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
+ );
+ }
+}