1 use crate::Distance; 2 use ordered_float::NotNan; 3 use serde::{Deserialize, Serialize}; 4 use std::error::Error; 5 use std::fmt; 6 use std::fs::File; 7 use std::io::{BufRead, BufReader}; 8 9 // longitude is x, latitude is y 10 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)] 11 pub struct LonLat { 12 longitude: NotNan<f64>, 13 latitude: NotNan<f64>, 14 } 15 16 impl LonLat { new(lon: f64, lat: f64) -> LonLat17 pub fn new(lon: f64, lat: f64) -> LonLat { 18 LonLat { 19 longitude: NotNan::new(lon).unwrap(), 20 latitude: NotNan::new(lat).unwrap(), 21 } 22 } 23 x(self) -> f6424 pub fn x(self) -> f64 { 25 self.longitude.into_inner() 26 } 27 y(self) -> f6428 pub fn y(self) -> f64 { 29 self.latitude.into_inner() 30 } 31 gps_dist_meters(self, other: LonLat) -> Distance32 pub fn gps_dist_meters(self, other: LonLat) -> Distance { 33 // Haversine distance 34 let earth_radius_m = 6_371_000.0; 35 let lon1 = self.x().to_radians(); 36 let lon2 = other.x().to_radians(); 37 let lat1 = self.y().to_radians(); 38 let lat2 = other.y().to_radians(); 39 40 let delta_lat = lat2 - lat1; 41 let delta_lon = lon2 - lon1; 42 43 let a = (delta_lat / 2.0).sin().powi(2) 44 + (delta_lon / 2.0).sin().powi(2) * lat1.cos() * lat2.cos(); 45 let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt()); 46 Distance::meters(earth_radius_m * c) 47 } 48 49 // Pretty meaningless units, for comparing distances very roughly fast_dist(self, other: LonLat) -> NotNan<f64>50 pub fn fast_dist(self, other: LonLat) -> NotNan<f64> { 51 NotNan::new((self.x() - other.x()).powi(2) + (self.y() - other.y()).powi(2)).unwrap() 52 } 53 approx_eq(self, other: LonLat) -> bool54 pub(crate) fn approx_eq(self, other: LonLat) -> bool { 55 let epsilon = 1e-8; 56 (self.x() - other.x()).abs() < epsilon && (self.y() - other.y()).abs() < epsilon 57 } 58 read_osmosis_polygon(path: String) -> Result<Vec<LonLat>, Box<dyn Error>>59 pub fn read_osmosis_polygon(path: String) -> Result<Vec<LonLat>, Box<dyn Error>> { 60 let f = File::open(&path)?; 61 let mut pts = Vec::new(); 62 for (idx, line) in BufReader::new(f).lines().enumerate() { 63 if idx < 2 { 64 continue; 65 } 66 let line = line?; 67 if line == "END" { 68 break; 69 } 70 let parts = line.trim().split(" ").collect::<Vec<_>>(); 71 pts.push(LonLat::new( 72 parts[0].parse::<f64>()?, 73 parts[1].parse::<f64>()?, 74 )); 75 } 76 Ok(pts) 77 } 78 } 79 80 impl fmt::Display for LonLat { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 82 write!(f, "LonLat({0}, {1})", self.x(), self.y()) 83 } 84 } 85