mirror of https://codeberg.org/topola/topola.git
fix(router/astar): Do not panic if navnode visit fails, just skip it
I have renamed some trait functions to make it clearer what they do, and clarified some comments.
This commit is contained in:
parent
24d119ad04
commit
e92864d58b
|
|
@ -103,8 +103,13 @@ where
|
||||||
for<'a> &'a G: IntoEdges<NodeId = G::NodeId, EdgeId = G::EdgeId> + MakeEdgeRef,
|
for<'a> &'a G: IntoEdges<NodeId = G::NodeId, EdgeId = G::EdgeId> + MakeEdgeRef,
|
||||||
K: Measure + Copy,
|
K: Measure + Copy,
|
||||||
{
|
{
|
||||||
fn is_goal(&mut self, graph: &G, node: G::NodeId, tracker: &PathTracker<G>) -> Option<R>;
|
fn visit_navnode(
|
||||||
fn place_probe<'a>(
|
&mut self,
|
||||||
|
graph: &G,
|
||||||
|
node: G::NodeId,
|
||||||
|
tracker: &PathTracker<G>,
|
||||||
|
) -> Result<Option<R>, ()>;
|
||||||
|
fn place_probe_at_navedge<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
graph: &'a G,
|
graph: &'a G,
|
||||||
edge: <&'a G as IntoEdgeReferences>::EdgeRef,
|
edge: <&'a G as IntoEdgeReferences>::EdgeRef,
|
||||||
|
|
@ -148,11 +153,11 @@ where
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AstarContinueStatus {
|
pub enum AstarContinueStatus {
|
||||||
/// A* has now placed a probe to measure the cost of the edge to a
|
/// A* has now placed a probe to measure the cost of the edge to a
|
||||||
/// neighboring node from the current position. The probed node has been
|
/// neighboring navnode from the current position. The probed navnode has
|
||||||
/// added to the priority queue, and the newly measured edge cost has been
|
/// been added to the priority queue, and the newly measured edge cost has
|
||||||
/// stored in a map.
|
/// been stored in a map.
|
||||||
Probing,
|
Probing,
|
||||||
/// A* has now placed a probe, but it turned out that the probed node has
|
/// A* has now placed a probe, but it turned out that the probed navnode has
|
||||||
/// been previously reached through a path with equal or lower score, so the
|
/// been previously reached through a path with equal or lower score, so the
|
||||||
/// probe's measurement has been discarded. The probe, however, will be only
|
/// probe's measurement has been discarded. The probe, however, will be only
|
||||||
/// removed in the next state just as if it was after the normal `Probing`
|
/// removed in the next state just as if it was after the normal `Probing`
|
||||||
|
|
@ -165,17 +170,20 @@ pub enum AstarContinueStatus {
|
||||||
/// to pause the A* while the placed probe exists, which is very useful
|
/// to pause the A* while the placed probe exists, which is very useful
|
||||||
/// for debugging.
|
/// for debugging.
|
||||||
Probed,
|
Probed,
|
||||||
/// A* has now attempted to visit a new node, but it turned out that it has
|
/// A* has now attempted to visit a new navnode, but it turned out that
|
||||||
/// been previously reached through a path with an equal or lower estimated
|
/// it has been previously reached through a path with an equal or lower
|
||||||
/// score, so the visit to that node has been skipped.
|
/// estimated score, so the visit to that navnode has been skipped.
|
||||||
VisitSkipped,
|
VisitSkipped,
|
||||||
/// A* has now visited a new node.
|
/// A* has failed to visit a new navnode. Happens, so A* will just proceed
|
||||||
|
/// to the next node in the priority queue.
|
||||||
|
VisitFailed,
|
||||||
|
/// A* has now visited a new navnode.
|
||||||
///
|
///
|
||||||
/// Quick recap if you have been trying to remember what is the difference
|
/// Quick recap if you have been trying to remember what is the difference
|
||||||
/// between probing and visiting: probing is done as part of a scan of
|
/// between probing and visiting: probing is done as part of a scan of
|
||||||
/// neighboring nodes around the currently visited node to add them to the
|
/// neighboring navnodes around the currently visited navnode to add them to
|
||||||
/// priority queue, whereas when a node is visited it actually *becomes* the
|
/// the priority queue, whereas when a navnode is visited it is taken from
|
||||||
/// currently visited node.
|
/// the priority queue to actually become the currently visited navnode.
|
||||||
Visited,
|
Visited,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,7 +246,7 @@ where
|
||||||
let node_score = self.scores[&curr_node];
|
let node_score = self.scores[&curr_node];
|
||||||
let edge = (&self.graph).edge_ref(edge_id);
|
let edge = (&self.graph).edge_ref(edge_id);
|
||||||
|
|
||||||
if let Some(edge_cost) = strategy.place_probe(&self.graph, edge) {
|
if let Some(edge_cost) = strategy.place_probe_at_navedge(&self.graph, edge) {
|
||||||
let next = edge.target();
|
let next = edge.target();
|
||||||
let next_score = node_score + edge_cost;
|
let next_score = node_score + edge_cost;
|
||||||
|
|
||||||
|
|
@ -277,7 +285,11 @@ where
|
||||||
return Err(AstarError::NotFound);
|
return Err(AstarError::NotFound);
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(result) = strategy.is_goal(&self.graph, node, &self.path_tracker) {
|
let Ok(maybe_result) = strategy.visit_navnode(&self.graph, node, &self.path_tracker) else {
|
||||||
|
return Ok(ControlFlow::Continue(AstarContinueStatus::VisitFailed));
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(result) = maybe_result {
|
||||||
let path = self.path_tracker.reconstruct_path_to(node);
|
let path = self.path_tracker.reconstruct_path_to(node);
|
||||||
let cost = self.scores[&node];
|
let cost = self.scores[&node];
|
||||||
return Ok(ControlFlow::Break((cost, path, result)));
|
return Ok(ControlFlow::Break((cost, path, result)));
|
||||||
|
|
|
||||||
|
|
@ -62,12 +62,12 @@ impl<'a, R> RouterAstarStrategy<'a, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: AccessRules> AstarStrategy<Navmesh, f64, BandTermsegIndex> for RouterAstarStrategy<'_, R> {
|
impl<R: AccessRules> AstarStrategy<Navmesh, f64, BandTermsegIndex> for RouterAstarStrategy<'_, R> {
|
||||||
fn is_goal(
|
fn visit_navnode(
|
||||||
&mut self,
|
&mut self,
|
||||||
navmesh: &Navmesh,
|
navmesh: &Navmesh,
|
||||||
vertex: NavnodeIndex,
|
vertex: NavnodeIndex,
|
||||||
tracker: &PathTracker<Navmesh>,
|
tracker: &PathTracker<Navmesh>,
|
||||||
) -> Option<BandTermsegIndex> {
|
) -> Result<Option<BandTermsegIndex>, ()> {
|
||||||
let new_path = tracker.reconstruct_path_to(vertex);
|
let new_path = tracker.reconstruct_path_to(vertex);
|
||||||
|
|
||||||
if vertex == navmesh.destination_navnode() {
|
if vertex == navmesh.destination_navnode() {
|
||||||
|
|
@ -84,16 +84,19 @@ impl<R: AccessRules> AstarStrategy<Navmesh, f64, BandTermsegIndex> for RouterAst
|
||||||
);
|
);
|
||||||
self.navcord.path.push(vertex);
|
self.navcord.path.push(vertex);
|
||||||
|
|
||||||
self.navcord.final_termseg
|
Ok(self.navcord.final_termseg)
|
||||||
} else {
|
} else {
|
||||||
self.layout
|
self.layout
|
||||||
.rework_path(navmesh, self.navcord, &new_path[..])
|
.rework_path(navmesh, self.navcord, &new_path[..])
|
||||||
.unwrap();
|
.map_or(Err(()), |_| Ok(None))
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place_probe(&mut self, navmesh: &Navmesh, edge: NavmeshEdgeReference) -> Option<f64> {
|
fn place_probe_at_navedge(
|
||||||
|
&mut self,
|
||||||
|
navmesh: &Navmesh,
|
||||||
|
edge: NavmeshEdgeReference,
|
||||||
|
) -> Option<f64> {
|
||||||
let old_head = self.navcord.head;
|
let old_head = self.navcord.head;
|
||||||
let result = self.navcord.step_to(self.layout, navmesh, edge.target());
|
let result = self.navcord.step_to(self.layout, navmesh, edge.target());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue