router: re-encapsulate graph in `Navmesh` and vertices in `VertexIndex`

As in previous commit, this was done in the past, but I removed it when
improving `Navmesh` to hold each navvertex instead of calculating tem
during access.
This commit is contained in:
Mikolaj Wielgus 2024-06-26 22:34:59 +02:00
parent 5254f768e5
commit 0419904b3f
3 changed files with 73 additions and 80 deletions

View File

@ -3,6 +3,7 @@ use std::collections::HashMap;
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use geo::Point; use geo::Point;
use petgraph::{ use petgraph::{
data::DataMap,
graph::UnGraph, graph::UnGraph,
stable_graph::NodeIndex, stable_graph::NodeIndex,
visit::{ visit::{
@ -106,9 +107,9 @@ pub enum NavmeshError {
pub struct Navmesh { pub struct Navmesh {
graph: UnGraph<NavvertexWeight, (), usize>, graph: UnGraph<NavvertexWeight, (), usize>,
source: FixedDotIndex, source: FixedDotIndex,
source_navvertex: NodeIndex<usize>, source_navvertex: NavvertexIndex,
target: FixedDotIndex, target: FixedDotIndex,
target_navvertex: NodeIndex<usize>, target_navvertex: NavvertexIndex,
} }
impl Navmesh { impl Navmesh {
@ -204,9 +205,9 @@ impl Navmesh {
Ok(Self { Ok(Self {
graph, graph,
source, source,
source_navvertex: source_navvertex.unwrap(), source_navvertex: NavvertexIndex(source_navvertex.unwrap()),
target, target,
target_navvertex: target_navvertex.unwrap(), target_navvertex: NavvertexIndex(target_navvertex.unwrap()),
}) })
} }
@ -218,7 +219,7 @@ impl Navmesh {
self.source self.source
} }
pub fn source_navvertex(&self) -> NodeIndex<usize> { pub fn source_navvertex(&self) -> NavvertexIndex {
self.source_navvertex self.source_navvertex
} }
@ -226,7 +227,7 @@ impl Navmesh {
self.target self.target
} }
pub fn target_navvertex(&self) -> NodeIndex<usize> { pub fn target_navvertex(&self) -> NavvertexIndex {
self.target_navvertex self.target_navvertex
} }
} }
@ -241,6 +242,16 @@ impl Data for Navmesh {
type EdgeWeight = (); type EdgeWeight = ();
} }
impl DataMap for Navmesh {
fn node_weight(&self, vertex: Self::NodeId) -> Option<&Self::NodeWeight> {
self.graph.node_weight(vertex.petgraph_index())
}
fn edge_weight(&self, _edge: Self::EdgeId) -> Option<&Self::EdgeWeight> {
None
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct NavmeshEdgeReference { pub struct NavmeshEdgeReference {
from: NavvertexIndex, from: NavvertexIndex,

View File

@ -1,5 +1,6 @@
use geo::EuclideanDistance; use geo::EuclideanDistance;
use petgraph::{ use petgraph::{
data::DataMap,
graph::{EdgeReference, NodeIndex, UnGraph}, graph::{EdgeReference, NodeIndex, UnGraph},
visit::EdgeRef, visit::EdgeRef,
}; };
@ -20,7 +21,10 @@ use crate::{
router::{ router::{
astar::{astar, AstarError, AstarStrategy, PathTracker}, astar::{astar, AstarError, AstarStrategy, PathTracker},
draw::DrawException, draw::DrawException,
navmesh::{BinavvertexNodeIndex, Navmesh, NavmeshError, NavvertexWeight}, navmesh::{
BinavvertexNodeIndex, Navmesh, NavmeshEdgeReference, NavmeshError, NavvertexIndex,
NavvertexWeight,
},
tracer::{Trace, Tracer}, tracer::{Trace, Tracer},
}, },
}; };
@ -83,33 +87,29 @@ impl<'a, R: RulesTrait> RouterAstarStrategy<'a, R> {
} }
} }
impl<'a, R: RulesTrait> AstarStrategy<&UnGraph<NavvertexWeight, (), usize>, f64, BandFirstSegIndex> impl<'a, R: RulesTrait> AstarStrategy<&Navmesh, f64, BandFirstSegIndex>
for RouterAstarStrategy<'a, R> for RouterAstarStrategy<'a, R>
{ {
fn is_goal( fn is_goal(
&mut self, &mut self,
graph: &&UnGraph<NavvertexWeight, (), usize>, navmesh: &&Navmesh,
vertex: NodeIndex<usize>, vertex: NavvertexIndex,
tracker: &PathTracker<&UnGraph<NavvertexWeight, (), usize>>, tracker: &PathTracker<&Navmesh>,
) -> Option<BandFirstSegIndex> { ) -> Option<BandFirstSegIndex> {
let new_path = tracker.reconstruct_path_to(vertex); let new_path = tracker.reconstruct_path_to(vertex);
let width = self.trace.width; let width = self.trace.width;
self.tracer self.tracer
.rework_path(*graph, &mut self.trace, &new_path[..], width) .rework_path(navmesh, &mut self.trace, &new_path[..], width)
.unwrap(); .unwrap();
self.tracer self.tracer
.finish(*graph, &mut self.trace, self.target, width) .finish(navmesh, &mut self.trace, self.target, width)
.ok() .ok()
} }
fn edge_cost( fn edge_cost(&mut self, navmesh: &&Navmesh, edge: NavmeshEdgeReference) -> Option<f64> {
&mut self, if edge.target().petgraph_index() == self.target.petgraph_index() {
graph: &&UnGraph<NavvertexWeight, (), usize>,
edge: EdgeReference<(), usize>,
) -> Option<f64> {
if edge.target() == self.target.petgraph_index() {
return None; return None;
} }
@ -118,24 +118,20 @@ impl<'a, R: RulesTrait> AstarStrategy<&UnGraph<NavvertexWeight, (), usize>, f64,
let width = self.trace.width; let width = self.trace.width;
let result = self let result = self
.tracer .tracer
.step(*graph, &mut self.trace, edge.target(), width); .step(navmesh, &mut self.trace, edge.target(), width);
let probe_length = self.bihead_length() - prev_bihead_length; let probe_length = self.bihead_length() - prev_bihead_length;
if result.is_ok() { if result.is_ok() {
self.tracer.undo_step(*graph, &mut self.trace); self.tracer.undo_step(navmesh, &mut self.trace);
Some(probe_length) Some(probe_length)
} else { } else {
None None
} }
} }
fn estimate_cost( fn estimate_cost(&mut self, navmesh: &&Navmesh, vertex: NavvertexIndex) -> f64 {
&mut self, let start_point = PrimitiveIndex::from(navmesh.node_weight(vertex).unwrap().node)
graph: &&UnGraph<NavvertexWeight, (), usize>,
vertex: NodeIndex<usize>,
) -> f64 {
let start_point = PrimitiveIndex::from(graph.node_weight(vertex).unwrap().node)
.primitive(self.tracer.layout.drawing()) .primitive(self.tracer.layout.drawing())
.shape() .shape()
.center(); .center();
@ -172,14 +168,14 @@ impl Router {
) -> Result<BandFirstSegIndex, RouterError> { ) -> Result<BandFirstSegIndex, RouterError> {
let mut tracer = Tracer::new(layout); let mut tracer = Tracer::new(layout);
let trace = tracer.start( let trace = tracer.start(
self.navmesh.graph(), &self.navmesh,
self.navmesh.source(), self.navmesh.source(),
self.navmesh.source_navvertex(), self.navmesh.source_navvertex(),
width, width,
); );
let (_cost, _path, band) = astar( let (_cost, _path, band) = astar(
self.navmesh.graph(), &self.navmesh,
self.navmesh.source_navvertex(), self.navmesh.source_navvertex(),
&mut RouterAstarStrategy::new(tracer, trace, self.navmesh.target()), &mut RouterAstarStrategy::new(tracer, trace, self.navmesh.target()),
)?; )?;

View File

@ -1,5 +1,8 @@
use contracts::{debug_ensures, debug_requires}; use contracts::{debug_ensures, debug_requires};
use petgraph::graph::{NodeIndex, UnGraph}; use petgraph::{
data::DataMap,
graph::{NodeIndex, UnGraph},
};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
@ -14,7 +17,7 @@ use crate::{
layout::Layout, layout::Layout,
router::{ router::{
draw::{Draw, DrawException}, draw::{Draw, DrawException},
navmesh::{BinavvertexNodeIndex, NavvertexWeight}, navmesh::{BinavvertexNodeIndex, Navmesh, NavvertexIndex, NavvertexWeight},
}, },
}; };
@ -28,7 +31,7 @@ pub enum TracerException {
#[derive(Debug)] #[derive(Debug)]
pub struct Trace { pub struct Trace {
pub path: Vec<NodeIndex<usize>>, pub path: Vec<NavvertexIndex>,
pub head: Head, pub head: Head,
pub width: f64, pub width: f64,
} }
@ -45,9 +48,9 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
pub fn start( pub fn start(
&mut self, &mut self,
_graph: &UnGraph<NavvertexWeight, (), usize>, _navmesh: &Navmesh,
source: FixedDotIndex, source: FixedDotIndex,
source_navvertex: NodeIndex<usize>, source_navvertex: NavvertexIndex,
width: f64, width: f64,
) -> Trace { ) -> Trace {
Trace { Trace {
@ -59,7 +62,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
pub fn finish( pub fn finish(
&mut self, &mut self,
graph: &UnGraph<NavvertexWeight, (), usize>, _navmesh: &Navmesh,
trace: &mut Trace, trace: &mut Trace,
target: FixedDotIndex, target: FixedDotIndex,
width: f64, width: f64,
@ -71,9 +74,9 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
#[debug_ensures(ret.is_ok() -> trace.path.len() == path.len())] #[debug_ensures(ret.is_ok() -> trace.path.len() == path.len())]
pub fn rework_path( pub fn rework_path(
&mut self, &mut self,
graph: &UnGraph<NavvertexWeight, (), usize>, navmesh: &Navmesh,
trace: &mut Trace, trace: &mut Trace,
path: &[NodeIndex<usize>], path: &[NavvertexIndex],
width: f64, width: f64,
) -> Result<(), TracerException> { ) -> Result<(), TracerException> {
let prefix_length = trace let prefix_length = trace
@ -84,21 +87,21 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
.count(); .count();
let length = trace.path.len(); let length = trace.path.len();
self.undo_path(graph, trace, length - prefix_length); self.undo_path(navmesh, trace, length - prefix_length);
Ok::<(), TracerException>(self.path(graph, trace, &path[prefix_length..], width)?) Ok::<(), TracerException>(self.path(navmesh, trace, &path[prefix_length..], width)?)
} }
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))] #[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))]
pub fn path( pub fn path(
&mut self, &mut self,
graph: &UnGraph<NavvertexWeight, (), usize>, navmesh: &Navmesh,
trace: &mut Trace, trace: &mut Trace,
path: &[NodeIndex<usize>], path: &[NavvertexIndex],
width: f64, width: f64,
) -> Result<(), TracerException> { ) -> Result<(), TracerException> {
for (i, vertex) in path.iter().enumerate() { for (i, vertex) in path.iter().enumerate() {
if let Err(err) = self.step(graph, trace, *vertex, width) { if let Err(err) = self.step(navmesh, trace, *vertex, width) {
self.undo_path(graph, trace, i); self.undo_path(navmesh, trace, i);
return Err(err.into()); return Err(err.into());
} }
} }
@ -107,14 +110,9 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
} }
#[debug_ensures(trace.path.len() == old(trace.path.len() - step_count))] #[debug_ensures(trace.path.len() == old(trace.path.len() - step_count))]
pub fn undo_path( pub fn undo_path(&mut self, navmesh: &Navmesh, trace: &mut Trace, step_count: usize) {
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
trace: &mut Trace,
step_count: usize,
) {
for _ in 0..step_count { for _ in 0..step_count {
self.undo_step(graph, trace); self.undo_step(navmesh, trace);
} }
} }
@ -123,12 +121,12 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))] #[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn step( pub fn step(
&mut self, &mut self,
graph: &UnGraph<NavvertexWeight, (), usize>, navmesh: &Navmesh,
trace: &mut Trace, trace: &mut Trace,
to: NodeIndex<usize>, to: NavvertexIndex,
width: f64, width: f64,
) -> Result<(), TracerException> { ) -> Result<(), TracerException> {
trace.head = self.wrap(graph, trace.head, to, width)?.into(); trace.head = self.wrap(navmesh, trace.head, to, width)?.into();
trace.path.push(to); trace.path.push(to);
Ok::<(), TracerException>(()) Ok::<(), TracerException>(())
@ -136,29 +134,29 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
fn wrap( fn wrap(
&mut self, &mut self,
graph: &UnGraph<NavvertexWeight, (), usize>, navmesh: &Navmesh,
head: Head, head: Head,
around: NodeIndex<usize>, around: NavvertexIndex,
width: f64, width: f64,
) -> Result<CaneHead, TracerException> { ) -> Result<CaneHead, TracerException> {
let cw = self let cw = self
.maybe_cw(graph, around) .maybe_cw(navmesh, around)
.ok_or(TracerException::CannotWrap)?; .ok_or(TracerException::CannotWrap)?;
match self.binavvertex(graph, around) { match self.binavvertex(navmesh, around) {
BinavvertexNodeIndex::FixedDot(dot) => { BinavvertexNodeIndex::FixedDot(dot) => {
self.wrap_around_fixed_dot(graph, head, dot, cw, width) self.wrap_around_fixed_dot(navmesh, head, dot, cw, width)
} }
BinavvertexNodeIndex::FixedBend(_fixed_bend) => todo!(), BinavvertexNodeIndex::FixedBend(_fixed_bend) => todo!(),
BinavvertexNodeIndex::LooseBend(loose_bend) => { BinavvertexNodeIndex::LooseBend(loose_bend) => {
self.wrap_around_loose_bend(graph, head, loose_bend, cw, width) self.wrap_around_loose_bend(navmesh, head, loose_bend, cw, width)
} }
} }
} }
fn wrap_around_fixed_dot( fn wrap_around_fixed_dot(
&mut self, &mut self,
graph: &UnGraph<NavvertexWeight, (), usize>, _navmesh: &Navmesh,
head: Head, head: Head,
around: FixedDotIndex, around: FixedDotIndex,
cw: bool, cw: bool,
@ -169,7 +167,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
fn wrap_around_loose_bend( fn wrap_around_loose_bend(
&mut self, &mut self,
graph: &UnGraph<NavvertexWeight, (), usize>, _navmesh: &Navmesh,
head: Head, head: Head,
around: LooseBendIndex, around: LooseBendIndex,
cw: bool, cw: bool,
@ -179,7 +177,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
} }
#[debug_ensures(trace.path.len() == old(trace.path.len() - 1))] #[debug_ensures(trace.path.len() == old(trace.path.len() - 1))]
pub fn undo_step(&mut self, graph: &UnGraph<NavvertexWeight, (), usize>, trace: &mut Trace) { pub fn undo_step(&mut self, _navmesh: &Navmesh, trace: &mut Trace) {
if let Head::Cane(head) = trace.head { if let Head::Cane(head) = trace.head {
trace.head = Draw::new(self.layout).undo_cane(head).unwrap(); trace.head = Draw::new(self.layout).undo_cane(head).unwrap();
} else { } else {
@ -189,27 +187,15 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
trace.path.pop(); trace.path.pop();
} }
fn maybe_cw( fn maybe_cw(&self, navmesh: &Navmesh, navvertex: NavvertexIndex) -> Option<bool> {
&self, navmesh.node_weight(navvertex).unwrap().maybe_cw
graph: &UnGraph<NavvertexWeight, (), usize>,
navvertex: NodeIndex<usize>,
) -> Option<bool> {
graph.node_weight(navvertex).unwrap().maybe_cw
} }
fn binavvertex( fn binavvertex(&self, navmesh: &Navmesh, navvertex: NavvertexIndex) -> BinavvertexNodeIndex {
&self, navmesh.node_weight(navvertex).unwrap().node
graph: &UnGraph<NavvertexWeight, (), usize>,
navvertex: NodeIndex<usize>,
) -> BinavvertexNodeIndex {
graph.node_weight(navvertex).unwrap().node
} }
fn primitive( fn primitive(&self, navmesh: &Navmesh, navvertex: NavvertexIndex) -> PrimitiveIndex {
&self, self.binavvertex(navmesh, navvertex).into()
graph: &UnGraph<NavvertexWeight, (), usize>,
navvertex: NodeIndex<usize>,
) -> PrimitiveIndex {
self.binavvertex(graph, navvertex).into()
} }
} }