commit 5bb7bf397b0df39cf40ca2d958a6d2a78750ca7e
parent 35734a7e6a83926aa03312cfb66a9f62c2937e6a
Author: Marcel <mtrnord1@gmail.com>
Date: Tue, 31 Dec 2019 01:24:02 +0100
Add a nicer terminal feel and cleanup some parts
Took 27 minutes
Diffstat:
7 files changed, 267 insertions(+), 202 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -4,6 +4,7 @@
name = "OSM_to_Euroscope"
version = "0.1.0"
dependencies = [
+ "clap",
"fnv",
"osmpbf",
]
@@ -15,12 +16,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -33,6 +59,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
+name = "clap"
+version = "2.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
name = "crc32fast"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -253,6 +294,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
+
+[[package]]
+name = "vec_map"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
+
+[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
@@ -9,3 +9,4 @@ edition = "2018"
[dependencies]
osmpbf = "0.1"
fnv = "1.0.6"
+clap = "2.31.2"
diff --git a/src/euroscope_ground.rs b/src/euroscope_ground.rs
@@ -0,0 +1,123 @@
+use std::fs;
+use std::fs::File;
+use std::io::Write;
+use std::path::Path;
+
+use fnv::FnvHashMap;
+use osmpbf::*;
+
+use crate::types::{Coords, LatLon, Refs};
+use crate::types;
+use crate::utils::format_coordinate;
+
+pub(crate) fn generate_ese_ground_taxiway<P: AsRef<Path> + Copy>(source_path: P, airport_name: &str) {
+ let out_path_string = format!("./out/{}.ese", airport_name);
+ let out_path = Path::new(&out_path_string);
+ if !out_path.parent().unwrap().exists() {
+ fs::create_dir_all(out_path.parent().unwrap()).expect("unable to generate dir");
+ }
+ let out_file = &mut File::create(out_path).expect("unable to open file");
+
+ out_file
+ .write_all(b"[GROUND]\n")
+ .expect("failed to write file");
+ let taxiways = get_taxiways(source_path);
+
+ let coords = get_taxiways_coords(source_path, taxiways);
+ write_taxiways(out_file, airport_name, coords);
+
+ out_file.sync_all().expect("unable to sync to file");
+}
+
+fn write_taxiways(out_file: &mut File, airport_name: &str, taxiways: FnvHashMap<String, Coords>) {
+ taxiways.iter().for_each(|(name, coordinates)| {
+ let type_string = format!("TAXI:{} {}:20:1\n", airport_name, name);
+ out_file
+ .write_all(type_string.as_bytes())
+ .expect("failed to write file");
+
+ let local_coords: Vec<&LatLon> = coordinates.iter().clone().collect();
+ local_coords.iter().for_each(|latlon| {
+ let lat_str = format_coordinate(latlon.lat);
+
+ let lon_str = format_coordinate(latlon.lon);
+
+ let coordinate_string: String;
+
+ coordinate_string = format!("COORD:N{}:E{}\n", lat_str, lon_str);
+ out_file
+ .write_all(coordinate_string.as_bytes())
+ .expect("failed to write file");
+ });
+ });
+}
+
+fn get_taxiways_coords<P: AsRef<Path> + Copy>(
+ path: P,
+ refs: FnvHashMap<String, Refs>,
+) -> FnvHashMap<String, Coords> {
+ let mut taxiways: FnvHashMap<String, Coords> = FnvHashMap::default();
+ let mut nodes: Vec<types::Node> = Vec::new();
+
+ let reader = ElementReader::from_path(path).unwrap();
+ reader
+ .for_each(|element| {
+ if let Element::DenseNode(node) = element {
+ let new_node = types::Node {
+ id: node.id,
+ lat: node.lat(),
+ lon: node.lon(),
+ };
+ nodes.push(new_node);
+ }
+ })
+ .unwrap();
+
+ for (key, val) in refs.iter() {
+ val.iter().for_each(|refval| {
+ if let Some(node) = nodes.iter().find(|x| x.id == *refval) {
+ let lat_lon = LatLon {
+ lat: node.lat,
+ lon: node.lon,
+ };
+
+ if taxiways.contains_key(key.as_str()) {
+ (*(taxiways.get_mut(key.as_str()).unwrap())).push(lat_lon);
+ } else {
+ let mut coords: Coords = Vec::new();
+ coords.push(lat_lon);
+ taxiways.insert(key.clone(), coords);
+ }
+ }
+ })
+ }
+
+ taxiways
+}
+
+fn get_taxiways<P: AsRef<Path> + Copy>(path: P) -> FnvHashMap<String, Refs> {
+ let mut taxiways: FnvHashMap<String, Refs> = FnvHashMap::default();
+
+ let reader = ElementReader::from_path(path).unwrap();
+ reader
+ .for_each(|element| {
+ if let Element::Way(way) = element {
+ if way
+ .tags()
+ .any(|(key, value)| key == "aeroway" && value == "taxiway")
+ {
+ if let Some((_, value)) = way.tags().find(|(key, _)| *key == "ref") {
+ let mut new_vals = way.refs().collect::<Vec<i64>>();
+
+ if taxiways.contains_key(value) {
+ taxiways.get_mut(value).unwrap().append(&mut new_vals);
+ } else {
+ taxiways.insert(value.to_string(), new_vals);
+ }
+ }
+ }
+ }
+ })
+ .unwrap();
+ taxiways
+}
diff --git a/src/main.rs b/src/main.rs
@@ -1,168 +1,49 @@
//#![feature(test)]
#![allow(non_snake_case)]
-use std::fs;
-use std::fs::File;
-use std::io::Write;
-use std::path::Path;
+extern crate clap;
-use fnv::FnvHashMap;
-use osmpbf::*;
+use std::process::exit;
-#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
-struct LatLon {
- lat: f64,
- lon: f64,
-}
-
-type Coords = Vec<LatLon>;
-type Refs = Vec<i64>;
-
-fn main() {
- generate_ese_ground_taxiway("./data/EDDH_cleaned.osm.pbf", "EDDH")
-}
-
-fn generate_ese_ground_taxiway<P: AsRef<Path> + Copy>(source_path: P, airport_name: &str) {
- let out_path_string = format!("./out/{}.ese", airport_name);
- let out_path = Path::new(&out_path_string);
- if !out_path.parent().unwrap().exists() {
- fs::create_dir_all(out_path.parent().unwrap()).expect("unable to generate dir");
- }
- let out_file = &mut File::create(out_path).expect("unable to open file");
-
- out_file
- .write_all(b"[GROUND]\n")
- .expect("failed to write file");
- let taxiways = get_taxiways(source_path);
-
- let coords = get_taxiways_coords(source_path, taxiways);
- write_taxiways(out_file, airport_name, coords);
-
- out_file.sync_all().expect("unable to sync to file");
-}
-
-fn to_2_digits(n: i32) -> i32 {
- let n = n as f32;
- let digit_offset = std::cmp::max((n.abs().log10() - 2.0).ceil() as i32, 0);
- let rounded = n / 10f32.powi(digit_offset);
- rounded as i32
-}
-
-fn format_coordinate(coordinate_raw: f64) -> String {
- let coordinate = coordinate_raw;
- let degree = coordinate.trunc() as i64;
- let minute = ((coordinate - degree as f64).abs() * 60.0).trunc() as i64;
- let seconds = 3600.0 * (coordinate - degree as f64).abs() - 60.0 * (minute as f64);
- let decimal_part_string = format!("{:.2}", seconds - (seconds.trunc() as f64) as f64);
- let decimal_part_split = decimal_part_string.split('.').collect::<Vec<&str>>();
- let decimal_part = decimal_part_split.last().unwrap();
-
- format!(
- "{:03}.{:02}.{:02}.{:02}",
- degree,
- minute,
- to_2_digits(seconds as i32),
- decimal_part
- )
-}
+use clap::{App, Arg, SubCommand};
-fn write_taxiways(out_file: &mut File, airport_name: &str, taxiways: FnvHashMap<String, Coords>) {
- taxiways.iter().for_each(|(name, coordinates)| {
- let type_string = format!("TAXI:{} {}:20:1\n", airport_name, name);
- out_file
- .write_all(type_string.as_bytes())
- .expect("failed to write file");
+use crate::euroscope_ground::generate_ese_ground_taxiway;
- let local_coords: Vec<&LatLon> = coordinates.iter().clone().collect();
- local_coords.iter().for_each(|latlon| {
- let lat_str = format_coordinate(latlon.lat);
+mod types;
+mod utils;
+mod euroscope_ground;
- let lon_str = format_coordinate(latlon.lon);
-
- let coordinate_string: String;
-
- coordinate_string = format!("COORD:N{}:E{}\n", lat_str, lon_str);
- out_file
- .write_all(coordinate_string.as_bytes())
- .expect("failed to write file");
- });
- });
-}
-
-struct Node {
- id: i64,
- lat: f64,
- lon: f64,
-}
-
-fn get_taxiways_coords<P: AsRef<Path> + Copy>(
- path: P,
- refs: FnvHashMap<String, Refs>,
-) -> FnvHashMap<String, Coords> {
- let mut taxiways: FnvHashMap<String, Coords> = FnvHashMap::default();
- let mut nodes: Vec<Node> = Vec::new();
-
- let reader = ElementReader::from_path(path).unwrap();
- reader
- .for_each(|element| {
- if let Element::DenseNode(node) = element {
- let new_node = Node {
- id: node.id,
- lat: node.lat(),
- lon: node.lon(),
- };
- nodes.push(new_node);
- }
- })
- .unwrap();
-
- for (key, val) in refs.iter() {
- val.iter().for_each(|refval| {
- if let Some(node) = nodes.iter().find(|x| x.id == *refval) {
- let lat_lon = LatLon {
- lat: node.lat,
- lon: node.lon,
- };
-
- if taxiways.contains_key(key.as_str()) {
- (*(taxiways.get_mut(key.as_str()).unwrap())).push(lat_lon);
- } else {
- let mut coords: Coords = Vec::new();
- coords.push(lat_lon);
- taxiways.insert(key.clone(), coords);
- }
- }
- })
+fn main() {
+ let matches = App::new("OSM_to_Euroscope")
+ .version("0.1.0")
+ .author("MTRNord <info@nordgedanken.de>")
+ .about("Converts OpenStreetMap Data to Euroscope Radar Screens")
+ .subcommand(SubCommand::with_name("taxiways")
+ .about("Converts taxiways to Euroscope Ground Networks")
+ .arg(Arg::with_name("osm_data")
+ .short("i")
+ .long("osm_data")
+ .value_name("osm.pbf FILE")
+ .takes_value(true)
+ .required(true)
+ .help("The input data used to convert from. (smaller data is faster). Needs to be .osm.pbf!"))
+ .arg(Arg::with_name("airport")
+ .short("a")
+ .long("airport")
+ .value_name("ICAO ID")
+ .takes_value(true)
+ .required(true)
+ .help("The ICAO identifier of the Airport which should be converted")))
+ .get_matches();
+
+
+ if let Some(matches) = matches.subcommand_matches("taxiways") {
+ //generate_ese_ground_taxiway("./data/EDDH_cleaned.osm.pbf", "EDDH");
+ generate_ese_ground_taxiway(matches.value_of("osm_data").unwrap(), matches.value_of("airport").unwrap());
+ } else {
+ println!("Please use the taxiways sub command!");
+ exit(1);
}
-
- taxiways
-}
-
-fn get_taxiways<P: AsRef<Path> + Copy>(path: P) -> FnvHashMap<String, Refs> {
- let mut taxiways: FnvHashMap<String, Refs> = FnvHashMap::default();
-
- let reader = ElementReader::from_path(path).unwrap();
- reader
- .for_each(|element| {
- if let Element::Way(way) = element {
- if way
- .tags()
- .any(|(key, value)| key == "aeroway" && value == "taxiway")
- {
- if let Some((_, value)) = way.tags().find(|(key, _)| *key == "ref") {
- let mut new_vals = way.refs().collect::<Vec<i64>>();
-
- if taxiways.contains_key(value) {
- taxiways.get_mut(value).unwrap().append(&mut new_vals);
- } else {
- taxiways.insert(value.to_string(), new_vals);
- }
- }
- }
- }
- })
- .unwrap();
- taxiways
}
#[cfg(test)]
diff --git a/src/main_lahm.rs b/src/main_lahm.rs
@@ -1,46 +0,0 @@
-use std::fs::File;
-
-use osm_xml::{Reference, Tag, OSM, Way};
-
-fn main() {
- let f = File::open("./data/EDDH.osm").unwrap();
- let doc = OSM::parse(f).unwrap();
-
- let way_info = way_reference_statistics(&doc);
-
- println!(
- "Way count {}",
- doc.ways
- .values()
- .filter(|way| {
- way.tags.contains(&Tag {
- key: "aeroway".to_string(),
- val: "taxiway".to_string(),
- })
- })
- .collect::<Vec<&Way>>()
- .len()
- );
- println!(
- "Way reference count: {}, invalid references: {}",
- way_info.0, way_info.1
- );
-}
-
-fn way_reference_statistics(doc: &OSM) -> (usize, usize) {
- doc.ways
- .values()
- .filter(|way| {
- way.tags.contains(&Tag {
- key: "aeroway".to_string(),
- val: "taxiway".to_string(),
- })
- })
- .flat_map(|way| way.nodes.iter())
- .fold((0, 0), |acc, node| match doc.resolve_reference(&node) {
- Reference::Node(_) => (acc.0 + 1, acc.1),
- Reference::Unresolved | Reference::Way(_) | Reference::Relation(_) => {
- (acc.0, acc.1 + 1)
- }
- })
-}
diff --git a/src/types.rs b/src/types.rs
@@ -0,0 +1,14 @@
+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
+pub(crate) struct LatLon {
+ pub(crate) lat: f64,
+ pub(crate) lon: f64,
+}
+
+pub(crate) struct Node {
+ pub(crate) id: i64,
+ pub(crate) lat: f64,
+ pub(crate) lon: f64,
+}
+
+pub(crate) type Coords = Vec<LatLon>;
+pub(crate) type Refs = Vec<i64>;
diff --git a/src/utils.rs b/src/utils.rs
@@ -0,0 +1,24 @@
+pub(crate) fn to_2_digits(n: i32) -> i32 {
+ let n = n as f32;
+ let digit_offset = std::cmp::max((n.abs().log10() - 2.0).ceil() as i32, 0);
+ let rounded = n / 10f32.powi(digit_offset);
+ rounded as i32
+}
+
+pub(crate) fn format_coordinate(coordinate_raw: f64) -> String {
+ let coordinate = coordinate_raw;
+ let degree = coordinate.trunc() as i64;
+ let minute = ((coordinate - degree as f64).abs() * 60.0).trunc() as i64;
+ let seconds = 3600.0 * (coordinate - degree as f64).abs() - 60.0 * (minute as f64);
+ let decimal_part_string = format!("{:.2}", seconds - (seconds.trunc() as f64) as f64);
+ let decimal_part_split = decimal_part_string.split('.').collect::<Vec<&str>>();
+ let decimal_part = decimal_part_split.last().unwrap();
+
+ format!(
+ "{:03}.{:02}.{:02}.{:02}",
+ degree,
+ minute,
+ to_2_digits(seconds as i32),
+ decimal_part
+ )
+}