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