refactor(router/navmesh): Change `NavnodeWeight` from struct to enum

This commit is contained in:
Mikolaj Wielgus 2025-05-22 18:00:47 +02:00
parent 1acae9ab41
commit fe6a286e32
4 changed files with 75 additions and 58 deletions

View File

@ -255,20 +255,22 @@ impl Viewport {
for edge in navmesh.edge_references() { for edge in navmesh.edge_references() {
let mut from = PrimitiveIndex::from( let mut from = PrimitiveIndex::from(
navmesh.node_weight(edge.source()).unwrap().node, navmesh.node_weight(edge.source()).unwrap().node(),
) )
.primitive(board.layout().drawing()) .primitive(board.layout().drawing())
.shape() .shape()
.center(); .center();
let mut to = PrimitiveIndex::from( let mut to = PrimitiveIndex::from(
navmesh.node_weight(edge.target()).unwrap().node, navmesh.node_weight(edge.target()).unwrap().node(),
) )
.primitive(board.layout().drawing()) .primitive(board.layout().drawing())
.shape() .shape()
.center(); .center();
if let Some(from_sense) = if let Some(from_sense) = navmesh
navmesh.node_weight(edge.source()).unwrap().maybe_sense .node_weight(edge.source())
.unwrap()
.maybe_sense()
{ {
from += match from_sense { from += match from_sense {
RotationSense::Counterclockwise => { RotationSense::Counterclockwise => {
@ -278,8 +280,10 @@ impl Viewport {
}; };
} }
if let Some(to_sense) = if let Some(to_sense) = navmesh
navmesh.node_weight(edge.target()).unwrap().maybe_sense .node_weight(edge.target())
.unwrap()
.maybe_sense()
{ {
to += match to_sense { to += match to_sense {
RotationSense::Counterclockwise => { RotationSense::Counterclockwise => {
@ -335,7 +339,7 @@ impl Viewport {
for index in navmesh.graph().node_indices() { for index in navmesh.graph().node_indices() {
let navnode = NavnodeIndex(index); let navnode = NavnodeIndex(index);
let mut pos = PrimitiveIndex::from( let mut pos = PrimitiveIndex::from(
navmesh.node_weight(navnode).unwrap().node, navmesh.node_weight(navnode).unwrap().node(),
) )
.primitive(board.layout().drawing()) .primitive(board.layout().drawing())
.shape() .shape()
@ -344,7 +348,7 @@ impl Viewport {
pos += match navmesh pos += match navmesh
.node_weight(navnode) .node_weight(navnode)
.unwrap() .unwrap()
.maybe_sense .maybe_sense()
{ {
Some(RotationSense::Counterclockwise) => { Some(RotationSense::Counterclockwise) => {
[0.0, 150.0].into() [0.0, 150.0].into()

View File

@ -18,7 +18,7 @@ use crate::{
use super::{ use super::{
draw::Draw, draw::Draw,
navcorder::{Navcorder, NavcorderException}, navcorder::{Navcorder, NavcorderException},
navmesh::{BinavnodeNodeIndex, Navmesh, NavnodeIndex}, navmesh::{NavigableNodeIndex, Navmesh, NavnodeIndex},
}; };
/// The `Navcord` is a data structure that holds the movable non-borrowing data /// The `Navcord` is a data structure that holds the movable non-borrowing data
@ -71,21 +71,21 @@ impl Navcord {
) -> Result<CaneHead, NavcorderException> { ) -> Result<CaneHead, NavcorderException> {
let around_node_weight = navmesh.node_weight(around).unwrap(); let around_node_weight = navmesh.node_weight(around).unwrap();
let sense = around_node_weight let sense = around_node_weight
.maybe_sense .maybe_sense()
.ok_or(NavcorderException::CannotWrap)?; .ok_or(NavcorderException::CannotWrap)?;
match around_node_weight.node { match around_node_weight.node() {
BinavnodeNodeIndex::FixedDot(dot) => { NavigableNodeIndex::FixedDot(dot) => {
layout.cane_around_dot(&mut self.recorder, head, dot, sense, self.width) layout.cane_around_dot(&mut self.recorder, head, dot, sense, self.width)
} }
BinavnodeNodeIndex::FixedBend(fixed_bend) => layout.cane_around_bend( NavigableNodeIndex::FixedBend(fixed_bend) => layout.cane_around_bend(
&mut self.recorder, &mut self.recorder,
head, head,
fixed_bend.into(), fixed_bend.into(),
sense, sense,
self.width, self.width,
), ),
BinavnodeNodeIndex::LooseBend(loose_bend) => layout.cane_around_bend( NavigableNodeIndex::LooseBend(loose_bend) => layout.cane_around_bend(
&mut self.recorder, &mut self.recorder,
head, head,
loose_bend.into(), loose_bend.into(),
@ -108,7 +108,7 @@ impl Navcord {
) -> Result<(), NavcorderException> { ) -> Result<(), NavcorderException> {
if to == navmesh.destination_navnode() { if to == navmesh.destination_navnode() {
let to_node_weight = navmesh.node_weight(to).unwrap(); let to_node_weight = navmesh.node_weight(to).unwrap();
let BinavnodeNodeIndex::FixedDot(to_dot) = to_node_weight.node else { let NavigableNodeIndex::FixedDot(to_dot) = to_node_weight.node() else {
unreachable!(); unreachable!();
}; };

View File

@ -58,28 +58,28 @@ impl GetPetgraphIndex for NavnodeIndex {
/// not considered navnodes. /// not considered navnodes.
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)] #[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinavnodeNodeIndex { pub enum NavigableNodeIndex {
FixedDot(FixedDotIndex), FixedDot(FixedDotIndex),
FixedBend(FixedBendIndex), FixedBend(FixedBendIndex),
LooseBend(LooseBendIndex), LooseBend(LooseBendIndex),
} }
impl From<BinavnodeNodeIndex> for PrimitiveIndex { impl From<NavigableNodeIndex> for PrimitiveIndex {
fn from(vertex: BinavnodeNodeIndex) -> Self { fn from(vertex: NavigableNodeIndex) -> Self {
match vertex { match vertex {
BinavnodeNodeIndex::FixedDot(dot) => PrimitiveIndex::FixedDot(dot), NavigableNodeIndex::FixedDot(dot) => PrimitiveIndex::FixedDot(dot),
BinavnodeNodeIndex::FixedBend(bend) => PrimitiveIndex::FixedBend(bend), NavigableNodeIndex::FixedBend(bend) => PrimitiveIndex::FixedBend(bend),
BinavnodeNodeIndex::LooseBend(bend) => PrimitiveIndex::LooseBend(bend), NavigableNodeIndex::LooseBend(bend) => PrimitiveIndex::LooseBend(bend),
} }
} }
} }
impl From<BinavnodeNodeIndex> for GearIndex { impl From<NavigableNodeIndex> for GearIndex {
fn from(vertex: BinavnodeNodeIndex) -> Self { fn from(vertex: NavigableNodeIndex) -> Self {
match vertex { match vertex {
BinavnodeNodeIndex::FixedDot(dot) => GearIndex::FixedDot(dot), NavigableNodeIndex::FixedDot(dot) => GearIndex::FixedDot(dot),
BinavnodeNodeIndex::FixedBend(bend) => GearIndex::FixedBend(bend), NavigableNodeIndex::FixedBend(bend) => GearIndex::FixedBend(bend),
BinavnodeNodeIndex::LooseBend(bend) => GearIndex::LooseBend(bend), NavigableNodeIndex::LooseBend(bend) => GearIndex::LooseBend(bend),
} }
} }
} }
@ -97,16 +97,16 @@ enum TrianvertexNodeIndex {
FixedBend(FixedBendIndex), FixedBend(FixedBendIndex),
} }
impl From<TrianvertexNodeIndex> for BinavnodeNodeIndex { impl From<TrianvertexNodeIndex> for NavigableNodeIndex {
fn from(vertex: TrianvertexNodeIndex) -> Self { fn from(vertex: TrianvertexNodeIndex) -> Self {
match vertex { match vertex {
TrianvertexNodeIndex::FixedDot(dot) => BinavnodeNodeIndex::FixedDot(dot), TrianvertexNodeIndex::FixedDot(dot) => NavigableNodeIndex::FixedDot(dot),
TrianvertexNodeIndex::FixedBend(bend) => BinavnodeNodeIndex::FixedBend(bend), TrianvertexNodeIndex::FixedBend(bend) => NavigableNodeIndex::FixedBend(bend),
} }
} }
} }
#[derive(Debug, Clone)] #[derive(Clone, Debug)]
struct TrianvertexWeight { struct TrianvertexWeight {
pub node: TrianvertexNodeIndex, pub node: TrianvertexNodeIndex,
pub pos: Point, pub pos: Point,
@ -130,15 +130,41 @@ impl HasPosition for TrianvertexWeight {
/// ///
/// See the following blog post for more information and a visualization of the navmesh /// See the following blog post for more information and a visualization of the navmesh
/// during autorouting: <https://topola.dev/blog/2024/07/20/junejuly-2024-development-update/#advanced-debug-visualization> /// during autorouting: <https://topola.dev/blog/2024/07/20/junejuly-2024-development-update/#advanced-debug-visualization>
#[derive(Debug, Clone)] #[derive(Clone, Debug)]
pub struct NavnodeWeight { pub enum NavnodeWeight {
pub node: BinavnodeNodeIndex, /// All navigable layout nodes except origin and destination nodes are
/// assigned one or more trinavnodes.
/// Each trinavnode consists of three navnodes distinguished by the three
/// following variants:
/// There are two navnodes for each navigable node: /// Navnode corresponding to a counterclockwise wrap around the layout node.
/// one is clockwise (`Some(true)`), the other counterclockwise (`Some(false)`). CounterclockwiseStep(NavigableNodeIndex),
/// The origin and destination nodes however have /// Navnode corresponding to a clockwise wrap around the layout node.
/// only one corresponding navmesh vertex each (`None`). ClockwiseStep(NavigableNodeIndex),
pub maybe_sense: Option<RotationSense>, /// Navnode corresponding to a leap between two step or terminal navnodes.
//Leap(NavigableNodeIndex),
/// Unlike the others, origin and destination layout nodes each are assigned
/// only one navnode, which we call the "terminal navnode".
Terminal(NavigableNodeIndex),
}
impl NavnodeWeight {
pub fn node(&self) -> NavigableNodeIndex {
match self {
NavnodeWeight::CounterclockwiseStep(node) => *node,
NavnodeWeight::ClockwiseStep(node) => *node,
NavnodeWeight::Terminal(node) => *node,
}
}
pub fn maybe_sense(&self) -> Option<RotationSense> {
match self {
NavnodeWeight::CounterclockwiseStep(..) => Some(RotationSense::Counterclockwise),
NavnodeWeight::ClockwiseStep(..) => Some(RotationSense::Clockwise),
NavnodeWeight::Terminal(..) => None,
}
}
} }
#[derive(Error, Debug, Clone)] #[derive(Error, Debug, Clone)]
@ -222,18 +248,12 @@ impl Navmesh {
for trianvertex in triangulation.node_identifiers() { for trianvertex in triangulation.node_identifiers() {
if trianvertex == origin.into() { if trianvertex == origin.into() {
let navnode = graph.add_node(NavnodeWeight { let navnode = graph.add_node(NavnodeWeight::Terminal(trianvertex.into()));
node: trianvertex.into(),
maybe_sense: None,
});
origin_navnode = Some(navnode); origin_navnode = Some(navnode);
map.insert(trianvertex, vec![(navnode, navnode)]); map.insert(trianvertex, vec![(navnode, navnode)]);
} else if trianvertex == destination.into() { } else if trianvertex == destination.into() {
let navnode = graph.add_node(NavnodeWeight { let navnode = graph.add_node(NavnodeWeight::Terminal(trianvertex.into()));
node: trianvertex.into(),
maybe_sense: None,
});
destination_navnode = Some(navnode); destination_navnode = Some(navnode);
map.insert(trianvertex, vec![(navnode, navnode)]); map.insert(trianvertex, vec![(navnode, navnode)]);
@ -241,7 +261,7 @@ impl Navmesh {
map.insert(trianvertex, vec![]); map.insert(trianvertex, vec![]);
let mut gear = let mut gear =
Into::<GearIndex>::into(Into::<BinavnodeNodeIndex>::into(trianvertex)); Into::<GearIndex>::into(Into::<NavigableNodeIndex>::into(trianvertex));
if options.squeeze_through_under_bends { if options.squeeze_through_under_bends {
Self::add_node_to_graph_and_map_as_binavnode( Self::add_node_to_graph_and_map_as_binavnode(
@ -311,17 +331,10 @@ impl Navmesh {
graph: &mut UnGraph<NavnodeWeight, (), usize>, graph: &mut UnGraph<NavnodeWeight, (), usize>,
map: &mut BTreeMap<TrianvertexNodeIndex, Vec<(NodeIndex<usize>, NodeIndex<usize>)>>, map: &mut BTreeMap<TrianvertexNodeIndex, Vec<(NodeIndex<usize>, NodeIndex<usize>)>>,
trianvertex: TrianvertexNodeIndex, trianvertex: TrianvertexNodeIndex,
node: BinavnodeNodeIndex, node: NavigableNodeIndex,
) { ) {
let navnode1 = graph.add_node(NavnodeWeight { let navnode1 = graph.add_node(NavnodeWeight::CounterclockwiseStep(node));
node, let navnode2 = graph.add_node(NavnodeWeight::ClockwiseStep(node));
maybe_sense: Some(RotationSense::Counterclockwise),
});
let navnode2 = graph.add_node(NavnodeWeight {
node,
maybe_sense: Some(RotationSense::Clockwise),
});
map.get_mut(&trianvertex) map.get_mut(&trianvertex)
.unwrap() .unwrap()

View File

@ -138,7 +138,7 @@ impl<R: AccessRules> AstarStrategy<Navmesh, f64, BandTermsegIndex> for RouterAst
} }
fn estimate_cost(&mut self, navmesh: &Navmesh, vertex: NavnodeIndex) -> f64 { fn estimate_cost(&mut self, navmesh: &Navmesh, vertex: NavnodeIndex) -> f64 {
let start_point = PrimitiveIndex::from(navmesh.node_weight(vertex).unwrap().node) let start_point = PrimitiveIndex::from(navmesh.node_weight(vertex).unwrap().node())
.primitive(self.layout.drawing()) .primitive(self.layout.drawing())
.shape() .shape()
.center(); .center();