smhi/
get_closest_station.rs1use crate::{Error, Gateway, Parameter, Station, BASE_URL};
2use serde::Deserialize;
3
4impl Gateway {
5 pub async fn get_closest_station<'a>(
6 &self,
7 latitude: f64,
8 longitude: f64,
9 parameter: &'a Parameter,
10 exclude: Option<&Vec<u32>>,
11 ) -> Result<(Station, f64), Error> {
12 #[derive(Deserialize)]
13 #[serde(rename_all = "camelCase")]
14 struct Response {
15 station: Vec<Station>,
16 }
17
18 let url = format!(
21 "{}/parameter/{}.json",
22 BASE_URL,
23 serde_json::to_string(¶meter).unwrap()
24 );
25 let res: Response = self.get(&url).await?;
26
27 let mut closest = None;
29 for station in res.station {
30 if station.active {
31 if let Some(exclude) = exclude {
33 if exclude.contains(&station.id) {
34 continue;
35 }
36 }
37
38 let distance =
41 distance_meters(latitude, longitude, station.latitude, station.longitude);
42 match &closest {
43 Some((_, closest_distance)) => {
44 if &distance < closest_distance {
45 closest = Some((station.clone(), distance));
46 }
47 }
48 None => closest = Some((station.clone(), distance)),
49 }
50 }
51 }
52
53 match closest {
54 Some((station, distance)) => Ok((station, distance)),
55 None => Err(Error::NotFound),
56 }
57 }
58}
59
60fn distance_meters(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 {
61 let x = deg2rad(lon1 - lon2) * f64::cos(deg2rad((lat1 + lat2) / 2.0));
62 let y = deg2rad(lat1 - lat2);
63 let dist = 6371000.0 * f64::sqrt(x * x + y * y);
64 return dist;
65}
66
67fn deg2rad(degrees: f64) -> f64 {
68 let pi = std::f64::consts::PI;
69 return degrees * (pi / 180.0);
70}