diff --git a/src/astar.rs b/src/astar.rs index f344771..31d7b22 100644 --- a/src/astar.rs +++ b/src/astar.rs @@ -96,19 +96,25 @@ where } } -pub fn astar( +pub trait AstarStrategy +where + G: IntoEdges + Visitable, + K: Measure + Copy, + G::NodeId: Eq + Hash, +{ + fn reroute(&mut self, node: G::NodeId, tracker: &PathTracker) -> Option; + fn edge_cost(&mut self, edge: G::EdgeRef) -> K; + fn estimate_cost(&mut self, node: G::NodeId) -> K; +} + +pub fn astar( graph: G, start: G::NodeId, - mut reroute: Reroute, - mut edge_cost: F, - mut estimate_cost: H, + strategy: &mut impl AstarStrategy, ) -> Option<(K, Vec)> where G: IntoEdges + Visitable, - Reroute: FnMut(G::NodeId, &PathTracker) -> Option, G::NodeId: Eq + Hash, - F: FnMut(G::EdgeRef) -> K, - H: FnMut(G::NodeId) -> K, K: Measure + Copy, { let mut visit_next = BinaryHeap::new(); @@ -118,10 +124,10 @@ where let zero_score = K::default(); scores.insert(start, zero_score); - visit_next.push(MinScored(estimate_cost(start), start)); + visit_next.push(MinScored(strategy.estimate_cost(start), start)); while let Some(MinScored(estimate_score, node)) = visit_next.pop() { - match reroute(node, &path_tracker) { + match strategy.reroute(node, &path_tracker) { None => { let path = path_tracker.reconstruct_path_to(node); let cost = scores[&node]; @@ -148,7 +154,7 @@ where for edge in graph.edges(node) { let next = edge.target(); - let next_score = node_score + route_cost + edge_cost(edge); + let next_score = node_score + route_cost + strategy.edge_cost(edge); match scores.entry(next) { Occupied(mut entry) => { @@ -165,7 +171,7 @@ where } path_tracker.set_predecessor(next, node); - let next_estimate_score = next_score + estimate_cost(next); + let next_estimate_score = next_score + strategy.estimate_cost(next); visit_next.push(MinScored(next_estimate_score, next)); } } diff --git a/src/router.rs b/src/router.rs index d4b816c..71952b3 100644 --- a/src/router.rs +++ b/src/router.rs @@ -2,7 +2,7 @@ use geo::geometry::Point; use petgraph::visit::{EdgeRef, IntoEdgeReferences}; use spade::InsertionError; -use crate::astar::astar; +use crate::astar::{astar, AstarStrategy, PathTracker}; use crate::bow::Bow; use crate::draw::{Draw, Head}; use crate::graph::{BendIndex, DotIndex, Ends, SegIndex, TaggedIndex}; @@ -11,8 +11,8 @@ use crate::guide::Guide; use crate::layout::Layout; use crate::math::Circle; -use crate::mesh::{Mesh, VertexIndex}; -use crate::route::Route; +use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex}; +use crate::route::{Route, Trace}; use crate::rules::{Conditions, Rules}; use crate::segbend::Segbend; @@ -21,6 +21,45 @@ pub struct Router { rules: Rules, } +pub struct DefaultAstarStrategy<'a> { + route: Route<'a>, + trace: Trace, + to: VertexIndex, +} + +impl<'a> DefaultAstarStrategy<'a> { + pub fn new(route: Route<'a>, trace: Trace, to: VertexIndex) -> Self { + Self { route, trace, to } + } +} + +impl<'a> AstarStrategy<&Mesh, u64> for DefaultAstarStrategy<'a> { + fn reroute(&mut self, vertex: VertexIndex, tracker: &PathTracker<&Mesh>) -> Option { + let new_path = tracker.reconstruct_path_to(vertex); + + if vertex == self.to { + self.route + .rework_path(&mut self.trace, &new_path[..new_path.len() - 1], 5.0) + .ok(); + self.route + .finish(&mut self.trace, new_path[new_path.len() - 1], 5.0) + .ok(); + None + } else { + self.route.rework_path(&mut self.trace, &new_path, 5.0).ok(); + Some(0) + } + } + + fn edge_cost(&mut self, edge: MeshEdgeReference) -> u64 { + 1 + } + + fn estimate_cost(&mut self, vertex: VertexIndex) -> u64 { + 0 + } +} + impl Router { pub fn new() -> Self { Router { @@ -37,29 +76,12 @@ impl Router { mesh.triangulate(&self.layout)?; let mut route = self.route(&mesh); - let mut trace = route.start(mesh.vertex(from)); + let trace = route.start(mesh.vertex(from)); let (_cost, path) = astar( &mesh, mesh.vertex(from), - |node, tracker| { - let new_path = tracker.reconstruct_path_to(node); - - if node == mesh.vertex(to) { - route - .rework_path(&mut trace, &new_path[..new_path.len() - 1], 5.0) - .ok(); - route - .finish(&mut trace, new_path[new_path.len() - 1], 5.0) - .ok(); - None - } else { - route.rework_path(&mut trace, &new_path, 5.0).ok(); - Some(0) - } - }, - |_edge| 1, - |_| 0, + &mut DefaultAstarStrategy::new(route, trace, mesh.vertex(to)), ) .unwrap(); // TODO. Ok(())