diff --git a/src/astar.rs b/src/astar.rs index df0cc0c..e80b16d 100644 --- a/src/astar.rs +++ b/src/astar.rs @@ -100,7 +100,7 @@ where K: Measure + Copy, G::NodeId: Eq + Hash, { - fn reroute(&mut self, node: G::NodeId, tracker: &PathTracker) -> Option; + fn is_goal(&mut self, node: G::NodeId, tracker: &PathTracker) -> bool; fn edge_cost(&mut self, edge: G::EdgeRef) -> K; fn estimate_cost(&mut self, node: G::NodeId) -> K; } @@ -125,54 +125,51 @@ where visit_next.push(MinScored(strategy.estimate_cost(start), start)); while let Some(MinScored(estimate_score, node)) = visit_next.pop() { - match strategy.reroute(node, &path_tracker) { - None => { - let path = path_tracker.reconstruct_path_to(node); - let cost = scores[&node]; - return Some((cost, path)); - } - Some(route_cost) => { - // This lookup can be unwrapped without fear of panic since the node was - // necessarily scored before adding it to `visit_next`. - let node_score = scores[&node]; + if strategy.is_goal(node, &path_tracker) { + let path = path_tracker.reconstruct_path_to(node); + let cost = scores[&node]; + return Some((cost, path)); + } - match estimate_scores.entry(node) { - Occupied(mut entry) => { - // If the node has already been visited with an equal or lower score than - // now, then we do not need to re-visit it. - if *entry.get() <= estimate_score { - continue; - } - entry.insert(estimate_score); - } - Vacant(entry) => { - entry.insert(estimate_score); - } + // This lookup can be unwrapped without fear of panic since the node was + // necessarily scored before adding it to `visit_next`. + let node_score = scores[&node]; + + match estimate_scores.entry(node) { + Occupied(mut entry) => { + // If the node has already been visited with an equal or lower score than + // now, then we do not need to re-visit it. + if *entry.get() <= estimate_score { + continue; } + entry.insert(estimate_score); + } + Vacant(entry) => { + entry.insert(estimate_score); + } + } - for edge in graph.edges(node) { - let next = edge.target(); - let next_score = node_score + route_cost + strategy.edge_cost(edge); + for edge in graph.edges(node) { + let next = edge.target(); + let next_score = node_score + strategy.edge_cost(edge); - match 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 { - continue; - } - entry.insert(next_score); - } - Vacant(entry) => { - entry.insert(next_score); - } + match 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 { + continue; } - - path_tracker.set_predecessor(next, node); - let next_estimate_score = next_score + strategy.estimate_cost(next); - visit_next.push(MinScored(next_estimate_score, next)); + entry.insert(next_score); + } + Vacant(entry) => { + entry.insert(next_score); } } + + path_tracker.set_predecessor(next, node); + let next_estimate_score = next_score + strategy.estimate_cost(next); + visit_next.push(MinScored(next_estimate_score, next)); } } diff --git a/src/main.rs b/src/main.rs index e94691e..219ba87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,19 +18,18 @@ mod layout; mod math; mod mesh; mod primitive; -mod route; mod router; mod rules; mod segbend; mod shape; +mod tracer; use geo::point; -use graph::{DotIndex, SegWeight, Tag, TaggedIndex}; +use graph::{DotIndex, SegWeight}; use layout::Layout; use mesh::{Mesh, MeshEdgeReference, VertexIndex}; use petgraph::visit::{EdgeRef, IntoEdgeReferences}; -use route::Route; -use router::{DefaultRouteStrategy, RouteStrategy}; +use router::RouterObserver; use sdl2::event::Event; use sdl2::gfx::primitives::DrawRenderer; use sdl2::keyboard::Keycode; @@ -41,6 +40,7 @@ use sdl2::EventPump; use shape::Shape; use std::panic; use std::time::Duration; +use tracer::Tracer; use crate::graph::DotWeight; use crate::math::Circle; @@ -52,48 +52,36 @@ enum RouterOrLayout<'a> { Layout(&'a Layout), } -struct DebugRouteStrategy<'a, RS: RouteStrategy> { - strategy: RS, +struct DebugRouterObserver<'a> { event_pump: &'a mut sdl2::EventPump, canvas: &'a mut sdl2::render::Canvas, } -impl<'a, RS: RouteStrategy> DebugRouteStrategy<'a, RS> { +impl<'a> DebugRouterObserver<'a> { pub fn new( - strategy: RS, event_pump: &'a mut sdl2::EventPump, canvas: &'a mut sdl2::render::Canvas, ) -> Self { - Self { - strategy, - event_pump, - canvas, - } + Self { event_pump, canvas } } } -impl<'a, RS: RouteStrategy> RouteStrategy for DebugRouteStrategy<'a, RS> { - fn route_cost(&mut self, route: &Route, path: &[VertexIndex]) -> u64 { +impl<'a> RouterObserver for DebugRouterObserver<'a> { + fn on_rework(&mut self, tracer: &Tracer, path: &[VertexIndex]) { render_times( self.event_pump, self.canvas, - RouterOrLayout::Layout(route.layout), + RouterOrLayout::Layout(tracer.layout), None, None, - Some(route.mesh.clone()), + Some(tracer.mesh.clone()), path, 10, ); - self.strategy.route_cost(route, path) } - fn edge_cost(&mut self, route: &Route, edge: MeshEdgeReference) -> u64 { - self.strategy.edge_cost(route, edge) - } - - fn estimate_cost(&mut self, route: &Route, vertex: VertexIndex) -> u64 { - self.strategy.estimate_cost(route, vertex) - } + fn on_probe(&mut self, _tracer: &Tracer, _edge: MeshEdgeReference) {} + fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {} } fn main() { @@ -304,11 +292,7 @@ fn render_times( .reroute( from, point! {x: state.x() as f64, y: state.y() as f64}, - &mut DebugRouteStrategy::new( - DefaultRouteStrategy::new(), - event_pump, - canvas, - ), + &mut DebugRouterObserver::new(event_pump, canvas), ) .ok(); } diff --git a/src/router.rs b/src/router.rs index 2537491..bc7679b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,91 +1,63 @@ use geo::geometry::Point; -use petgraph::visit::{EdgeRef, IntoEdgeReferences}; +use petgraph::visit::EdgeRef; use spade::InsertionError; use crate::astar::{astar, AstarStrategy, PathTracker}; -use crate::bow::Bow; -use crate::draw::{Draw, Head}; -use crate::graph::{BendIndex, DotIndex, Ends, SegIndex, TaggedIndex}; -use crate::graph::{BendWeight, DotWeight, SegWeight}; -use crate::guide::Guide; +use crate::graph::{DotIndex, DotWeight, Ends}; use crate::layout::Layout; use crate::math::Circle; use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex}; -use crate::route::{Route, Trace}; -use crate::rules::{Conditions, Rules}; -use crate::segbend::Segbend; +use crate::rules::Rules; +use crate::tracer::{Trace, Tracer}; + +pub trait RouterObserver { + fn on_rework(&mut self, tracer: &Tracer, path: &[VertexIndex]); + fn on_probe(&mut self, tracer: &Tracer, edge: MeshEdgeReference); + fn on_estimate(&mut self, tracer: &Tracer, vertex: VertexIndex); +} pub struct Router { pub layout: Layout, rules: Rules, } -pub trait RouteStrategy { - fn route_cost(&mut self, route: &Route, path: &[VertexIndex]) -> u64; - fn edge_cost(&mut self, route: &Route, edge: MeshEdgeReference) -> u64; - fn estimate_cost(&mut self, route: &Route, vertex: VertexIndex) -> u64; -} - -pub struct DefaultRouteStrategy {} - -impl DefaultRouteStrategy { - pub fn new() -> Self { - Self {} - } -} - -impl RouteStrategy for DefaultRouteStrategy { - fn route_cost(&mut self, route: &Route, path: &[VertexIndex]) -> u64 { - 0 - } - - fn edge_cost(&mut self, route: &Route, edge: MeshEdgeReference) -> u64 { - 1 - } - - fn estimate_cost(&mut self, route: &Route, vertex: VertexIndex) -> u64 { - 0 - } -} - -struct RouterAstarStrategy<'a, RS: RouteStrategy> { - route: Route<'a>, +struct RouterAstarStrategy<'a, RO: RouterObserver> { + tracer: Tracer<'a>, trace: Trace, to: VertexIndex, - strategy: &'a mut RS, + observer: &'a mut RO, } -impl<'a, RS: RouteStrategy> RouterAstarStrategy<'a, RS> { - pub fn new(route: Route<'a>, trace: Trace, to: VertexIndex, strategy: &'a mut RS) -> Self { +impl<'a, RO: RouterObserver> RouterAstarStrategy<'a, RO> { + pub fn new(tracer: Tracer<'a>, trace: Trace, to: VertexIndex, observer: &'a mut RO) -> Self { Self { - route, + tracer, trace, to, - strategy, + observer, } } } -impl<'a, RS: RouteStrategy> AstarStrategy<&Mesh, u64> for RouterAstarStrategy<'a, RS> { - fn reroute(&mut self, vertex: VertexIndex, tracker: &PathTracker<&Mesh>) -> Option { +impl<'a, RO: RouterObserver> AstarStrategy<&Mesh, u64> for RouterAstarStrategy<'a, RO> { + fn is_goal(&mut self, vertex: VertexIndex, tracker: &PathTracker<&Mesh>) -> bool { let new_path = tracker.reconstruct_path_to(vertex); - self.route.rework_path(&mut self.trace, &new_path, 5.0); + self.tracer.rework_path(&mut self.trace, &new_path, 5.0); + self.observer.on_rework(&self.tracer, &new_path); - if self.route.finish(&mut self.trace, self.to, 5.0).is_ok() { - return None; - } - - Some(self.strategy.route_cost(&self.route, &new_path)) + self.tracer.finish(&mut self.trace, self.to, 5.0).is_ok() } fn edge_cost(&mut self, edge: MeshEdgeReference) -> u64 { - self.strategy.edge_cost(&self.route, edge) + self.observer.on_probe(&self.tracer, edge); + 1 } fn estimate_cost(&mut self, vertex: VertexIndex) -> u64 { - self.strategy.estimate_cost(&self.route, vertex) + self.observer.on_estimate(&self.tracer, vertex); + 0 } } @@ -101,7 +73,7 @@ impl Router { &mut self, from: DotIndex, to: DotIndex, - strategy: &mut impl RouteStrategy, + observer: &mut impl RouterObserver, ) -> Result { // XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look // right. @@ -109,13 +81,13 @@ impl Router { let mut mesh = Mesh::new(); mesh.triangulate(&self.layout)?; - let mut route = self.route(&mesh); - let trace = route.start(mesh.vertex(from)); + let mut tracer = self.tracer(&mesh); + let trace = tracer.start(mesh.vertex(from)); let (_cost, path) = astar( &mesh, mesh.vertex(from), - &mut RouterAstarStrategy::new(route, trace, mesh.vertex(to), strategy), + &mut RouterAstarStrategy::new(tracer, trace, mesh.vertex(to), observer), ) .unwrap(); // TODO. @@ -126,7 +98,7 @@ impl Router { &mut self, from: DotIndex, to: Point, - strategy: &mut impl RouteStrategy, + observer: &mut impl RouterObserver, ) -> Result { let to_dot = if let Some(band) = self.layout.next_band(from) { let to_dot = band.ends().1; @@ -144,7 +116,7 @@ impl Router { .unwrap() // TODO. }; - self.enroute(from, to_dot, strategy) + self.enroute(from, to_dot, observer) } /*pub fn squeeze_around_dot( @@ -259,8 +231,8 @@ impl Router { Ok(()) }*/ - pub fn route<'a>(&'a mut self, mesh: &'a Mesh) -> Route { - Route::new(&mut self.layout, &self.rules, mesh) + pub fn tracer<'a>(&'a mut self, mesh: &'a Mesh) -> Tracer { + Tracer::new(&mut self.layout, &self.rules, mesh) } /*pub fn routeedges(&self) -> impl Iterator + '_ { diff --git a/src/route.rs b/src/tracer.rs similarity index 96% rename from src/route.rs rename to src/tracer.rs index 671bbc3..d67e480 100644 --- a/src/route.rs +++ b/src/tracer.rs @@ -3,7 +3,7 @@ use contracts::debug_ensures; use crate::{ draw::{BareHead, Draw, Head}, layout::Layout, - mesh::{Mesh, VertexIndex}, + mesh::{Mesh, MeshEdgeReference, VertexIndex}, rules::Rules, }; @@ -13,15 +13,15 @@ pub struct Trace { head: Head, } -pub struct Route<'a> { +pub struct Tracer<'a> { pub layout: &'a mut Layout, pub rules: &'a Rules, pub mesh: &'a Mesh, } -impl<'a> Route<'a> { +impl<'a> Tracer<'a> { pub fn new(layout: &'a mut Layout, rules: &'a Rules, mesh: &'a Mesh) -> Self { - Route { + Tracer { layout, rules, mesh,