feat(router/navcord): Make it possible to visit leap navnodes

Closes https://codeberg.org/topola/topola/issues/121
This commit is contained in:
Mikolaj Wielgus 2025-05-23 01:46:45 +02:00
parent a27b263288
commit aef5c6471e
4 changed files with 19 additions and 11 deletions

View File

@ -18,7 +18,7 @@ use crate::{
use super::{ use super::{
draw::Draw, draw::Draw,
navcorder::{Navcorder, NavcorderException}, navcorder::{Navcorder, NavcorderException},
navmesh::{NavigableNodeIndex, Navmesh, NavnodeIndex}, navmesh::{NavigableNodeIndex, Navmesh, NavnodeIndex, NavnodeWeight},
}; };
/// 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
@ -106,17 +106,20 @@ impl Navcord {
navmesh: &Navmesh, navmesh: &Navmesh,
to: NavnodeIndex, to: NavnodeIndex,
) -> Result<(), NavcorderException> { ) -> Result<(), NavcorderException> {
let to_node_weight = navmesh.node_weight(to).unwrap();
if to == navmesh.destination_navnode() { if to == navmesh.destination_navnode() {
let to_node_weight = navmesh.node_weight(to).unwrap();
let NavigableNodeIndex::FixedDot(to_dot) = to_node_weight.node() else { let NavigableNodeIndex::FixedDot(to_dot) = to_node_weight.node() else {
unreachable!(); unreachable!();
}; };
self.final_termseg = Some(layout.finish(navmesh, self, to_dot).unwrap()); self.final_termseg = Some(layout.finish(navmesh, self, to_dot)?);
// NOTE: We don't update the head here because there is currently // NOTE: We don't update the head here because there is currently
// no head variant that consists only of a seg, and I'm not sure if // no head variant that consists only of a seg, and I'm not sure if
// there should be one. // there should be one.
} else if matches!(to_node_weight, NavnodeWeight::Leap(..)) {
// Nothing to do beyond pushing the navnode onto the path.
} else { } else {
self.head = self.wrap(layout, navmesh, self.head, to)?.into(); self.head = self.wrap(layout, navmesh, self.head, to)?.into();
} }
@ -134,10 +137,15 @@ impl Navcord {
pub fn step_back<R: AccessRules>( pub fn step_back<R: AccessRules>(
&mut self, &mut self,
layout: &mut Layout<R>, layout: &mut Layout<R>,
navmesh: &Navmesh,
) -> Result<(), NavcorderException> { ) -> Result<(), NavcorderException> {
let last_node_weight = navmesh.node_weight(*self.path.last().unwrap());
if let Some(final_termseg) = self.final_termseg { if let Some(final_termseg) = self.final_termseg {
layout.remove_termseg(&mut self.recorder, final_termseg); layout.remove_termseg(&mut self.recorder, final_termseg);
self.final_termseg = None; self.final_termseg = None;
} else if matches!(last_node_weight, Some(NavnodeWeight::Leap(..))) {
// Nothing to do beyond popping the navnode from the path.
} else { } else {
if let Head::Cane(head) = self.head { if let Head::Cane(head) = self.head {
self.head = layout.undo_cane(&mut self.recorder, head).unwrap(); self.head = layout.undo_cane(&mut self.recorder, head).unwrap();

View File

@ -54,7 +54,7 @@ pub trait Navcorder {
path: &[NavnodeIndex], path: &[NavnodeIndex],
) -> Result<(), NavcorderException>; ) -> Result<(), NavcorderException>;
fn undo_path(&mut self, navcord: &mut Navcord, step_count: usize); fn undo_path(&mut self, navmesh: &Navmesh, navcord: &mut Navcord, step_count: usize);
} }
impl<R: AccessRules> Navcorder for Layout<R> { impl<R: AccessRules> Navcorder for Layout<R> {
@ -93,7 +93,7 @@ impl<R: AccessRules> Navcorder for Layout<R> {
.count(); .count();
let length = navcord.path.len(); let length = navcord.path.len();
self.undo_path(navcord, length - prefix_length); self.undo_path(navmesh, navcord, length - prefix_length);
self.path(navmesh, navcord, &path[prefix_length..]) self.path(navmesh, navcord, &path[prefix_length..])
} }
@ -106,7 +106,7 @@ impl<R: AccessRules> Navcorder for Layout<R> {
) -> Result<(), NavcorderException> { ) -> Result<(), NavcorderException> {
for (i, vertex) in path.iter().enumerate() { for (i, vertex) in path.iter().enumerate() {
if let Err(err) = navcord.step_to(self, navmesh, *vertex) { if let Err(err) = navcord.step_to(self, navmesh, *vertex) {
self.undo_path(navcord, i); self.undo_path(navmesh, navcord, i);
return Err(err); return Err(err);
} }
} }
@ -115,9 +115,9 @@ impl<R: AccessRules> Navcorder for Layout<R> {
} }
#[debug_ensures(navcord.path.len() == old(navcord.path.len() - step_count))] #[debug_ensures(navcord.path.len() == old(navcord.path.len() - step_count))]
fn undo_path(&mut self, navcord: &mut Navcord, step_count: usize) { fn undo_path(&mut self, navmesh: &Navmesh, navcord: &mut Navcord, step_count: usize) {
for _ in 0..step_count { for _ in 0..step_count {
let _ = navcord.step_back(self); let _ = navcord.step_back(self, navmesh);
} }
} }
} }

View File

@ -90,7 +90,7 @@ impl<R: AccessRules> Step<Router<'_, R>, BandTermsegIndex> for RouteStepper {
// NOTE(fogti): The 1 instead 0 is because the first element in the path // NOTE(fogti): The 1 instead 0 is because the first element in the path
// is the source navnode. See also: `NavcordStepper::new`. // is the source navnode. See also: `NavcordStepper::new`.
for _ in 1..self.navcord.path.len() { for _ in 1..self.navcord.path.len() {
self.navcord.step_back(layout); self.navcord.step_back(layout, &self.astar.graph);
} }
Err(e) Err(e)
} }

View File

@ -136,8 +136,8 @@ impl<R: AccessRules> AstarStrategy<Navmesh, f64, BandTermsegIndex> for RouterAst
} }
} }
fn remove_probe(&mut self, _navmesh: &Navmesh) { fn remove_probe(&mut self, navmesh: &Navmesh) {
self.navcord.step_back(self.layout); self.navcord.step_back(self.layout, navmesh);
} }
fn estimate_cost(&mut self, navmesh: &Navmesh, vertex: NavnodeIndex) -> f64 { fn estimate_cost(&mut self, navmesh: &Navmesh, vertex: NavnodeIndex) -> f64 {