router: improve error handling -- more error types, remove some unwraps

This commit is contained in:
Mikolaj Wielgus 2024-05-29 23:49:24 +02:00
parent af9cbeba61
commit a4503a42c6
4 changed files with 61 additions and 43 deletions

View File

@ -22,7 +22,7 @@ use crate::{
rules::RulesTrait, rules::RulesTrait,
}, },
layout::{Layout, NodeIndex}, layout::{Layout, NodeIndex},
router::{navmesh::Navmesh, Router, RouterObserverTrait, RoutingError}, router::{navmesh::Navmesh, Router, RouterError, RouterObserverTrait},
triangulation::GetVertexIndex, triangulation::GetVertexIndex,
}; };
@ -73,12 +73,12 @@ impl Autoroute {
(None, None) (None, None)
}; };
let router = Router::new_from_navmesh( let mut router = Router::new_from_navmesh(
&mut autorouter.layout, &mut autorouter.layout,
std::mem::replace(&mut self.navmesh, new_navmesh).unwrap(), std::mem::replace(&mut self.navmesh, new_navmesh).unwrap(),
); );
let Ok(band) = router.unwrap().route_band(100.0, observer) else { let Ok(band) = router.route_band(100.0, observer) else {
return false; return false;
}; };

View File

@ -11,6 +11,7 @@ use std::hash::Hash;
use petgraph::algo::Measure; use petgraph::algo::Measure;
use petgraph::visit::{EdgeRef, GraphBase, IntoEdges}; use petgraph::visit::{EdgeRef, GraphBase, IntoEdges};
use thiserror::Error;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -105,7 +106,7 @@ where
fn estimate_cost(&mut self, node: G::NodeId) -> K; fn estimate_cost(&mut self, node: G::NodeId) -> K;
} }
struct Astar<G, K> pub struct Astar<G, K>
where where
G: IntoEdges, G: IntoEdges,
G::NodeId: Eq + Hash, G::NodeId: Eq + Hash,
@ -118,15 +119,21 @@ where
pub path_tracker: PathTracker<G>, pub path_tracker: PathTracker<G>,
} }
enum AstarStatus<G, K, R> #[derive(Error, Debug, Clone)]
pub enum AstarError {
#[error("A* search found no path")]
NotFound,
}
pub enum AstarStatus<G, K, R>
where where
G: IntoEdges, G: IntoEdges,
G::NodeId: Eq + Hash, G::NodeId: Eq + Hash,
K: Measure + Copy, K: Measure + Copy,
{ {
Running, Running,
Success(K, Vec<G::NodeId>, R), Finished(K, Vec<G::NodeId>, R),
Failure, Error(AstarError),
} }
impl<G, K> Astar<G, K> impl<G, K> Astar<G, K>
@ -153,13 +160,13 @@ where
pub fn step<R>(&mut self, strategy: &mut impl AstarStrategy<G, K, R>) -> AstarStatus<G, K, R> { pub fn step<R>(&mut self, strategy: &mut impl AstarStrategy<G, K, R>) -> AstarStatus<G, K, R> {
let Some(MinScored(estimate_score, node)) = self.visit_next.pop() else { let Some(MinScored(estimate_score, node)) = self.visit_next.pop() else {
return AstarStatus::Failure; return AstarStatus::Error(AstarError::NotFound);
}; };
if let Some(result) = strategy.is_goal(node, &self.path_tracker) { if let Some(result) = strategy.is_goal(node, &self.path_tracker) {
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 AstarStatus::Success(cost, path, result); return AstarStatus::Finished(cost, path, result);
} }
// This lookup can be unwrapped without fear of panic since the node was // This lookup can be unwrapped without fear of panic since the node was
@ -213,7 +220,7 @@ pub fn astar<G, K, R>(
graph: G, graph: G,
start: G::NodeId, start: G::NodeId,
strategy: &mut impl AstarStrategy<G, K, R>, strategy: &mut impl AstarStrategy<G, K, R>,
) -> Option<(K, Vec<G::NodeId>, R)> ) -> Result<(K, Vec<G::NodeId>, R), AstarError>
where where
G: IntoEdges, G: IntoEdges,
G::NodeId: Eq + Hash, G::NodeId: Eq + Hash,
@ -221,9 +228,17 @@ where
{ {
let mut astar = Astar::new(graph, start, strategy); let mut astar = Astar::new(graph, start, strategy);
while let AstarStatus::Running = astar.step(strategy) { loop {
// let status = astar.step(strategy);
}
None /*if !matches!(status, AstarStatus::Running) {
return status;
}*/
match status {
AstarStatus::Running => (),
AstarStatus::Finished(cost, path, band) => return Ok((cost, path, band)),
AstarStatus::Error(err) => return Err(err),
}
}
} }

View File

@ -6,6 +6,7 @@ use itertools::Itertools;
use petgraph::visit::{self, NodeIndexable}; use petgraph::visit::{self, NodeIndexable};
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef}; use petgraph::{stable_graph::NodeIndex, visit::EdgeRef};
use spade::{HasPosition, InsertionError, Point2}; use spade::{HasPosition, InsertionError, Point2};
use thiserror::Error;
use crate::drawing::graph::{GetLayer, GetMaybeNet}; use crate::drawing::graph::{GetLayer, GetMaybeNet};
use crate::geometry::shape::ShapeTrait; use crate::geometry::shape::ShapeTrait;
@ -85,12 +86,18 @@ pub struct Navmesh {
to: FixedDotIndex, to: FixedDotIndex,
} }
#[derive(Error, Debug, Clone)]
pub enum NavmeshError {
#[error("failed to insert vertex in navmesh")]
Insertion(#[from] InsertionError),
}
impl Navmesh { impl Navmesh {
pub fn new( pub fn new(
layout: &Layout<impl RulesTrait>, layout: &Layout<impl RulesTrait>,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
) -> Result<Self, InsertionError> { ) -> Result<Self, NavmeshError> {
let mut this = Self { let mut this = Self {
triangulation: Triangulation::new(layout.drawing().geometry().graph().node_bound()), triangulation: Triangulation::new(layout.drawing().geometry().graph().node_bound()),
vertex_to_triangulation_vertex: Vec::new(), vertex_to_triangulation_vertex: Vec::new(),

View File

@ -6,31 +6,28 @@ use petgraph::visit::EdgeRef;
use spade::InsertionError; use spade::InsertionError;
use thiserror::Error; use thiserror::Error;
use crate::drawing::band::BandIndex;
use crate::drawing::graph::{GetLayer, GetMaybeNet};
use crate::drawing::guide::HeadTrait;
use crate::geometry::primitive::PrimitiveShapeTrait;
use crate::layout::Layout;
use crate::{ use crate::{
drawing::{ drawing::{
band::BandIndex,
dot::FixedDotIndex, dot::FixedDotIndex,
graph::{MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
guide::HeadTrait,
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::RulesTrait, rules::RulesTrait,
}, },
geometry::shape::ShapeTrait, geometry::shape::ShapeTrait,
layout::Layout,
router::{
astar::{astar, AstarError, AstarStrategy, PathTracker},
draw::DrawException,
navmesh::{Navmesh, NavmeshEdgeReference, NavmeshError, VertexIndex},
tracer::{Trace, Tracer},
},
}; };
use crate::router::{ /*#[derive(Error, Debug, Clone, Copy)]
astar::{astar, AstarStrategy, PathTracker},
draw::DrawException,
navmesh::{Navmesh, NavmeshEdgeReference, VertexIndex},
tracer::{Trace, Tracer},
};
#[derive(Error, Debug, Clone, Copy)]
#[error("failed to route from {from:?} to {to:?}")] // this should eventually use Display #[error("failed to route from {from:?} to {to:?}")] // this should eventually use Display
pub struct RoutingError { pub struct RouterError {
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
source: RoutingErrorKind, source: RoutingErrorKind,
@ -44,6 +41,13 @@ pub enum RoutingErrorKind {
// TODO more descriptive message // TODO more descriptive message
#[error("A* found no path")] #[error("A* found no path")]
AStar, AStar,
}*/
#[derive(Error, Debug, Clone)]
#[error("routing failed")]
pub enum RouterError {
Navmesh(#[from] NavmeshError),
Astar(#[from] AstarError),
} }
pub trait RouterObserverTrait<R: RulesTrait> { pub trait RouterObserverTrait<R: RulesTrait> {
@ -169,26 +173,23 @@ impl<'a, R: RulesTrait> Router<'a, R> {
layout: &'a mut Arc<Mutex<Layout<R>>>, layout: &'a mut Arc<Mutex<Layout<R>>>,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
) -> Result<Self, InsertionError> { ) -> Result<Self, RouterError> {
let navmesh = { let navmesh = {
let layout = layout.lock().unwrap(); let layout = layout.lock().unwrap();
Navmesh::new(&layout, from, to)? Navmesh::new(&layout, from, to)?
}; };
Self::new_from_navmesh(layout, navmesh) Ok(Self::new_from_navmesh(layout, navmesh))
} }
pub fn new_from_navmesh( pub fn new_from_navmesh(layout: &'a mut Arc<Mutex<Layout<R>>>, navmesh: Navmesh) -> Self {
layout: &'a mut Arc<Mutex<Layout<R>>>, Self { layout, navmesh }
navmesh: Navmesh,
) -> Result<Self, InsertionError> {
Ok(Self { layout, navmesh })
} }
pub fn route_band( pub fn route_band(
&mut self, &mut self,
width: f64, width: f64,
observer: &mut impl RouterObserverTrait<R>, observer: &mut impl RouterObserverTrait<R>,
) -> Result<BandIndex, RoutingError> { ) -> Result<BandIndex, RouterError> {
let mut tracer = self.tracer(); let mut tracer = self.tracer();
let trace = tracer.start(self.navmesh.from(), width); let trace = tracer.start(self.navmesh.from(), width);
@ -196,12 +197,7 @@ impl<'a, R: RulesTrait> Router<'a, R> {
&self.navmesh, &self.navmesh,
self.navmesh.from().into(), self.navmesh.from().into(),
&mut RouterAstarStrategy::new(tracer, trace, self.navmesh.to(), observer), &mut RouterAstarStrategy::new(tracer, trace, self.navmesh.to(), observer),
) )?;
.ok_or(RoutingError {
from: self.navmesh.from(),
to: self.navmesh.to(),
source: RoutingErrorKind::AStar,
})?;
Ok(band) Ok(band)
} }