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,
|
graph: G,
|
||||||
start: G::NodeId,
|
start: G::NodeId,
|
||||||
mut reroute: Reroute,
|
strategy: &mut impl AstarStrategy<G, K>,
|
||||||
mut edge_cost: F,
|
|
||||||
mut estimate_cost: H,
|
|
||||||
) -> Option<(K, Vec<G::NodeId>)>
|
) -> Option<(K, Vec<G::NodeId>)>
|
||||||
where
|
where
|
||||||
G: IntoEdges + Visitable,
|
G: IntoEdges + Visitable,
|
||||||
Reroute: FnMut(G::NodeId, &PathTracker<G>) -> Option<K>,
|
|
||||||
G::NodeId: Eq + Hash,
|
G::NodeId: Eq + Hash,
|
||||||
F: FnMut(G::EdgeRef) -> K,
|
|
||||||
H: FnMut(G::NodeId) -> K,
|
|
||||||
K: Measure + Copy,
|
K: Measure + Copy,
|
||||||
{
|
{
|
||||||
let mut visit_next = BinaryHeap::new();
|
let mut visit_next = BinaryHeap::new();
|
||||||
|
|
@ -118,10 +124,10 @@ where
|
||||||
|
|
||||||
let zero_score = K::default();
|
let zero_score = K::default();
|
||||||
scores.insert(start, zero_score);
|
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() {
|
while let Some(MinScored(estimate_score, node)) = visit_next.pop() {
|
||||||
match reroute(node, &path_tracker) {
|
match strategy.reroute(node, &path_tracker) {
|
||||||
None => {
|
None => {
|
||||||
let path = path_tracker.reconstruct_path_to(node);
|
let path = path_tracker.reconstruct_path_to(node);
|
||||||
let cost = scores[&node];
|
let cost = scores[&node];
|
||||||
|
|
@ -148,7 +154,7 @@ where
|
||||||
|
|
||||||
for edge in graph.edges(node) {
|
for edge in graph.edges(node) {
|
||||||
let next = edge.target();
|
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) {
|
match scores.entry(next) {
|
||||||
Occupied(mut entry) => {
|
Occupied(mut entry) => {
|
||||||
|
|
@ -165,7 +171,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
path_tracker.set_predecessor(next, node);
|
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));
|
visit_next.push(MinScored(next_estimate_score, next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use geo::geometry::Point;
|
||||||
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
|
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
|
||||||
use spade::InsertionError;
|
use spade::InsertionError;
|
||||||
|
|
||||||
use crate::astar::astar;
|
use crate::astar::{astar, AstarStrategy, PathTracker};
|
||||||
use crate::bow::Bow;
|
use crate::bow::Bow;
|
||||||
use crate::draw::{Draw, Head};
|
use crate::draw::{Draw, Head};
|
||||||
use crate::graph::{BendIndex, DotIndex, Ends, SegIndex, TaggedIndex};
|
use crate::graph::{BendIndex, DotIndex, Ends, SegIndex, TaggedIndex};
|
||||||
|
|
@ -11,8 +11,8 @@ use crate::guide::Guide;
|
||||||
use crate::layout::Layout;
|
use crate::layout::Layout;
|
||||||
|
|
||||||
use crate::math::Circle;
|
use crate::math::Circle;
|
||||||
use crate::mesh::{Mesh, VertexIndex};
|
use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
|
||||||
use crate::route::Route;
|
use crate::route::{Route, Trace};
|
||||||
use crate::rules::{Conditions, Rules};
|
use crate::rules::{Conditions, Rules};
|
||||||
use crate::segbend::Segbend;
|
use crate::segbend::Segbend;
|
||||||
|
|
||||||
|
|
@ -21,6 +21,45 @@ pub struct Router {
|
||||||
rules: Rules,
|
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 {
|
impl Router {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Router {
|
Router {
|
||||||
|
|
@ -37,29 +76,12 @@ impl Router {
|
||||||
mesh.triangulate(&self.layout)?;
|
mesh.triangulate(&self.layout)?;
|
||||||
|
|
||||||
let mut route = self.route(&mesh);
|
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(
|
let (_cost, path) = astar(
|
||||||
&mesh,
|
&mesh,
|
||||||
mesh.vertex(from),
|
mesh.vertex(from),
|
||||||
|node, tracker| {
|
&mut DefaultAstarStrategy::new(route, trace, mesh.vertex(to)),
|
||||||
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,
|
|
||||||
)
|
)
|
||||||
.unwrap(); // TODO.
|
.unwrap(); // TODO.
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue