diff --git a/Cargo.toml b/Cargo.toml index cf9550d..b372341 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ stats = [] verbose = [] async = [] no-default-baking = [] +detailed-layers = [] serde = ["glam/serde", "bvh2d/serde", "dep:serde"] [dependencies] diff --git a/src/async_helpers.rs b/src/async_helpers.rs index 23f69fd..2cfcb1c 100644 --- a/src/async_helpers.rs +++ b/src/async_helpers.rs @@ -91,6 +91,7 @@ impl<'m> Future for FuturePath<'m> { return Poll::Ready(Some(Path { length: self.from.distance(self.to), path: vec![self.to], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(self.to, ending_polygon.layer())], })); } diff --git a/src/helpers.rs b/src/helpers.rs index f36af32..846786d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,7 +5,7 @@ use tracing::instrument; use crate::instance::EdgeSide; -const EPSILON: f32 = 1e-4; +pub(crate) const EPSILON: f32 = 1e-4; pub(crate) trait Vec2Helper { fn side(self, edge: (Vec2, Vec2)) -> EdgeSide; diff --git a/src/instance.rs b/src/instance.rs index f172419..1eee07f 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,4 +1,3 @@ -use bvh2d::EPSILON; use smallvec::SmallVec; #[cfg(feature = "tracing")] use tracing::instrument; @@ -11,6 +10,8 @@ use std::time::Instant; use glam::Vec2; use hashbrown::{hash_map::Entry, HashMap}; +#[cfg(feature = "detailed-layers")] +use crate::helpers::EPSILON; use crate::{ helpers::{heuristic, line_intersect_segment, turning_point, Vec2Helper}, Mesh, Path, SearchNode, PRECISION, @@ -61,6 +62,7 @@ pub(crate) struct SearchInstance<'m> { pub(crate) queue: BinaryHeap, pub(crate) node_buffer: Vec, pub(crate) root_history: HashMap, + #[cfg(feature = "detailed-layers")] pub(crate) from: Vec2, pub(crate) to: Vec2, pub(crate) polygon_to: u32, @@ -130,6 +132,7 @@ impl<'m> SearchInstance<'m> { queue: BinaryHeap::with_capacity(15), node_buffer: Vec::with_capacity(10), root_history: HashMap::with_capacity(10), + #[cfg(feature = "detailed-layers")] from: from.0, to: to.0, polygon_to: to.1, @@ -156,6 +159,7 @@ impl<'m> SearchInstance<'m> { let empty_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from.0, interval: (Vec2::new(0.0, 0.0), Vec2::new(0.0, 0.0)), @@ -268,45 +272,49 @@ impl<'m> SearchInstance<'m> { path.push(self.to); path_with_layers_end.push((self.to, next.polygon_to.layer())); } - - let mut path_with_layers = vec![]; - let mut from = self.from; - for (index, potential_point) in next.path_with_layers.iter().enumerate() { - if potential_point.0 == potential_point.1 { - from = potential_point.0; - path_with_layers.push((potential_point.0, potential_point.2)); - } else { - // look for next fixed point to find the intersection - let to = next - .path_with_layers - .iter() - .skip(index + 1) - .find(|point| point.0 == point.1) - .map(|point| point.0) - .unwrap_or(path_with_layers_end[0].0); - if let Some(intersection) = line_intersect_segment( - (from, to), - (potential_point.0, potential_point.1), - ) { - from = intersection; - path_with_layers.push((intersection, potential_point.2)); + #[cfg(feature = "detailed-layers")] + let path_with_layers = { + let mut path_with_layers = vec![]; + let mut from = self.from; + for (index, potential_point) in next.path_with_layers.iter().enumerate() { + if potential_point.0 == potential_point.1 { + from = potential_point.0; + path_with_layers.push((potential_point.0, potential_point.2)); + } else { + // look for next fixed point to find the intersection + let to = next + .path_with_layers + .iter() + .skip(index + 1) + .find(|point| point.0 == point.1) + .map(|point| point.0) + .unwrap_or(path_with_layers_end[0].0); + if let Some(intersection) = line_intersect_segment( + (from, to), + (potential_point.0, potential_point.1), + ) { + from = intersection; + path_with_layers.push((intersection, potential_point.2)); + } } } - } - path_with_layers.extend(path_with_layers_end); - let mut path_with_layers_peekable = path_with_layers.iter().peekable(); - let mut path_with_layers = vec![]; - while let Some(p) = path_with_layers_peekable.next() { - if let Some(n) = path_with_layers_peekable.peek() { - if p.0.distance_squared(n.0) < EPSILON { - continue; + path_with_layers.extend(path_with_layers_end); + let mut path_with_layers_peekable = path_with_layers.iter().peekable(); + let mut path_with_layers = vec![]; + while let Some(p) = path_with_layers_peekable.next() { + if let Some(n) = path_with_layers_peekable.peek() { + if p.0.distance_squared(n.0) < EPSILON { + continue; + } } + path_with_layers.push(*p); } - path_with_layers.push(*p); - } + path_with_layers + }; return InstanceStep::Found(Path { path, length: next.f + next.g, + #[cfg(feature = "detailed-layers")] path_with_layers, }); } @@ -508,11 +516,14 @@ impl<'m> SearchInstance<'m> { } let mut path = node.path.clone(); + #[cfg(feature = "detailed-layers")] let mut path_with_layers = node.path_with_layers.clone(); if root != node.root { path.push(root); + #[cfg(feature = "detailed-layers")] path_with_layers.push((root, root, node.polygon_to.layer())); } + #[cfg(feature = "detailed-layers")] if other_side.layer() != node.polygon_to.layer() { path_with_layers.push((start.0, end.0, other_side.layer())); } @@ -530,6 +541,7 @@ impl<'m> SearchInstance<'m> { let new_node = SearchNode { path, + #[cfg(feature = "detailed-layers")] path_with_layers, root, interval: (start.0, end.0), diff --git a/src/layers.rs b/src/layers.rs index 2a989eb..01eae47 100644 --- a/src/layers.rs +++ b/src/layers.rs @@ -215,13 +215,11 @@ impl Layer { mod tests { use std::collections::HashSet; + #[cfg(feature = "detailed-layers")] + use crate::helpers::line_intersect_segment; + use crate::{instance::U32Layer, Coords, Layer, Mesh, Path, Polygon, SearchNode, Vertex}; use glam::{vec2, IVec2, Vec2}; - use crate::{ - helpers::line_intersect_segment, instance::U32Layer, Coords, Layer, Mesh, Path, Polygon, - SearchNode, Vertex, - }; - fn mesh_u_grid() -> Mesh { let main_layer = Layer { vertices: vec![ @@ -299,6 +297,7 @@ mod tests { let to = vec2(1.1, 0.1); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(0.0, 1.0), vec2(1.0, 1.0)), @@ -316,6 +315,7 @@ mod tests { Path { path: vec![to], length: from.distance(to), + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(to, 0)], } ); @@ -329,6 +329,7 @@ mod tests { let to = vec2(2.1, 1.9); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(0.0, 1.0), vec2(1.0, 1.0)), @@ -360,6 +361,7 @@ mod tests { length: from.distance(vec2(1.0, 1.0)) + vec2(1.0, 1.0).distance(vec2(2.0, 1.0)) + vec2(2.0, 1.0).distance(to), + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(vec2(1.0, 1.0), 0), (vec2(2.0, 1.0), 2), (to, 2)], } ); @@ -435,6 +437,7 @@ mod tests { blocked.insert(1); let path = dbg!(mesh.path_on_layers(from, to, blocked).unwrap()); assert_eq!(path.path, vec![vec2(2.0, 2.0), vec2(3.0, 1.0), to]); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![(vec2(2.0, 2.0), 0), (vec2(3.0, 1.0), 0), (to, 0)] @@ -450,6 +453,7 @@ mod tests { let to = vec2(5.0 - i as f32 / 10.0, 0.9); let path = dbg!(mesh.path(from, to).unwrap()); assert_eq!(path.path, vec![to]); + #[cfg(feature = "detailed-layers")] assert_eq!( reduce_path_precision(path.path_with_layers), reduce_path_precision(vec![ @@ -477,6 +481,7 @@ mod tests { let to = vec2(i as f32 / 10.0, 2.1); let path = dbg!(mesh.path(from, to).unwrap()); assert_eq!(path.path, vec![to]); + #[cfg(feature = "detailed-layers")] assert_eq!( reduce_path_precision(path.path_with_layers), reduce_path_precision(vec![ @@ -506,6 +511,7 @@ mod tests { match i { 7 => { assert_eq!(path.path, vec![vec2(1.0, 2.0), to]); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![(vec2(1.0, 2.0), 1), (vec2(4.0, 1.0), 0), (to, 0)] @@ -513,6 +519,7 @@ mod tests { } _ if i < 11 => { assert_eq!(path.path, vec![vec2(1.0, 2.0), vec2(4.0, 1.0), to]); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![(vec2(1.0, 2.0), 1), (vec2(4.0, 1.0), 0), (to, 0)] @@ -520,6 +527,7 @@ mod tests { } _ if i < 15 => { assert_eq!(path.path, vec![vec2(2.0, 2.0), vec2(3.0, 1.0), to]); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![(vec2(2.0, 2.0), 0), (vec2(3.0, 1.0), 0), (to, 0)] @@ -540,6 +548,7 @@ mod tests { match i { 7 => { assert_eq!(path.path, vec![vec2(4.0, 1.0), to]); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![(vec2(4.0, 1.0), 1), (vec2(0.9999997, 2.0), 0), (to, 0)] @@ -547,6 +556,7 @@ mod tests { } _ if i < 11 => { assert_eq!(path.path, vec![vec2(4.0, 1.0), vec2(1.0, 2.0), to]); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![(vec2(4.0, 1.0), 1), (vec2(1.0, 2.0), 0), (to, 0)] @@ -554,6 +564,7 @@ mod tests { } _ if i < 15 => { assert_eq!(path.path, vec![vec2(3.0, 1.0), vec2(2.0, 2.0), to]); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![(vec2(3.0, 1.0), 0), (vec2(2.0, 2.0), 0), (to, 0)] @@ -583,6 +594,7 @@ mod tests { path.path, vec![vec2(3.0, 1.0,), vec2(4.0, 1.0,), vec2(2.5, 1.5,),], ); + #[cfg(feature = "detailed-layers")] assert_eq!( path.path_with_layers, vec![ @@ -608,6 +620,7 @@ mod tests { path_back.path, vec![vec2(4.0, 1.0,), vec2(3.0, 1.0,), vec2(2.5, 1.5,),], ); + #[cfg(feature = "detailed-layers")] assert_eq!( path_back.path_with_layers, vec![ diff --git a/src/lib.rs b/src/lib.rs index ccb8d58..8a59d36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,7 @@ pub struct Path { /// Coordinates for each step of the path. The destination is the last step. pub path: Vec, /// Coordinates for each step of the path, including when changing layer. The destination is the last step. + #[cfg(feature = "detailed-layers")] pub path_with_layers: Vec<(Vec2, u8)>, } /// A navigation mesh @@ -253,6 +254,7 @@ impl Mesh { return Some(Path { length: from.pos.distance(to.pos), path: vec![to.pos], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(to.pos, ending_polygon.layer())], }); } @@ -306,6 +308,7 @@ impl Mesh { queue: BinaryHeap::new(), node_buffer: Vec::new(), root_history: HashMap::new(), + #[cfg(feature = "detailed-layers")] from: node.root, to, polygon_to: self.get_point_location(to), @@ -343,6 +346,7 @@ impl Mesh { queue: BinaryHeap::new(), node_buffer: Vec::new(), root_history: HashMap::new(), + #[cfg(feature = "detailed-layers")] from: Vec2::ZERO, to: Vec2::ZERO, polygon_to: self.get_point_location(vec2(0.0, 0.0)), @@ -403,6 +407,7 @@ impl Mesh { #[derive(PartialEq, Debug)] struct SearchNode { path: Vec, + #[cfg(feature = "detailed-layers")] path_with_layers: Vec<(Vec2, Vec2, u8)>, root: Vec2, interval: (Vec2, Vec2), @@ -516,6 +521,7 @@ mod tests { let to = vec2(2.9, 0.9); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(1.0, 0.0), vec2(1.0, 1.0)), @@ -543,6 +549,7 @@ mod tests { Path { path: vec![to], length: from.distance(to), + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(to, 0)], } ); @@ -556,6 +563,7 @@ mod tests { let from = vec2(2.9, 0.9); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(2.0, 1.0), vec2(2.0, 0.0)), @@ -582,6 +590,7 @@ mod tests { Path { path: vec![to], length: from.distance(to), + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(to, 0)], } ); @@ -595,6 +604,7 @@ mod tests { let to = vec2(2.1, 1.9); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(0.0, 1.0), vec2(1.0, 1.0)), @@ -626,6 +636,7 @@ mod tests { length: from.distance(vec2(1.0, 1.0)) + vec2(1.0, 1.0).distance(vec2(2.0, 1.0)) + vec2(2.0, 1.0).distance(to), + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(vec2(1.0, 1.0), 0), (vec2(2.0, 1.0), 0), (to, 0)], } ); @@ -639,6 +650,7 @@ mod tests { let to = vec2(2.1, 1.9); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(1.0, 0.0), vec2(1.0, 1.0)), @@ -670,6 +682,7 @@ mod tests { length: from.distance(vec2(1.0, 1.0)) + vec2(1.0, 1.0).distance(vec2(2.0, 1.0)) + vec2(2.0, 1.0).distance(to), + #[cfg(feature = "detailed-layers")] path_with_layers: vec![(vec2(1.0, 1.0), 0), (vec2(2.0, 1.0), 0), (to, 0)], } ); @@ -744,6 +757,7 @@ mod tests { let to = vec2(7.0, 6.9); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)), @@ -790,6 +804,7 @@ mod tests { let to = vec2(13.0, 6.0); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)), @@ -860,6 +875,7 @@ mod tests { let to = vec2(5.0, 3.0); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)), @@ -927,6 +943,7 @@ mod tests { let to = vec2(3.0, 1.0); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)), @@ -990,6 +1007,7 @@ mod tests { let to = vec2(3.0, 1.0); let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)), @@ -1011,6 +1029,7 @@ mod tests { let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: from, interval: (vec2(9.75, 6.75), vec2(7.0, 4.0)), @@ -1032,6 +1051,7 @@ mod tests { let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: vec2(11.0, 3.0), interval: (vec2(10.0, 7.0), vec2(7.0, 4.0)), @@ -1056,6 +1076,7 @@ mod tests { let search_node = SearchNode { path: vec![], + #[cfg(feature = "detailed-layers")] path_with_layers: vec![], root: vec2(0.0, 0.0), interval: (vec2(1.0, 0.0), vec2(1.0, 1.0)),