diff --git a/src/autorouter/autoroute.rs b/src/autorouter/autoroute.rs index 52e752c..fc231c1 100644 --- a/src/autorouter/autoroute.rs +++ b/src/autorouter/autoroute.rs @@ -1,14 +1,16 @@ use petgraph::graph::EdgeIndex; use crate::{ - autorouter::{ - invoker::{GetMaybeNavmesh, GetMaybeTrace}, - Autorouter, AutorouterError, AutorouterStatus, - }, board::mesadata::AccessMesadata, + geometry::primitive::PrimitiveShape, router::{navmesh::Navmesh, route::Route, trace::Trace, Router, RouterStatus}, }; +use super::{ + invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace}, + Autorouter, AutorouterError, AutorouterStatus, +}; + pub struct Autoroute { ratlines_iter: Box>>, route: Option, @@ -83,14 +85,6 @@ impl Autoroute { Ok(AutorouterStatus::Running) } - - pub fn navmesh(&self) -> Option<&Navmesh> { - self.route.as_ref().map(|route| route.navmesh()) - } - - pub fn trace(&self) -> Option<&Trace> { - self.route.as_ref().map(|route| route.trace()) - } } impl GetMaybeNavmesh for Autoroute { @@ -104,3 +98,9 @@ impl GetMaybeTrace for Autoroute { self.route.as_ref().map(|route| route.trace()) } } + +impl GetGhosts for Autoroute { + fn ghosts(&self) -> &[PrimitiveShape] { + self.route.as_ref().map_or(&[], |route| route.ghosts()) + } +} diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index e019da3..67d5adf 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -12,6 +12,8 @@ use crate::{ Autorouter, AutorouterError, AutorouterStatus, }, board::mesadata::AccessMesadata, + drawing::graph::PrimitiveIndex, + geometry::primitive::PrimitiveShape, layout::via::ViaWeight, router::{navmesh::Navmesh, trace::Trace}, }; @@ -26,6 +28,11 @@ pub trait GetMaybeTrace { fn maybe_trace(&self) -> Option<&Trace>; } +#[enum_dispatch] +pub trait GetGhosts { + fn ghosts(&self) -> &[PrimitiveShape]; +} + #[derive(Error, Debug, Clone)] pub enum InvokerError { #[error(transparent)] @@ -46,7 +53,7 @@ pub enum Command { PlaceVia(ViaWeight), } -#[enum_dispatch(GetMaybeNavmesh, GetMaybeTrace)] +#[enum_dispatch(GetMaybeNavmesh, GetMaybeTrace, GetGhosts)] pub enum Execute { Autoroute(Autoroute), PlaceVia(PlaceVia), @@ -129,6 +136,12 @@ impl GetMaybeTrace for ExecuteWithStatus { } } +impl GetGhosts for ExecuteWithStatus { + fn ghosts(&self) -> &[PrimitiveShape] { + self.execute.ghosts() + } +} + pub struct Invoker { autorouter: Autorouter, history: History, diff --git a/src/autorouter/place_via.rs b/src/autorouter/place_via.rs index 2f10b59..ed151ec 100644 --- a/src/autorouter/place_via.rs +++ b/src/autorouter/place_via.rs @@ -1,13 +1,16 @@ use crate::{ - autorouter::{ - invoker::{GetMaybeNavmesh, GetMaybeTrace}, - Autorouter, AutorouterError, - }, board::mesadata::AccessMesadata, + drawing::graph::PrimitiveIndex, + geometry::primitive::PrimitiveShape, layout::via::ViaWeight, router::{navmesh::Navmesh, trace::Trace}, }; +use super::{ + invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace}, + Autorouter, AutorouterError, +}; + #[derive(Debug)] pub struct PlaceVia { weight: ViaWeight, @@ -37,3 +40,9 @@ impl GetMaybeTrace for PlaceVia { None } } + +impl GetGhosts for PlaceVia { + fn ghosts(&self) -> &[PrimitiveShape] { + &[] + } +} diff --git a/src/bin/topola-egui/viewport.rs b/src/bin/topola-egui/viewport.rs index 6fc83dd..8022688 100644 --- a/src/bin/topola-egui/viewport.rs +++ b/src/bin/topola-egui/viewport.rs @@ -4,7 +4,9 @@ use petgraph::{ visit::{EdgeRef, IntoEdgeReferences}, }; use topola::{ - autorouter::invoker::{Command, ExecuteWithStatus, GetMaybeNavmesh, GetMaybeTrace, Invoker}, + autorouter::invoker::{ + Command, ExecuteWithStatus, GetGhosts, GetMaybeNavmesh, GetMaybeTrace, Invoker, + }, board::mesadata::AccessMesadata, drawing::{ graph::{MakePrimitive, PrimitiveIndex}, @@ -213,11 +215,11 @@ impl Viewport { } } - /*for ghost in shared_data.ghosts.iter() { - painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150)); - }*/ - if let Some(execute) = maybe_execute { + for ghost in execute.ghosts().iter() { + painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150)); + } + if let Some(navmesh) = execute.maybe_navmesh() { if let (origin, destination) = (navmesh.origin(), navmesh.destination()) { painter.paint_dot( diff --git a/src/router/astar.rs b/src/router/astar.rs index eca12bf..a2a954a 100644 --- a/src/router/astar.rs +++ b/src/router/astar.rs @@ -96,7 +96,7 @@ where } } -pub trait AstarStrategy +pub trait AstarStrategy where G: GraphBase, G::NodeId: Eq + Hash, @@ -108,7 +108,7 @@ where &mut self, graph: &'a G, edge: <&'a G as IntoEdgeReferences>::EdgeRef, - ) -> Result<(K, PS), PE>; + ) -> Option; fn estimate_cost(&mut self, graph: &G, node: G::NodeId) -> K; } @@ -140,14 +140,14 @@ pub enum AstarError { } #[derive(Debug)] -pub enum AstarStatus +pub enum AstarStatus where G: GraphBase, G::NodeId: Eq + Hash, for<'a> &'a G: IntoEdges + MakeEdgeRef, K: Measure + Copy, { - Probed(Result), + Probed, Visited, Finished(K, Vec, R), } @@ -159,11 +159,7 @@ where for<'a> &'a G: IntoEdges + MakeEdgeRef, K: Measure + Copy, { - pub fn new( - graph: G, - start: G::NodeId, - strategy: &mut impl AstarStrategy, - ) -> Self { + pub fn new(graph: G, start: G::NodeId, strategy: &mut impl AstarStrategy) -> Self { let mut this = Self { graph, visit_next: BinaryHeap::new(), @@ -183,10 +179,10 @@ where this } - pub fn step( + pub fn step( &mut self, - strategy: &mut impl AstarStrategy, - ) -> Result, AstarError> { + strategy: &mut impl AstarStrategy, + ) -> Result, AstarError> { if let Some(curr_node) = self.maybe_curr_node { if let Some(edge_id) = self.edge_ids.pop_front() { // This lookup can be unwrapped without fear of panic since the node was @@ -194,37 +190,34 @@ where let node_score = self.scores[&curr_node]; let edge = (&self.graph).edge_ref(edge_id); - match strategy.probe(&self.graph, edge) { - Ok((edge_cost, probe_status)) => { - let next = edge.target(); - let next_score = node_score + edge_cost; + if let Some(edge_cost) = strategy.probe(&self.graph, edge) { + let next = edge.target(); + let next_score = node_score + edge_cost; - match self.scores.entry(next) { - Occupied(mut entry) => { - // No need to add neighbors that we have already reached through a - // shorter path than now. - if *entry.get() <= next_score { - return Ok(AstarStatus::Probed(Ok(probe_status))); - } - entry.insert(next_score); - } - Vacant(entry) => { - entry.insert(next_score); + match self.scores.entry(next) { + Occupied(mut entry) => { + // No need to add neighbors that we have already reached through a + // shorter path than now. + if *entry.get() <= next_score { + return Ok(AstarStatus::Probed); } + entry.insert(next_score); + } + Vacant(entry) => { + entry.insert(next_score); } - - self.path_tracker.set_predecessor(next, curr_node); - let next_estimate_score = - next_score + strategy.estimate_cost(&self.graph, next); - self.visit_next.push(MinScored(next_estimate_score, next)); - - return Ok(AstarStatus::Probed(Ok(probe_status))); } - Err(probe_err) => return Ok(AstarStatus::Probed(Err(probe_err))), + + self.path_tracker.set_predecessor(next, curr_node); + let next_estimate_score = + next_score + strategy.estimate_cost(&self.graph, next); + self.visit_next.push(MinScored(next_estimate_score, next)); } - } else { - self.maybe_curr_node = None; + + return Ok(AstarStatus::Probed); } + + self.maybe_curr_node = None; } let Some(MinScored(estimate_score, node)) = self.visit_next.pop() else { @@ -258,10 +251,10 @@ where } } -pub fn astar( +pub fn astar( graph: G, start: G::NodeId, - strategy: &mut impl AstarStrategy, + strategy: &mut impl AstarStrategy, ) -> Result<(K, Vec, R), AstarError> where G: GraphBase, diff --git a/src/router/route.rs b/src/router/route.rs index 7490d94..982d2a4 100644 --- a/src/router/route.rs +++ b/src/router/route.rs @@ -14,7 +14,10 @@ use crate::{ primitive::MakePrimitiveShape, rules::AccessRules, }, - geometry::{primitive::AccessPrimitiveShape, shape::AccessShape}, + geometry::{ + primitive::{AccessPrimitiveShape, PrimitiveShape}, + shape::AccessShape, + }, graph::GetPetgraphIndex, layout::Layout, router::{ @@ -33,6 +36,7 @@ use crate::{ pub struct Route { astar: Astar, trace: Trace, + ghosts: Vec, } impl Route { @@ -60,8 +64,13 @@ impl Route { let mut strategy = RouterAstarStrategy::new(tracer, &mut trace, target); let astar = Astar::new(navmesh, source_navvertex, &mut strategy); + let ghosts = vec![]; - Self { astar, trace } + Self { + astar, + trace, + ghosts, + } } pub fn step( @@ -72,10 +81,13 @@ impl Route { let target = self.astar.graph.destination(); let mut strategy = RouterAstarStrategy::new(tracer, &mut self.trace, target); - match self.astar.step(&mut strategy)? { - AstarStatus::Probed(..) | AstarStatus::Visited => Ok(RouterStatus::Running), + let result = match self.astar.step(&mut strategy)? { + AstarStatus::Probed | AstarStatus::Visited => Ok(RouterStatus::Running), AstarStatus::Finished(_cost, _path, band) => Ok(RouterStatus::Finished(band)), - } + }; + + self.ghosts = strategy.ghosts; + result } pub fn navmesh(&self) -> &Navmesh { @@ -85,4 +97,8 @@ impl Route { pub fn trace(&self) -> &Trace { &self.trace } + + pub fn ghosts(&self) -> &[PrimitiveShape] { + &self.ghosts + } } diff --git a/src/router/router.rs b/src/router/router.rs index d77158f..298ddfe 100644 --- a/src/router/router.rs +++ b/src/router/router.rs @@ -10,20 +10,23 @@ use crate::{ head::{GetFace, Head}, primitive::MakePrimitiveShape, rules::AccessRules, + Collision, Infringement, LayoutException, }, geometry::{ - primitive::AccessPrimitiveShape, + primitive::{AccessPrimitiveShape, PrimitiveShape}, shape::{AccessShape, MeasureLength}, }, graph::GetPetgraphIndex, layout::Layout, - router::{ - astar::{AstarError, AstarStatus, AstarStrategy, PathTracker}, - navmesh::{Navmesh, NavmeshEdgeReference, NavmeshError, NavvertexIndex}, - route::Route, - trace::Trace, - tracer::Tracer, - }, +}; + +use super::{ + astar::{AstarError, AstarStrategy, PathTracker}, + draw::DrawException, + navmesh::{Navmesh, NavmeshEdgeReference, NavmeshError, NavvertexIndex}, + route::Route, + trace::Trace, + tracer::{Tracer, TracerException}, }; #[derive(Error, Debug, Clone)] @@ -44,6 +47,7 @@ pub struct RouterAstarStrategy<'a, R: AccessRules> { pub tracer: Tracer<'a, R>, pub trace: &'a mut Trace, pub target: FixedDotIndex, + pub ghosts: Vec, } impl<'a, R: AccessRules> RouterAstarStrategy<'a, R> { @@ -52,6 +56,7 @@ impl<'a, R: AccessRules> RouterAstarStrategy<'a, R> { tracer, trace, target, + ghosts: vec![], } } @@ -71,7 +76,7 @@ impl<'a, R: AccessRules> RouterAstarStrategy<'a, R> { } } -impl<'a, R: AccessRules> AstarStrategy +impl<'a, R: AccessRules> AstarStrategy for RouterAstarStrategy<'a, R> { fn is_goal( @@ -92,9 +97,9 @@ impl<'a, R: AccessRules> AstarStrategy .ok() } - fn probe(&mut self, navmesh: &Navmesh, edge: NavmeshEdgeReference) -> Result<(f64, ()), ()> { + fn probe(&mut self, navmesh: &Navmesh, edge: NavmeshEdgeReference) -> Option { if edge.target().petgraph_index() == self.target.petgraph_index() { - return Err(()); + return None; } let prev_bihead_length = self.bihead_length(); @@ -106,11 +111,32 @@ impl<'a, R: AccessRules> AstarStrategy let probe_length = self.bihead_length() - prev_bihead_length; - if result.is_ok() { - self.trace.undo_step(&mut self.tracer); - Ok((probe_length, ())) - } else { - Err(()) + match result { + Ok(..) => { + self.trace.undo_step(&mut self.tracer); + Some(probe_length) + } + Err(err) => { + if let TracerException::CannotDraw(draw_err) = err { + let layout_err = match draw_err { + DrawException::NoTangents(..) => return None, + DrawException::CannotFinishIn(.., layout_err) => layout_err, + DrawException::CannotWrapAround(.., layout_err) => layout_err, + }; + + let (ghost, ..) = match layout_err { + LayoutException::NoTangents(..) => return None, + LayoutException::Infringement(Infringement(ghost, obstacle)) => { + (ghost, obstacle) + } + LayoutException::Collision(Collision(ghost, obstacle)) => (ghost, obstacle), + LayoutException::AlreadyConnected(..) => return None, + }; + + self.ghosts = vec![ghost]; + } + None + } } }