pub mod graph;
use crate::road_network::types::RoadNetwork;
use geo::Point;
use petgraph::algo::dijkstra;
use std::collections::HashMap;
use std::sync::{LazyLock, Mutex};
pub use graph::NetworkGraph;
type RouteKey = (u64, u64); type RouteCache = HashMap<RouteKey, Option<f64>>;
static ROUTE_CACHE: LazyLock<Mutex<RouteCache>> =
LazyLock::new(|| Mutex::new(HashMap::new()));
pub fn calculate_route_distance(
network: &RoadNetwork,
start_point: Point<f64>,
end_point: Point<f64>,
) -> Option<f64> {
let cache_key = create_cache_key(start_point, end_point);
if let Ok(cache) = ROUTE_CACHE.lock() {
if let Some(&cached_result) = cache.get(&cache_key) {
return cached_result;
}
}
let graph = NetworkGraph::from_road_network(network);
calculate_route_distance_with_graph(&graph, start_point, end_point)
}
pub fn calculate_route_distance_with_graph(
graph: &NetworkGraph,
start_point: Point<f64>,
end_point: Point<f64>,
) -> Option<f64> {
let cache_key = create_cache_key(start_point, end_point);
if let Ok(cache) = ROUTE_CACHE.lock() {
if let Some(&cached_result) = cache.get(&cache_key) {
return cached_result;
}
}
let start_node = graph.find_closest_node(start_point)?;
let end_node = graph.find_closest_node(end_point)?;
let distances = dijkstra(&graph.graph, start_node, Some(end_node), |edge_ref| {
edge_ref.weight().length
});
let result = distances.get(&end_node).copied();
cache_result(cache_key, result);
result
}
pub fn clear_route_cache() {
if let Ok(mut cache) = ROUTE_CACHE.lock() {
cache.clear();
}
}
fn create_cache_key(start_point: Point<f64>, end_point: Point<f64>) -> RouteKey {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
let start_x = (start_point.x() * 1e6).round() as i64;
let start_y = (start_point.y() * 1e6).round() as i64;
start_x.hash(&mut hasher);
start_y.hash(&mut hasher);
let start_hash = hasher.finish();
let mut hasher = DefaultHasher::new();
let end_x = (end_point.x() * 1e6).round() as i64;
let end_y = (end_point.y() * 1e6).round() as i64;
end_x.hash(&mut hasher);
end_y.hash(&mut hasher);
let end_hash = hasher.finish();
(start_hash, end_hash)
}
fn cache_result(cache_key: RouteKey, result: Option<f64>) {
if let Ok(mut cache) = ROUTE_CACHE.lock() {
if cache.len() > 1000 {
cache.clear();
}
cache.insert(cache_key, result);
}
}