diff --git a/crates/topola-egui/src/viewport.rs b/crates/topola-egui/src/viewport.rs index 2a0cf56..92d5f21 100644 --- a/crates/topola-egui/src/viewport.rs +++ b/crates/topola-egui/src/viewport.rs @@ -255,20 +255,22 @@ impl Viewport { for edge in navmesh.edge_references() { let mut from = PrimitiveIndex::from( - navmesh.node_weight(edge.source()).unwrap().node, + navmesh.node_weight(edge.source()).unwrap().node(), ) .primitive(board.layout().drawing()) .shape() .center(); let mut to = PrimitiveIndex::from( - navmesh.node_weight(edge.target()).unwrap().node, + navmesh.node_weight(edge.target()).unwrap().node(), ) .primitive(board.layout().drawing()) .shape() .center(); - if let Some(from_sense) = - navmesh.node_weight(edge.source()).unwrap().maybe_sense + if let Some(from_sense) = navmesh + .node_weight(edge.source()) + .unwrap() + .maybe_sense() { from += match from_sense { RotationSense::Counterclockwise => { @@ -278,8 +280,10 @@ impl Viewport { }; } - if let Some(to_sense) = - navmesh.node_weight(edge.target()).unwrap().maybe_sense + if let Some(to_sense) = navmesh + .node_weight(edge.target()) + .unwrap() + .maybe_sense() { to += match to_sense { RotationSense::Counterclockwise => { @@ -335,7 +339,7 @@ impl Viewport { for index in navmesh.graph().node_indices() { let navnode = NavnodeIndex(index); let mut pos = PrimitiveIndex::from( - navmesh.node_weight(navnode).unwrap().node, + navmesh.node_weight(navnode).unwrap().node(), ) .primitive(board.layout().drawing()) .shape() @@ -344,7 +348,7 @@ impl Viewport { pos += match navmesh .node_weight(navnode) .unwrap() - .maybe_sense + .maybe_sense() { Some(RotationSense::Counterclockwise) => { [0.0, 150.0].into() diff --git a/src/router/navcord.rs b/src/router/navcord.rs index fd8ae90..d33ab46 100644 --- a/src/router/navcord.rs +++ b/src/router/navcord.rs @@ -18,7 +18,7 @@ use crate::{ use super::{ draw::Draw, navcorder::{Navcorder, NavcorderException}, - navmesh::{BinavnodeNodeIndex, Navmesh, NavnodeIndex}, + navmesh::{NavigableNodeIndex, Navmesh, NavnodeIndex}, }; /// The `Navcord` is a data structure that holds the movable non-borrowing data @@ -71,21 +71,21 @@ impl Navcord { ) -> Result { let around_node_weight = navmesh.node_weight(around).unwrap(); let sense = around_node_weight - .maybe_sense + .maybe_sense() .ok_or(NavcorderException::CannotWrap)?; - match around_node_weight.node { - BinavnodeNodeIndex::FixedDot(dot) => { + match around_node_weight.node() { + NavigableNodeIndex::FixedDot(dot) => { 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, head, fixed_bend.into(), sense, self.width, ), - BinavnodeNodeIndex::LooseBend(loose_bend) => layout.cane_around_bend( + NavigableNodeIndex::LooseBend(loose_bend) => layout.cane_around_bend( &mut self.recorder, head, loose_bend.into(), @@ -108,7 +108,7 @@ impl Navcord { ) -> Result<(), NavcorderException> { if to == navmesh.destination_navnode() { 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!(); }; diff --git a/src/router/navmesh.rs b/src/router/navmesh.rs index 58e751a..f25a262 100644 --- a/src/router/navmesh.rs +++ b/src/router/navmesh.rs @@ -58,28 +58,28 @@ impl GetPetgraphIndex for NavnodeIndex { /// not considered navnodes. #[enum_dispatch(GetPetgraphIndex, MakePrimitive)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BinavnodeNodeIndex { +pub enum NavigableNodeIndex { FixedDot(FixedDotIndex), FixedBend(FixedBendIndex), LooseBend(LooseBendIndex), } -impl From for PrimitiveIndex { - fn from(vertex: BinavnodeNodeIndex) -> Self { +impl From for PrimitiveIndex { + fn from(vertex: NavigableNodeIndex) -> Self { match vertex { - BinavnodeNodeIndex::FixedDot(dot) => PrimitiveIndex::FixedDot(dot), - BinavnodeNodeIndex::FixedBend(bend) => PrimitiveIndex::FixedBend(bend), - BinavnodeNodeIndex::LooseBend(bend) => PrimitiveIndex::LooseBend(bend), + NavigableNodeIndex::FixedDot(dot) => PrimitiveIndex::FixedDot(dot), + NavigableNodeIndex::FixedBend(bend) => PrimitiveIndex::FixedBend(bend), + NavigableNodeIndex::LooseBend(bend) => PrimitiveIndex::LooseBend(bend), } } } -impl From for GearIndex { - fn from(vertex: BinavnodeNodeIndex) -> Self { +impl From for GearIndex { + fn from(vertex: NavigableNodeIndex) -> Self { match vertex { - BinavnodeNodeIndex::FixedDot(dot) => GearIndex::FixedDot(dot), - BinavnodeNodeIndex::FixedBend(bend) => GearIndex::FixedBend(bend), - BinavnodeNodeIndex::LooseBend(bend) => GearIndex::LooseBend(bend), + NavigableNodeIndex::FixedDot(dot) => GearIndex::FixedDot(dot), + NavigableNodeIndex::FixedBend(bend) => GearIndex::FixedBend(bend), + NavigableNodeIndex::LooseBend(bend) => GearIndex::LooseBend(bend), } } } @@ -97,16 +97,16 @@ enum TrianvertexNodeIndex { FixedBend(FixedBendIndex), } -impl From for BinavnodeNodeIndex { +impl From for NavigableNodeIndex { fn from(vertex: TrianvertexNodeIndex) -> Self { match vertex { - TrianvertexNodeIndex::FixedDot(dot) => BinavnodeNodeIndex::FixedDot(dot), - TrianvertexNodeIndex::FixedBend(bend) => BinavnodeNodeIndex::FixedBend(bend), + TrianvertexNodeIndex::FixedDot(dot) => NavigableNodeIndex::FixedDot(dot), + TrianvertexNodeIndex::FixedBend(bend) => NavigableNodeIndex::FixedBend(bend), } } } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] struct TrianvertexWeight { pub node: TrianvertexNodeIndex, 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 /// during autorouting: -#[derive(Debug, Clone)] -pub struct NavnodeWeight { - pub node: BinavnodeNodeIndex, +#[derive(Clone, Debug)] +pub enum NavnodeWeight { + /// 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: - /// one is clockwise (`Some(true)`), the other counterclockwise (`Some(false)`). - /// The origin and destination nodes however have - /// only one corresponding navmesh vertex each (`None`). - pub maybe_sense: Option, + /// Navnode corresponding to a counterclockwise wrap around the layout node. + CounterclockwiseStep(NavigableNodeIndex), + /// Navnode corresponding to a clockwise wrap around the layout node. + ClockwiseStep(NavigableNodeIndex), + /// 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 { + match self { + NavnodeWeight::CounterclockwiseStep(..) => Some(RotationSense::Counterclockwise), + NavnodeWeight::ClockwiseStep(..) => Some(RotationSense::Clockwise), + NavnodeWeight::Terminal(..) => None, + } + } } #[derive(Error, Debug, Clone)] @@ -222,18 +248,12 @@ impl Navmesh { for trianvertex in triangulation.node_identifiers() { if trianvertex == origin.into() { - let navnode = graph.add_node(NavnodeWeight { - node: trianvertex.into(), - maybe_sense: None, - }); + let navnode = graph.add_node(NavnodeWeight::Terminal(trianvertex.into())); origin_navnode = Some(navnode); map.insert(trianvertex, vec![(navnode, navnode)]); } else if trianvertex == destination.into() { - let navnode = graph.add_node(NavnodeWeight { - node: trianvertex.into(), - maybe_sense: None, - }); + let navnode = graph.add_node(NavnodeWeight::Terminal(trianvertex.into())); destination_navnode = Some(navnode); map.insert(trianvertex, vec![(navnode, navnode)]); @@ -241,7 +261,7 @@ impl Navmesh { map.insert(trianvertex, vec![]); let mut gear = - Into::::into(Into::::into(trianvertex)); + Into::::into(Into::::into(trianvertex)); if options.squeeze_through_under_bends { Self::add_node_to_graph_and_map_as_binavnode( @@ -311,17 +331,10 @@ impl Navmesh { graph: &mut UnGraph, map: &mut BTreeMap, NodeIndex)>>, trianvertex: TrianvertexNodeIndex, - node: BinavnodeNodeIndex, + node: NavigableNodeIndex, ) { - let navnode1 = graph.add_node(NavnodeWeight { - node, - maybe_sense: Some(RotationSense::Counterclockwise), - }); - - let navnode2 = graph.add_node(NavnodeWeight { - node, - maybe_sense: Some(RotationSense::Clockwise), - }); + let navnode1 = graph.add_node(NavnodeWeight::CounterclockwiseStep(node)); + let navnode2 = graph.add_node(NavnodeWeight::ClockwiseStep(node)); map.get_mut(&trianvertex) .unwrap() diff --git a/src/router/router.rs b/src/router/router.rs index 4eb2586..08e6b6f 100644 --- a/src/router/router.rs +++ b/src/router/router.rs @@ -138,7 +138,7 @@ impl AstarStrategy for RouterAst } 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()) .shape() .center();