euroscope_ground.rs (4625B)
1 use std::fs; 2 use std::fs::File; 3 use std::io::{BufReader, Cursor, Write}; 4 use std::path::Path; 5 6 use fnv::FnvHashMap; 7 use osmio::obj_types::StringOSMObj; 8 use osmio::xml::XMLReader; 9 use osmio::{Node, OSMObjBase, OSMReader, Way}; 10 use reqwest::{Request, Response}; 11 12 use crate::types; 13 use crate::types::{Coords, LatLon, Refs}; 14 use percent_encoding::{percent_encode, NON_ALPHANUMERIC}; 15 16 pub(crate) async fn generate_ese_ground_taxiway( 17 airport_name: &str, 18 ) -> Result<(), Box<dyn std::error::Error>> { 19 let out_path_string = format!("./out/{}.ese", airport_name); 20 let out_path = Path::new(&out_path_string); 21 if !out_path.parent().unwrap().exists() { 22 fs::create_dir_all(out_path.parent().unwrap()).expect("unable to generate dir"); 23 } 24 let out_file = &mut File::create(out_path).expect("unable to open file"); 25 26 out_file 27 .write_all(b"[GROUND]\n") 28 .expect("failed to write file"); 29 30 let client = reqwest::Client::builder().build()?; 31 let query0 = "data="; 32 let query1 = "[out:xml][timeout:25]; 33 area[icao="; 34 let query2 = "]->.searchArea; 35 ( 36 node[\"aeroway\"=\"taxiway\"][\"ref\"](area.searchArea); 37 way[\"aeroway\"=\"taxiway\"][\"ref\"](area.searchArea); 38 relation[\"aeroway\"=\"taxiway\"][\"ref\"](area.searchArea); 39 ); 40 out body; 41 >; 42 out skel qt;"; 43 let complete: String = [query1, airport_name, query2].concat(); 44 let query = percent_encode(complete.replace("\n", "").as_bytes(), NON_ALPHANUMERIC).to_string(); 45 let query_complete: String = [query0, query.as_str()].concat(); 46 let req: Request = client.post("https://overpass-api.de/api/interpreter") 47 .body(query_complete).build()?; 48 49 let resp: Response = client.execute(req).await?; 50 51 let data = resp.text().await?; 52 53 let data_buffer = Cursor::new(data); 54 let buf_reader = BufReader::new(data_buffer); 55 56 let mut osm = XMLReader::new(buf_reader); 57 58 let mut nodes: Vec<types::Node> = Vec::new(); 59 let mut ways: FnvHashMap<String, Refs> = FnvHashMap::default(); 60 let mut taxiways: FnvHashMap<String, Coords> = FnvHashMap::default(); 61 62 osm.objects().for_each(|object| match object { 63 StringOSMObj::Node(n) => { 64 let lat_lon = n.lat_lon().expect("unable to get lat_lon"); 65 let new_node = types::Node { 66 id: n.id(), 67 lat: lat_lon.0 as f64, 68 lon: lat_lon.1 as f64, 69 }; 70 nodes.push(new_node); 71 } 72 StringOSMObj::Way(w) => { 73 let mut tags = w.tags(); 74 if tags.any(|x| x.0 == "aeroway" && x.1 == "taxiway") { 75 if tags.any(|x| x.0 == "ref") { 76 let value = w 77 .tags() 78 .find(|x| x.0 == "ref") 79 .expect("unable to find ref") 80 .1; 81 let mut nodes: Vec<i64> = Vec::from(w.nodes()); 82 83 if ways.contains_key(value) { 84 ways.get_mut(value).unwrap().append(&mut nodes); 85 } else { 86 ways.insert(value.to_string(), nodes); 87 } 88 } 89 } 90 } 91 StringOSMObj::Relation(_) => {} 92 }); 93 for (key, val) in ways.iter() { 94 val.iter().for_each(|&refval| { 95 if let Some(node) = nodes.iter().find(|&x| x.id == refval) { 96 let lat_lon = LatLon { 97 lat: node.lat, 98 lon: node.lon, 99 }; 100 101 if taxiways.contains_key(key.as_str()) { 102 (*(taxiways.get_mut(key.as_str()).unwrap())).push(lat_lon); 103 } else { 104 let mut coords: Coords = Vec::new(); 105 coords.push(lat_lon); 106 taxiways.insert(key.clone(), coords); 107 } 108 } 109 }); 110 } 111 112 write_taxiways(out_file, airport_name, taxiways); 113 114 out_file.sync_all().expect("unable to sync to file"); 115 Ok(()) 116 } 117 118 fn write_taxiways(out_file: &mut File, airport_name: &str, taxiways: FnvHashMap<String, Coords>) { 119 taxiways.iter().for_each(|(name, coordinates)| { 120 let type_string = format!("TAXI:{} {}:20:1\n", airport_name, name); 121 out_file 122 .write_all(type_string.as_bytes()) 123 .expect("failed to write file"); 124 125 let local_coords: Vec<&LatLon> = coordinates.iter().clone().collect(); 126 local_coords.iter().for_each(|latlon| { 127 out_file 128 .write_all(format_coordinate!(latlon.lat, latlon.lon)) 129 .expect("failed to write file"); 130 }); 131 }); 132 }