use log::{error, info};
use osmgraphing::{configs::Config, helpers, io::Parser, network::NodeIdx, routing};
use rand::{
distributions::{Distribution, Uniform},
SeedableRng,
};
use std::{path::PathBuf, time::Instant};
fn main() {
let matches = parse_cmdline();
match helpers::init_logging(matches.value_of("log").unwrap(), vec![]) {
Ok(_) => (),
Err(msg) => {
error!("{}", msg);
return;
}
};
info!("EXECUTE {}", env!("CARGO_PKG_NAME"));
let cfg = {
let cfg_file = PathBuf::from(matches.value_of("cfg").unwrap());
match Config::from_yaml(&cfg_file) {
Ok(cfg) => cfg,
Err(msg) => {
error!("{}", msg);
std::process::exit(1);
}
}
};
if let Some(cfg_routing) = &cfg.routing {
info!(
"EXECUTE Parse graph, then do routing with {} metric(s).",
cfg_routing.dim()
);
} else {
info!("EXECUTE Parse graph without routing.");
}
let now = Instant::now();
let graph = match Parser::parse_and_finalize(cfg.parser) {
Ok(graph) => graph,
Err(msg) => {
error!("{}", msg);
std::process::exit(1);
}
};
info!(
"Finished parsing in {} seconds ({} µs).",
now.elapsed().as_secs(),
now.elapsed().as_micros(),
);
info!("");
info!("{}", graph);
let cfg_routing = match cfg.routing {
Some(cfg_routing) => cfg_routing,
None => return,
};
let nodes = graph.nodes();
let mut dijkstra = routing::Dijkstra::new();
let route_count = 100;
let seed = 42;
let mut gen_route: Box<dyn FnMut() -> Option<(NodeIdx, NodeIdx)>> = {
if nodes.count() * nodes.count() <= route_count {
let mut i = 0;
let nodes = graph.nodes();
Box::new(move || {
if i < nodes.count() * nodes.count() {
let src_idx = NodeIdx(i / nodes.count());
let dst_idx = NodeIdx(i % nodes.count());
i += 1;
Some((src_idx, dst_idx))
} else {
None
}
})
} else {
let mut rng = rand_pcg::Pcg32::seed_from_u64(seed);
let die = Uniform::from(0..nodes.count());
let mut i = 0;
Box::new(move || {
if i < route_count {
let src_idx = NodeIdx(die.sample(&mut rng));
let dst_idx = NodeIdx(die.sample(&mut rng));
i += 1;
Some((src_idx, dst_idx))
} else {
None
}
})
}
};
while let Some((src_idx, dst_idx)) = gen_route() {
let src = nodes.create(src_idx);
let dst = nodes.create(dst_idx);
info!("");
let now = Instant::now();
let option_path = dijkstra.compute_best_path(&src, &dst, &graph, &cfg_routing);
info!(
"Ran Dijkstra-query in {} ms",
now.elapsed().as_micros() as f64 / 1_000.0,
);
if let Some(path) = option_path {
info!(
"Cost {:?} from ({}) to ({}).",
path.calc_cost(cfg_routing.metric_indices(), &graph),
src,
dst
);
} else {
info!("No path from ({}) to ({}).", src, dst);
}
}
}
fn parse_cmdline<'a>() -> clap::ArgMatches<'a> {
let tmp = &[
"Sets the logging-level by setting environment-variable 'RUST_LOG'.",
"The env-variable 'RUST_LOG' has precedence.",
"It takes values of modules, e.g.",
"export RUST_LOG='warn,osmgraphing=info'",
"for getting warn's by default, but 'info' about the others",
]
.join("\n");
let arg_log_level = clap::Arg::with_name("log")
.long("log")
.short("l")
.value_name("FILTER-LEVEL")
.help(tmp)
.takes_value(true)
.required(false)
.default_value("INFO")
.possible_values(&vec!["TRACE", "DEBUG", "INFO", "WARN", "ERROR"]);
let arg_cfg_file = clap::Arg::with_name("cfg")
.long("config")
.short("c")
.value_name("PATH")
.help("Sets the parser and routing according to this config.")
.takes_value(true)
.required(true);
clap::App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.author(env!("CARGO_PKG_AUTHORS"))
.about(env!("CARGO_PKG_DESCRIPTION"))
.long_about(
(&[
"",
"This tool takes a config-file, parses the chosen graph with specified",
"settings, and executes some routing-queries (if provided in config-file).",
]
.join("\n"))
.as_ref(),
)
.arg(arg_log_level)
.arg(arg_cfg_file)
.get_matches()
}