1#[cfg(feature = "sbas")]
3use crate::prelude::Constellation;
4
5#[cfg(feature = "sbas")]
9use geo::{point, Contains, LineString};
10#[cfg(feature = "sbas")]
11use std::iter::FromIterator;
12#[cfg(feature = "sbas")]
13use std::str::FromStr;
14#[cfg(feature = "sbas")]
15use wkt::{Geometry, Wkt, WktFloat};
16
17#[cfg(feature = "sbas")]
18fn wkt_line_string_to_geo<T>(line_string: &wkt::types::LineString<T>) -> LineString<T>
19where
20 T: WktFloat + Default + FromStr,
21{
22 LineString::from_iter(line_string.0.iter().map(|coord| (coord.x, coord.y)))
23}
24
25#[cfg(feature = "sbas")]
26fn line_string<T>(name: &str) -> LineString<T>
27where
28 T: WktFloat + Default + FromStr,
29{
30 let mut res = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
31 res.push("data");
32 res.push(name);
33 let content = std::fs::read_to_string(res).unwrap();
34 let wkt = Wkt::from_str(&content).unwrap();
35 match wkt.item {
36 Geometry::LineString(line) => wkt_line_string_to_geo(&line),
37 _ => unreachable!(),
38 }
39}
40
41#[cfg(feature = "sbas")]
42fn load_database() -> Vec<(Constellation, geo::Polygon)> {
43 let mut db: Vec<(Constellation, geo::Polygon)> = Vec::new();
44 let db_path = env!("CARGO_MANIFEST_DIR").to_owned() + "/data/";
45 let db_path = std::path::PathBuf::from(db_path);
46 for entry in std::fs::read_dir(db_path).unwrap() {
47 let entry = entry.unwrap();
48 let path = entry.path();
49 let fullpath = &path.to_str().unwrap();
50 let extension = path.extension().unwrap().to_str().unwrap();
51 let name = path.file_stem().unwrap().to_str().unwrap();
52 if extension.eq("wkt") {
53 let poly = geo::Polygon::<f64>::new(
54 line_string(fullpath), vec![],
56 ); if let Ok(sbas) = Constellation::from_str(&name.to_uppercase()) {
58 db.push((sbas, poly))
59 }
60 }
61 }
62 db
63}
64
65#[cfg(feature = "sbas")]
66#[cfg_attr(docsrs, doc(cfg(feature = "sbas")))]
67pub fn sbas_selection(lat: f64, lon: f64) -> Option<Constellation> {
83 let db = load_database();
84 let point: geo::Point<f64> = point!(x: lon, y: lat,);
85 for (sbas, area) in db {
86 if area.contains(&point) {
87 return Some(sbas.clone());
88 }
89 }
90 None
91}
92
93#[cfg(feature = "sbas")]
94#[cfg(test)]
95mod test {
96 use super::*;
97 #[test]
98 #[cfg(feature = "sbas")]
99 fn sbas_helper() {
100 let sbas = sbas_selection(48.808378, 2.382682);
102 assert_eq!(sbas.is_some(), true);
103 assert_eq!(sbas.unwrap(), Constellation::EGNOS);
104
105 let sbas = sbas_selection(-77.490631, 91.435181);
107 assert_eq!(sbas.is_none(), true);
108
109 let sbas = sbas_selection(33.981431, -118.193601);
111 assert_eq!(sbas.is_some(), true);
112 assert_eq!(sbas.unwrap(), Constellation::WAAS);
113
114 let sbas = sbas_selection(-23.216639, -63.170983);
116 assert_eq!(sbas.is_none(), true);
117
118 let sbas = sbas_selection(10.714217, 17.087263);
120 assert_eq!(sbas.is_some(), true);
121 assert_eq!(sbas.unwrap(), Constellation::ASBAS);
122
123 let sbas = sbas_selection(-32.473320, 21.112770);
125 assert_eq!(sbas.is_none(), true);
126
127 let sbas = sbas_selection(19.314290, 76.798953);
129 assert_eq!(sbas.is_some(), true);
130 assert_eq!(sbas.unwrap(), Constellation::GAGAN);
131
132 let sbas = sbas_selection(-29.349172, 72.773447);
134 assert_eq!(sbas.is_none(), true);
135
136 let sbas = sbas_selection(-27.579847, 131.334992);
138 assert_eq!(sbas.is_some(), true);
139 assert_eq!(sbas.unwrap(), Constellation::SPAN);
140 let sbas = sbas_selection(-45.113525, 169.864842);
142 assert_eq!(sbas.is_some(), true);
143 assert_eq!(sbas.unwrap(), Constellation::SPAN);
144
145 let sbas = sbas_selection(34.462967, 98.172480);
147 assert_eq!(sbas, Some(Constellation::BDSBAS));
148
149 let sbas = sbas_selection(37.067846, 128.34);
151 assert_eq!(sbas, Some(Constellation::KASS));
152
153 let sbas = sbas_selection(36.081095, 138.274859);
155 assert_eq!(sbas, Some(Constellation::MSAS));
156
157 let sbas = sbas_selection(60.004390, 89.090326);
159 assert_eq!(sbas, Some(Constellation::SDCM));
160 }
161}