mirror of https://codeberg.org/topola/topola.git
Implement `AstarStrategy` trait to not borrow A* context multiple times
This commit is contained in:
parent
b5f9a5957a
commit
bea6d84878
28
src/astar.rs
28
src/astar.rs
|
|
@ -96,19 +96,25 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn astar<G, F, H, K, Reroute>(
|
||||
pub trait AstarStrategy<G, K>
|
||||
where
|
||||
G: IntoEdges + Visitable,
|
||||
K: Measure + Copy,
|
||||
G::NodeId: Eq + Hash,
|
||||
{
|
||||
fn reroute(&mut self, node: G::NodeId, tracker: &PathTracker<G>) -> Option<K>;
|
||||
fn edge_cost(&mut self, edge: G::EdgeRef) -> K;
|
||||
fn estimate_cost(&mut self, node: G::NodeId) -> K;
|
||||
}
|
||||
|
||||
pub fn astar<G, K>(
|
||||
graph: G,
|
||||
start: G::NodeId,
|
||||
mut reroute: Reroute,
|
||||
mut edge_cost: F,
|
||||
mut estimate_cost: H,
|
||||
strategy: &mut impl AstarStrategy<G, K>,
|
||||
) -> Option<(K, Vec<G::NodeId>)>
|
||||
where
|
||||
G: IntoEdges + Visitable,
|
||||
Reroute: FnMut(G::NodeId, &PathTracker<G>) -> Option<K>,
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<u64> {
|
||||
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(())
|
||||
|
|
|
|||
Loading…
Reference in New Issue