Untangle large source file
This commit is contained in:
parent
6960bd42c5
commit
3ba8001807
@ -1,2 +1,4 @@
|
|||||||
pub mod lexicographic_file_walker;
|
pub mod lexicographic_file_walker;
|
||||||
pub mod osm;
|
pub mod osm;
|
||||||
|
pub mod osm_db;
|
||||||
|
pub mod osrm_world;
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
// TODO: consider trait for OSM entities
|
|
||||||
// TODO: better error handling in XML creation
|
|
||||||
// FIXME: today nodes are stored twice
|
|
||||||
// TODO: move node lookup by name to here
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
|
use xml_builder::XMLElement;
|
||||||
|
|
||||||
static OSM_USER: &str = "osrm";
|
static OSM_USER: &str = "osrm";
|
||||||
static OSM_TIMESTAMP: &str = "2000-01-01T00:00:00Z";
|
static OSM_TIMESTAMP: &str = "2000-01-01T00:00:00Z";
|
||||||
@ -134,127 +130,3 @@ impl OSMWay {
|
|||||||
// self.tags.insert(key.into(), value.into());
|
// self.tags.insert(key.into(), value.into());
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct OSMDb {
|
|
||||||
nodes: Vec<(char, OSMNode)>,
|
|
||||||
ways: Vec<OSMWay>,
|
|
||||||
// relations: Vec<OSMRelation>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OSMDb {
|
|
||||||
pub fn add_node(&mut self, node: OSMNode) {
|
|
||||||
let name = node.tags.get("name").unwrap();
|
|
||||||
assert!(
|
|
||||||
name.len() == 1,
|
|
||||||
"name needs to be of length 1, but was \"{name}\""
|
|
||||||
);
|
|
||||||
self.nodes.push((name.chars().next().unwrap(), node));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_node(&self, search_name: char) -> Option<&(char, OSMNode)> {
|
|
||||||
// TODO: this is a linear search.
|
|
||||||
self.nodes.iter().find(|(name, _node)| search_name == *name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_way(&mut self, way: OSMWay) {
|
|
||||||
self.ways.push(way);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub fn add_relation(&mut self, relation: OSMRelation) {
|
|
||||||
// self.relations.push(relation);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn clear(&mut self) {
|
|
||||||
// self.nodes.clear();
|
|
||||||
// self.ways.clear();
|
|
||||||
// // self.relations.clear();
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn to_xml(&self) -> String {
|
|
||||||
let mut xml = XMLBuilder::new()
|
|
||||||
.version(XMLVersion::XML1_0)
|
|
||||||
.encoding("UTF-8".into())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let mut osm = XMLElement::new("osm");
|
|
||||||
osm.add_attribute("generator", "osrm-test");
|
|
||||||
osm.add_attribute("version", "0.6");
|
|
||||||
|
|
||||||
for (_, node) in &self.nodes {
|
|
||||||
osm.add_child(node.to_xml()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
for way in &self.ways {
|
|
||||||
osm.add_child(way.to_xml()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
xml.set_root_element(osm);
|
|
||||||
|
|
||||||
let mut writer: Vec<u8> = Vec::new();
|
|
||||||
xml.generate(&mut writer).unwrap();
|
|
||||||
String::from_utf8(writer).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub fn node_len(&self) -> usize {
|
|
||||||
// self.nodes.len()
|
|
||||||
// }
|
|
||||||
// pub fn way_len(&self) -> usize {
|
|
||||||
// self.ways.len()
|
|
||||||
// }
|
|
||||||
// pub fn relation_len(&self) -> usize {
|
|
||||||
// self.relations.len()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty_db_by_default() {
|
|
||||||
use super::*;
|
|
||||||
let osm_db = OSMDb::default();
|
|
||||||
assert_eq!(0, osm_db.node_len());
|
|
||||||
assert_eq!(0, osm_db.way_len());
|
|
||||||
// assert_eq!(0, osm_db.relation_len());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn osm_db_with_single_node() {
|
|
||||||
use super::*;
|
|
||||||
let mut osm_db = OSMDb::default();
|
|
||||||
|
|
||||||
let mut node1 = OSMNode {
|
|
||||||
id: 123,
|
|
||||||
lat: 50.1234,
|
|
||||||
lon: 8.9876,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut node2 = OSMNode {
|
|
||||||
id: 321,
|
|
||||||
lat: 50.1234,
|
|
||||||
lon: 8.9876,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
node1.add_tag("name", "a");
|
|
||||||
node2.add_tag("name", "b");
|
|
||||||
osm_db.add_node(node1.clone());
|
|
||||||
osm_db.add_node(node2.clone());
|
|
||||||
|
|
||||||
let mut way = OSMWay {
|
|
||||||
id: 890,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
way.nodes.push(node1);
|
|
||||||
way.nodes.push(node2);
|
|
||||||
|
|
||||||
osm_db.add_way(way);
|
|
||||||
|
|
||||||
let actual = osm_db.to_xml();
|
|
||||||
let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<osm generator=\"osrm-test\" version=\"0.6\">\n\t<node id=\"123\" version=\"1.0\" user=\"osrm\" timestamp=\"2000-01-01T00:00:00Z\" lon=\"8.9876\" lat=\"50.1234\">\n\t\t<tag name=\"a\" />\n\t</node>\n\t<node id=\"321\" version=\"1.0\" user=\"osrm\" timestamp=\"2000-01-01T00:00:00Z\" lon=\"8.9876\" lat=\"50.1234\">\n\t\t<tag name=\"b\" />\n\t</node>\n\t<way id=\"890\" version=\"1\" uid=\"1\" user=\"osrm\" timestamp=\"2000-01-01T00:00:00Z\">\n\t\t<nd ref=\"123\" />\n\t\t<nd ref=\"321\" />\n\t</way>\n</osm>\n";
|
|
||||||
|
|
||||||
println!("{actual}");
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
127
tests/common/osm_db.rs
Normal file
127
tests/common/osm_db.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
|
||||||
|
use super::osm::{OSMNode, OSMWay};
|
||||||
|
|
||||||
|
// TODO: better error handling in XML creation
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct OSMDb {
|
||||||
|
nodes: Vec<(char, OSMNode)>,
|
||||||
|
ways: Vec<OSMWay>,
|
||||||
|
// relations: Vec<OSMRelation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OSMDb {
|
||||||
|
pub fn add_node(&mut self, node: OSMNode) {
|
||||||
|
let name = node.tags.get("name").unwrap();
|
||||||
|
assert!(
|
||||||
|
name.len() == 1,
|
||||||
|
"name needs to be of length 1, but was \"{name}\""
|
||||||
|
);
|
||||||
|
self.nodes.push((name.chars().next().unwrap(), node));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_node(&self, search_name: char) -> Option<&(char, OSMNode)> {
|
||||||
|
// TODO: this is a linear search.
|
||||||
|
self.nodes.iter().find(|(name, _node)| search_name == *name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_way(&mut self, way: OSMWay) {
|
||||||
|
self.ways.push(way);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn add_relation(&mut self, relation: OSMRelation) {
|
||||||
|
// self.relations.push(relation);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn clear(&mut self) {
|
||||||
|
// self.nodes.clear();
|
||||||
|
// self.ways.clear();
|
||||||
|
// // self.relations.clear();
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn to_xml(&self) -> String {
|
||||||
|
let mut xml = XMLBuilder::new()
|
||||||
|
.version(XMLVersion::XML1_0)
|
||||||
|
.encoding("UTF-8".into())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let mut osm = XMLElement::new("osm");
|
||||||
|
osm.add_attribute("generator", "osrm-test");
|
||||||
|
osm.add_attribute("version", "0.6");
|
||||||
|
|
||||||
|
for (_, node) in &self.nodes {
|
||||||
|
osm.add_child(node.to_xml()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for way in &self.ways {
|
||||||
|
osm.add_child(way.to_xml()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.set_root_element(osm);
|
||||||
|
|
||||||
|
let mut writer: Vec<u8> = Vec::new();
|
||||||
|
xml.generate(&mut writer).unwrap();
|
||||||
|
String::from_utf8(writer).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn node_len(&self) -> usize {
|
||||||
|
// self.nodes.len()
|
||||||
|
// }
|
||||||
|
// pub fn way_len(&self) -> usize {
|
||||||
|
// self.ways.len()
|
||||||
|
// }
|
||||||
|
// pub fn relation_len(&self) -> usize {
|
||||||
|
// self.relations.len()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_db_by_default() {
|
||||||
|
use super::*;
|
||||||
|
let osm_db = OSMDb::default();
|
||||||
|
assert_eq!(0, osm_db.node_len());
|
||||||
|
assert_eq!(0, osm_db.way_len());
|
||||||
|
// assert_eq!(0, osm_db.relation_len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn osm_db_with_single_node() {
|
||||||
|
use super::*;
|
||||||
|
let mut osm_db = OSMDb::default();
|
||||||
|
|
||||||
|
let mut node1 = OSMNode {
|
||||||
|
id: 123,
|
||||||
|
lat: 50.1234,
|
||||||
|
lon: 8.9876,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut node2 = OSMNode {
|
||||||
|
id: 321,
|
||||||
|
lat: 50.1234,
|
||||||
|
lon: 8.9876,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
node1.add_tag("name", "a");
|
||||||
|
node2.add_tag("name", "b");
|
||||||
|
osm_db.add_node(node1.clone());
|
||||||
|
osm_db.add_node(node2.clone());
|
||||||
|
|
||||||
|
let mut way = OSMWay {
|
||||||
|
id: 890,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
way.nodes.push(node1);
|
||||||
|
way.nodes.push(node2);
|
||||||
|
|
||||||
|
osm_db.add_way(way);
|
||||||
|
|
||||||
|
let actual = osm_db.to_xml();
|
||||||
|
let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<osm generator=\"osrm-test\" version=\"0.6\">\n\t<node id=\"123\" version=\"1.0\" user=\"osrm\" timestamp=\"2000-01-01T00:00:00Z\" lon=\"8.9876\" lat=\"50.1234\">\n\t\t<tag name=\"a\" />\n\t</node>\n\t<node id=\"321\" version=\"1.0\" user=\"osrm\" timestamp=\"2000-01-01T00:00:00Z\" lon=\"8.9876\" lat=\"50.1234\">\n\t\t<tag name=\"b\" />\n\t</node>\n\t<way id=\"890\" version=\"1\" uid=\"1\" user=\"osrm\" timestamp=\"2000-01-01T00:00:00Z\">\n\t\t<nd ref=\"123\" />\n\t\t<nd ref=\"321\" />\n\t</way>\n</osm>\n";
|
||||||
|
|
||||||
|
println!("{actual}");
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
}
|
64
tests/common/osrm_world.rs
Normal file
64
tests/common/osrm_world.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use std::{collections::{HashMap, HashSet}, fs::File, path::PathBuf};
|
||||||
|
use crate::Point;
|
||||||
|
use cucumber::World;
|
||||||
|
|
||||||
|
use super::{osm::OSMNode, osm_db::OSMDb};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, World)]
|
||||||
|
pub struct OSRMWorld {
|
||||||
|
pub feature_path: Option<PathBuf>,
|
||||||
|
pub scenario_id: String,
|
||||||
|
pub feature_digest: String,
|
||||||
|
pub osrm_digest: String,
|
||||||
|
pub osm_id: u64,
|
||||||
|
pub profile: String,
|
||||||
|
|
||||||
|
pub known_osm_nodes: HashSet<char>,
|
||||||
|
pub known_locations: HashMap<char, Point>,
|
||||||
|
|
||||||
|
pub osm_db: OSMDb,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OSRMWorld {
|
||||||
|
pub fn set_scenario_specific_paths_and_digests(&mut self, path: Option<PathBuf>) {
|
||||||
|
self.feature_path.clone_from(&path);
|
||||||
|
|
||||||
|
let file = File::open(path.clone().unwrap())
|
||||||
|
.unwrap_or_else(|_| panic!("filesystem broken? can't open file {:?}", path));
|
||||||
|
self.feature_digest = chksum_md5::chksum(file)
|
||||||
|
.expect("md5 could not be computed")
|
||||||
|
.to_hex_lowercase();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_osm_id(&mut self) -> u64 {
|
||||||
|
// number implicitly starts a 1. This is in line with previous implementations
|
||||||
|
self.osm_id += 1;
|
||||||
|
self.osm_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_osm_node(&mut self, name: char, location: Point, id: Option<u64>) {
|
||||||
|
if self.known_osm_nodes.contains(&name) {
|
||||||
|
panic!("duplicate node: {name}");
|
||||||
|
}
|
||||||
|
let id = match id {
|
||||||
|
Some(id) => id,
|
||||||
|
None => self.make_osm_id(),
|
||||||
|
};
|
||||||
|
let node = OSMNode {
|
||||||
|
id,
|
||||||
|
lat: location.y(),
|
||||||
|
lon: location.x(),
|
||||||
|
tags: HashMap::from([("name".to_string(), name.to_string())]),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.known_osm_nodes.insert(name);
|
||||||
|
self.osm_db.add_node(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_location(&mut self, name: char, location: Point) {
|
||||||
|
if self.known_locations.contains_key(&name) {
|
||||||
|
panic!("duplicate location: {name}")
|
||||||
|
}
|
||||||
|
self.known_locations.insert(name, location);
|
||||||
|
}
|
||||||
|
}
|
@ -3,80 +3,20 @@ extern crate clap;
|
|||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::fs::{create_dir_all, File};
|
use std::fs::{create_dir_all, File};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
use crate::common::osrm_world::OSRMWorld;
|
||||||
use cheap_ruler::CheapRuler;
|
use cheap_ruler::CheapRuler;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use common::lexicographic_file_walker::LexicographicFileWalker;
|
use common::lexicographic_file_walker::LexicographicFileWalker;
|
||||||
use common::osm::{OSMDb, OSMNode, OSMWay};
|
use common::osm::OSMWay;
|
||||||
use cucumber::{self, gherkin::Step, given, when, World};
|
use cucumber::{self, gherkin::Step, given, when, World};
|
||||||
use futures::{future, FutureExt};
|
use futures::{future, FutureExt};
|
||||||
use geo_types::{point, Point};
|
use geo_types::{point, Point};
|
||||||
|
|
||||||
#[derive(Debug, Default, World)]
|
|
||||||
struct OSRMWorld {
|
|
||||||
feature_path: Option<PathBuf>,
|
|
||||||
scenario_id: String,
|
|
||||||
feature_digest: String,
|
|
||||||
osrm_digest: String,
|
|
||||||
osm_id: u64,
|
|
||||||
profile: String,
|
|
||||||
|
|
||||||
known_osm_nodes: HashSet<char>,
|
|
||||||
known_locations: HashMap<char, Point>,
|
|
||||||
|
|
||||||
osm_db: OSMDb,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OSRMWorld {
|
|
||||||
fn set_scenario_specific_paths_and_digests(&mut self, path: Option<PathBuf>) {
|
|
||||||
self.feature_path.clone_from(&path);
|
|
||||||
|
|
||||||
let file = File::open(path.clone().unwrap())
|
|
||||||
.unwrap_or_else(|_| panic!("filesystem broken? can't open file {:?}", path));
|
|
||||||
self.feature_digest = chksum_md5::chksum(file)
|
|
||||||
.expect("md5 could not be computed")
|
|
||||||
.to_hex_lowercase();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_osm_id(&mut self) -> u64 {
|
|
||||||
// number implicitly starts a 1. This is in line with previous implementations
|
|
||||||
self.osm_id += 1;
|
|
||||||
self.osm_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_osm_node(&mut self, name: char, location: Point, id: Option<u64>) {
|
|
||||||
if self.known_osm_nodes.contains(&name) {
|
|
||||||
panic!("duplicate node: {name}");
|
|
||||||
}
|
|
||||||
let id = match id {
|
|
||||||
Some(id) => id,
|
|
||||||
None => self.make_osm_id(),
|
|
||||||
};
|
|
||||||
let node = OSMNode {
|
|
||||||
id,
|
|
||||||
lat: location.y(),
|
|
||||||
lon: location.x(),
|
|
||||||
tags: HashMap::from([("name".to_string(), name.to_string())]),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.known_osm_nodes.insert(name);
|
|
||||||
self.osm_db.add_node(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_location(&mut self, name: char, location: Point) {
|
|
||||||
if self.known_locations.contains_key(&name) {
|
|
||||||
panic!("duplicate location: {name}")
|
|
||||||
}
|
|
||||||
self.known_locations.insert(name, location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_ORIGIN: [f64; 2] = [1., 1.]; // TODO: move to world?
|
const DEFAULT_ORIGIN: [f64; 2] = [1., 1.]; // TODO: move to world?
|
||||||
const DEFAULT_GRID_SIZE: f64 = 100.; // TODO: move to world?
|
const DEFAULT_GRID_SIZE: f64 = 100.; // TODO: move to world?
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user