diff --git a/src/async_helpers.rs b/src/async_helpers.rs index fd39765..bffdaf0 100644 --- a/src/async_helpers.rs +++ b/src/async_helpers.rs @@ -58,7 +58,7 @@ impl<'m> Future for FuturePath<'m> { if ending_polygon == u32::MAX { return Poll::Ready(None); } - if let Some(islands) = self.mesh.islands.as_ref() { + if let Some(islands) = self.mesh.layers[0].islands.as_ref() { let start_island = islands.get(starting_polygon_index as usize); let end_island = islands.get(ending_polygon as usize); if start_island.is_some() && end_island.is_some() && start_island != end_island { diff --git a/src/input/polyanya_file.rs b/src/input/polyanya_file.rs index 8abce89..8602a64 100644 --- a/src/input/polyanya_file.rs +++ b/src/input/polyanya_file.rs @@ -2,7 +2,7 @@ use std::io::{self, BufRead, Read, Write}; use glam::Vec2; -use crate::{Mesh, MeshError, Polygon, Vertex}; +use crate::{Layer, Mesh, MeshError, Polygon, Vertex}; /// A mesh read from a Polyanya file in the format `mesh 2`. /// @@ -142,15 +142,19 @@ impl TryFrom for Mesh { type Error = MeshError; fn try_from(value: PolyanyaFile) -> Result { - Mesh::new(value.vertices, value.polygons) + Ok(Mesh { + layers: vec![Layer::new(value.vertices, value.polygons)?], + ..Default::default() + }) } } impl From for PolyanyaFile { - fn from(mesh: Mesh) -> Self { + fn from(mut mesh: Mesh) -> Self { + let last_layer = mesh.layers.pop().unwrap(); PolyanyaFile { - vertices: mesh.vertices, - polygons: mesh.polygons, + vertices: last_layer.vertices, + polygons: last_layer.polygons, } } } diff --git a/src/input/triangulation.rs b/src/input/triangulation.rs index 294e9ff..82aae24 100644 --- a/src/input/triangulation.rs +++ b/src/input/triangulation.rs @@ -1,4 +1,4 @@ -use std::collections::VecDeque; +use std::{collections::VecDeque, default}; #[cfg(feature = "tracing")] use tracing::instrument; @@ -8,7 +8,7 @@ use geo::{Contains, Coord, Polygon as GeoPolygon, SimplifyVwPreserve}; use glam::{vec2, Vec2}; use spade::{ConstrainedDelaunayTriangulation, Point2, Triangulation as SpadeTriangulation}; -use crate::{Mesh, Polygon, Vertex}; +use crate::{Layer, Mesh, Polygon, Vertex}; /// An helper to create a [`Mesh`] from a list of edges and obstacle, using a constrained Delaunay triangulation. #[derive(Clone)] @@ -153,7 +153,7 @@ impl Triangulation { /// mesh.merge_polygons(); /// /// // One call to merge should have reduced the number of polygons, baking will be less expensive. - /// mesh.bake(); + /// mesh.layers[0].bake(); /// ``` #[cfg_attr(feature = "tracing", instrument(skip_all))] pub fn as_navmesh(&self) -> Mesh { @@ -239,8 +239,11 @@ impl Triangulation { drop(vertex_span); Mesh { - vertices, - polygons, + layers: vec![Layer { + vertices, + polygons, + ..Default::default() + }], ..Default::default() } } diff --git a/src/input/trimesh.rs b/src/input/trimesh.rs index 0314612..5195569 100644 --- a/src/input/trimesh.rs +++ b/src/input/trimesh.rs @@ -1,7 +1,7 @@ -use crate::{Mesh, MeshError, Polygon, Vertex}; +use crate::{Layer, Mesh, MeshError, Polygon, Vertex}; use glam::Vec2; use std::cmp::Ordering; -use std::iter; +use std::{default, iter}; trait Triangle { fn get_clockwise_neighbor(&self, index: usize) -> usize; @@ -120,7 +120,10 @@ impl TryFrom for Mesh { .into_iter() .map(|vertex| Vertex::new(vertex.coords, vertex.polygons)) .collect(); - Self::new(vertices, polygons) + Ok(Mesh { + layers: vec![Layer::new(vertices, polygons)?], + ..Default::default() + }) } } @@ -198,39 +201,42 @@ mod tests { triangles: vec![[0, 1, 4], [1, 2, 5], [5, 2, 3], [1, 5, 3], [0, 4, 3]], } .try_into()?; - assert_eq!(regular_mesh.polygons, from_trimesh.polygons); - for (index, (expected_vertex, actual_vertex)) in regular_mesh + assert_eq!( + regular_mesh.layers[0].polygons, + from_trimesh.layers[0].polygons + ); + for (index, (expected_vertex, actual_vertex)) in regular_mesh.layers[0] .vertices .iter() - .zip(from_trimesh.vertices.iter()) + .zip(from_trimesh.layers[0].vertices.iter()) .enumerate() { assert_eq!( expected_vertex.coords, actual_vertex.coords, "\nvertex {index} does not have the expected coords.\nExpected vertices: {0:?}\nGot vertices: {1:?}", - regular_mesh.vertices, from_trimesh.vertices + regular_mesh.layers[0].vertices, from_trimesh.layers[0].vertices ); assert_eq!( expected_vertex.is_corner, actual_vertex.is_corner, "\nvertex {index} does not have the expected value for `is_corner`.\nExpected vertices: {0:?}\nGot vertices: {1:?}", - regular_mesh.vertices, from_trimesh.vertices + regular_mesh.layers[0].vertices, from_trimesh.layers[0].vertices ); let adjusted_actual = wrap_to_first(&actual_vertex.polygons, |index| *index != -1).unwrap_or_else(|| panic!("vertex {index}: Found only surrounded by obstacles.\nExpected vertices: {0:?}\nGot vertices: {1:?}", - regular_mesh.vertices, from_trimesh.vertices)); + regular_mesh.layers[0].vertices, from_trimesh.layers[0].vertices)); let adjusted_expectation= wrap_to_first(&expected_vertex.polygons, |polygon| { *polygon == adjusted_actual[0] }) .unwrap_or_else(|| panic!("vertex {index}: Failed to expected polygons.\nExpected vertices: {0:?}\nGot vertices: {1:?}", - regular_mesh.vertices, from_trimesh.vertices)); + regular_mesh.layers[0].vertices, from_trimesh.layers[0].vertices)); assert_eq!( adjusted_expectation, adjusted_actual, "\nvertex {index} does not have the expected polygons.\nExpected vertices: {0:?}\nGot vertices: {1:?}", - regular_mesh.vertices, from_trimesh.vertices + regular_mesh.layers[0].vertices, from_trimesh.layers[0].vertices ); } Ok(()) diff --git a/src/instance.rs b/src/instance.rs index 873b4fd..627ce33 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -75,7 +75,7 @@ impl<'m> SearchInstance<'m> { to: (Vec2, u32), #[cfg(feature = "stats")] start: Instant, ) -> Self { - let starting_polygon = &mesh.polygons[from.1 as usize]; + let starting_polygon = &mesh.layers[0].polygons[from.1 as usize]; let mut search_instance = SearchInstance { queue: BinaryHeap::with_capacity(15), @@ -116,12 +116,12 @@ impl<'m> SearchInstance<'m> { }; for edge in starting_polygon.edges_index().iter() { - let start = if let Some(v) = mesh.vertices.get(edge.0 as usize) { + let start = if let Some(v) = mesh.layers[0].vertices.get(edge.0 as usize) { v } else { continue; }; - let end = if let Some(v) = mesh.vertices.get(edge.1 as usize) { + let end = if let Some(v) = mesh.layers[0].vertices.get(edge.1 as usize) { v } else { continue; @@ -134,8 +134,7 @@ impl<'m> SearchInstance<'m> { if other_side == to.1 as isize || (other_side != isize::MAX - && !search_instance - .mesh + && !search_instance.mesh.layers[0] .polygons .get(other_side as usize) .unwrap() @@ -234,7 +233,7 @@ impl<'m> SearchInstance<'m> { pub(crate) fn edges_between(&self, node: &SearchNode) -> SmallVec<[Successor; 10]> { let mut successors = SmallVec::new(); - let polygon = &self.mesh.polygons[node.polygon_to as usize]; + let polygon = &self.mesh.layers[0].polygons[node.polygon_to as usize]; // if node.interval.0.distance(node.root) < 1.0e-5 // || node.interval.1.distance(node.root) < 1.0e-5 @@ -259,15 +258,15 @@ impl<'m> SearchInstance<'m> { let mut ty = SuccessorType::RightNonObservable; for edge in &polygon.circular_edges_index(right_index..=left_index) { - if edge.0.max(edge.1) as usize > self.mesh.vertices.len() { + if edge.0.max(edge.1) as usize > self.mesh.layers[0].vertices.len() { continue; } // Bounds are checked just before #[allow(unsafe_code)] let (start, end) = unsafe { ( - self.mesh.vertices.get_unchecked(edge.0 as usize), - self.mesh.vertices.get_unchecked(edge.1 as usize), + self.mesh.layers[0].vertices.get_unchecked(edge.0 as usize), + self.mesh.layers[0].vertices.get_unchecked(edge.1 as usize), ) }; let mut start_point = start.coords; @@ -503,8 +502,12 @@ impl<'m> SearchInstance<'m> { #[allow(unsafe_code)] let (start, end) = unsafe { ( - self.mesh.vertices.get_unchecked(successor.edge.0 as usize), - self.mesh.vertices.get_unchecked(successor.edge.1 as usize), + self.mesh.layers[0] + .vertices + .get_unchecked(successor.edge.0 as usize), + self.mesh.layers[0] + .vertices + .get_unchecked(successor.edge.1 as usize), ) }; @@ -536,8 +539,7 @@ impl<'m> SearchInstance<'m> { // prune edges that only lead to one other polygon, and not the target: dead end pruning if self.polygon_to != other_side - && self - .mesh + && self.mesh.layers[0] .polygons .get(other_side as usize) .unwrap() @@ -561,7 +563,10 @@ impl<'m> SearchInstance<'m> { } continue; } - let vertex = self.mesh.vertices.get(node.edge.0 as usize).unwrap(); + let vertex = self.mesh.layers[0] + .vertices + .get(node.edge.0 as usize) + .unwrap(); if vertex.is_corner && vertex.coords.distance_squared(node.interval.0) < EPSILON { @@ -583,7 +588,10 @@ impl<'m> SearchInstance<'m> { } continue; } - let vertex = self.mesh.vertices.get(node.edge.1 as usize).unwrap(); + let vertex = self.mesh.layers[0] + .vertices + .get(node.edge.1 as usize) + .unwrap(); if vertex.is_corner && vertex.coords.distance_squared(node.interval.1) < EPSILON { diff --git a/src/lib.rs b/src/lib.rs index 6bf557a..4b08b0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,16 +63,33 @@ pub struct Path { pub path: Vec, } -/// A navigation mesh #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Mesh { +pub struct Layer { /// List of `Vertex` in this mesh pub vertices: Vec, /// List of `Polygons` in this mesh pub polygons: Vec, baked_polygons: Option, islands: Option>, +} + +impl Default for Layer { + fn default() -> Self { + Self { + vertices: Default::default(), + polygons: Default::default(), + baked_polygons: Default::default(), + islands: Default::default(), + } + } +} + +/// A navigation mesh +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Mesh { + pub layers: Vec, delta: f32, #[cfg(feature = "stats")] pub(crate) scenarios: Cell, @@ -81,17 +98,24 @@ pub struct Mesh { impl Default for Mesh { fn default() -> Self { Self { + layers: vec![], delta: 0.1, - vertices: Default::default(), - polygons: Default::default(), - baked_polygons: Default::default(), - islands: Default::default(), #[cfg(feature = "stats")] scenarios: Cell::new(0), } } } +impl Mesh { + pub fn new(vertices: Vec, polygons: Vec) -> Result { + let layer = Layer::new(vertices, polygons)?; + Ok(Mesh { + layers: vec![layer], + ..Default::default() + }) + } +} + struct Root(Vec2); impl PartialEq for Root { @@ -133,7 +157,7 @@ pub enum MeshError { InvalidMesh, } -impl Mesh { +impl Layer { /// Remove pre-computed optimizations from the mesh. Call this if you modified the [`Mesh`]. #[inline] pub fn unbake(&mut self) { @@ -224,19 +248,21 @@ impl Mesh { if vertices.is_empty() || polygons.is_empty() { return Err(MeshError::EmptyMesh); } - let mut mesh = Mesh { + let mut layer = Layer { vertices, polygons, ..Default::default() }; #[cfg(not(feature = "no-default-baking"))] - mesh.bake(); + layer.bake(); // just to not get a warning on the mut borrow. should be pretty much free anyway #[cfg(feature = "no-default-baking")] mesh.unbake(); - Ok(mesh) + Ok(layer) } +} +impl Mesh { /// Compute a path between two points. /// /// This method returns a `Future`, to get the path in a blocking way use [`Self::path`]. @@ -271,7 +297,7 @@ impl Mesh { if ending_polygon == u32::MAX { return None; } - if let Some(islands) = self.islands.as_ref() { + if let Some(islands) = self.layers[0].islands.as_ref() { let start_island = islands.get(starting_polygon_index as usize); let end_island = islands.get(ending_polygon as usize); if start_island.is_some() && end_island.is_some() && start_island != end_island { @@ -310,7 +336,7 @@ impl Mesh { ); // Limit search to avoid an infinite loop. - for _ in 0..self.polygons.len() * 1000 { + for _ in 0..self.layers[0].polygons.len() * 1000 { match search_instance.next() { InstanceStep::Found(path) => return Some(path), InstanceStep::NotFound => return None, @@ -427,7 +453,7 @@ impl Mesh { ] .iter() .map(|delta| { - if self.baked_polygons.is_none() { + if self.layers[0].baked_polygons.is_none() { self.get_point_location_unit(point + *delta) } else { self.get_point_location_unit_baked(point + *delta) @@ -439,7 +465,7 @@ impl Mesh { #[cfg_attr(feature = "tracing", instrument(skip_all))] fn get_point_location_unit(&self, point: Vec2) -> u32 { - for (i, polygon) in self.polygons.iter().enumerate() { + for (i, polygon) in self.layers[0].polygons.iter().enumerate() { if self.point_in_polygon(point, polygon) { return i as u32; } @@ -449,11 +475,12 @@ impl Mesh { #[cfg_attr(feature = "tracing", instrument(skip_all))] fn get_point_location_unit_baked(&self, point: Vec2) -> u32 { - self.baked_polygons + self.layers[0] + .baked_polygons .as_ref() .unwrap() .contains_iterator(&point) - .find(|index| self.point_in_polygon(point, &self.polygons[*index])) + .find(|index| self.point_in_polygon(point, &self.layers[0].polygons[*index])) .map(|index| index as u32) .unwrap_or(u32::MAX) } @@ -463,7 +490,7 @@ impl Mesh { fn point_in_polygon(&self, point: Vec2, polygon: &Polygon) -> bool { let mut edged = false; for edge in polygon.edges_index().iter() { - if edge.0.max(edge.1) as usize >= self.vertices.len() { + if edge.0.max(edge.1) as usize >= self.layers[0].vertices.len() { return false; } edged = true; @@ -471,8 +498,14 @@ impl Mesh { #[allow(unsafe_code)] let (last, next) = unsafe { ( - self.vertices.get_unchecked(edge.0 as usize).coords, - self.vertices.get_unchecked(edge.1 as usize).coords, + self.layers[0] + .vertices + .get_unchecked(edge.0 as usize) + .coords, + self.layers[0] + .vertices + .get_unchecked(edge.1 as usize) + .coords, ) }; @@ -551,10 +584,10 @@ mod tests { use glam::Vec2; - use crate::{helpers::*, Mesh, Path, Polygon, SearchNode, Vertex}; + use crate::{helpers::*, Layer, Mesh, Path, Polygon, SearchNode, Vertex}; fn mesh_u_grid() -> Mesh { - Mesh { + let layer = Layer { vertices: vec![ Vertex::new(Vec2::new(0., 0.), vec![0, -1]), Vertex::new(Vec2::new(1., 0.), vec![0, 1, -1]), @@ -577,13 +610,17 @@ mod tests { Polygon::new(vec![6, 7, 11, 10], true), ], ..Default::default() + }; + Mesh { + layers: vec![layer], + ..Default::default() } } #[test] fn point_in_polygon() { let mut mesh = mesh_u_grid(); - mesh.bake(); + mesh.layers[0].bake(); assert_eq!(mesh.get_point_location(Vec2::new(0.5, 0.5)), 0); assert_eq!(mesh.get_point_location(Vec2::new(1.5, 0.5)), 1); assert_eq!(mesh.get_point_location(Vec2::new(0.5, 1.5)), 3); @@ -761,12 +798,12 @@ mod tests { #[test] fn empty_mesh_fails() { - let mesh = Mesh::new(vec![], vec![]); - assert!(matches!(mesh, Err(crate::MeshError::EmptyMesh))); + let layer = Layer::new(vec![], vec![]); + assert!(matches!(layer, Err(crate::MeshError::EmptyMesh))); } fn mesh_from_paper() -> Mesh { - Mesh { + let layer = Layer { vertices: vec![ Vertex::new(Vec2::new(0., 6.), vec![0, -1]), // 0 Vertex::new(Vec2::new(2., 5.), vec![0, -1, 2]), // 1 @@ -802,13 +839,17 @@ mod tests { Polygon::new(vec![11, 17, 20, 21], true), ], ..Default::default() + }; + Mesh { + layers: vec![layer], + ..Default::default() } } #[test] fn paper_point_in_polygon() { let mut mesh = mesh_from_paper(); - mesh.bake(); + mesh.layers[0].bake(); assert_eq!(mesh.get_point_location(Vec2::new(0.5, 0.5)), u32::MAX); assert_eq!(mesh.get_point_location(Vec2::new(2.0, 6.0)), 0); assert_eq!(mesh.get_point_location(Vec2::new(2.0, 5.1)), 0); diff --git a/src/merger.rs b/src/merger.rs index 998b432..6153c52 100644 --- a/src/merger.rs +++ b/src/merger.rs @@ -10,14 +10,15 @@ impl Mesh { /// This merge neighbouring polygons when possible, keeping them convex. #[cfg_attr(feature = "tracing", instrument(skip_all))] pub fn merge_polygons(&mut self) -> bool { - self.unbake(); - let mut area = self + // TODO: do it for each layer, keep the stitch polygons unmerged + self.layers[0].unbake(); + let mut area = self.layers[0] .polygons .iter() .enumerate() .map(|(i, poly)| (i, poly.area(self))) .collect::>(); - let mut union_polygons = UnionFind::new(self.polygons.len() as i32); + let mut union_polygons = UnionFind::new(self.layers[0].polygons.len() as i32); area.sort_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap().reverse()); @@ -26,14 +27,14 @@ impl Mesh { // already merged continue; } - let poly = &self.polygons[*poly_index]; + let poly = &self.layers[0].polygons[*poly_index]; for edge in poly.edges_index() { - let start = if let Some(v) = self.vertices.get(edge.0 as usize) { + let start = if let Some(v) = self.layers[0].vertices.get(edge.0 as usize) { v } else { continue; }; - let end = if let Some(v) = self.vertices.get(edge.1 as usize) { + let end = if let Some(v) = self.layers[0].vertices.get(edge.1 as usize) { v } else { continue; @@ -52,7 +53,7 @@ impl Mesh { continue; } - let other_vertices = &self.polygons[other_side as usize].vertices; + let other_vertices = &self.layers[0].polygons[other_side as usize].vertices; let mut joined_vertices_index = Vec::with_capacity(poly.vertices.len() + other_vertices.len() - 2); let mut joined_vertices = @@ -65,7 +66,7 @@ impl Mesh { .take_while(|i| **i != edge.0) { joined_vertices_index.push(*i); - let c = self.vertices[*i as usize].coords; + let c = self.layers[0].vertices[*i as usize].coords; joined_vertices.push(geo::Coord { x: c.x, y: c.y }); } for i in other_vertices @@ -75,22 +76,22 @@ impl Mesh { .take_while(|i| **i != edge.1) { joined_vertices_index.push(*i); - let c = self.vertices[*i as usize].coords; + let c = self.layers[0].vertices[*i as usize].coords; joined_vertices.push(geo::Coord { x: c.x, y: c.y }); } let mut line = geo::LineString(joined_vertices); line.close(); if line.is_ccw_convex() { union_polygons.union(*poly_index as i32, other_side as i32); - self.polygons[*poly_index].vertices = joined_vertices_index; + self.layers[0].polygons[*poly_index].vertices = joined_vertices_index; // TODO: correctly set the value for merged polygon - self.polygons[*poly_index].is_one_way = false; + self.layers[0].polygons[*poly_index].is_one_way = false; break; } } } - let mut new_indexes = vec![-1; self.polygons.len()]; + let mut new_indexes = vec![-1_isize; self.layers[0].polygons.len()]; let mut kept = 0; for (i, p) in union_polygons.parent.iter().enumerate() { let p = union_polygons.find(*p); @@ -102,15 +103,17 @@ impl Mesh { if i as i32 == p { let j = new_indexes[p as usize] as usize; if i != j { - self.polygons.swap(i, j); + self.layers[0].polygons.swap(i, j); } } else { new_indexes[i] = new_indexes[p as usize]; } } - self.polygons.resize_with(kept as usize, || unreachable!()); + self.layers[0] + .polygons + .resize_with(kept as usize, || unreachable!()); - for vertex in self.vertices.iter_mut() { + for vertex in self.layers[0].vertices.iter_mut() { for p in vertex.polygons.iter_mut() { if *p != -1 { *p = new_indexes[*p as usize]; @@ -171,8 +174,8 @@ mod test { use crate::{Mesh, Polygon, Triangulation, Vertex}; fn mesh_u_grid() -> Mesh { - Mesh { - vertices: vec![ + Mesh::new( + vec![ Vertex::new(Vec2::new(0., 0.), vec![0, -1]), Vertex::new(Vec2::new(1., 0.), vec![0, 1, -1]), Vertex::new(Vec2::new(2., 0.), vec![1, 2, -1]), @@ -190,7 +193,7 @@ mod test { Vertex::new(Vec2::new(2., 3.), vec![6, -1]), Vertex::new(Vec2::new(3., 3.), vec![6, -1]), ], - polygons: vec![ + vec![ Polygon::new(vec![0, 1, 5, 4], false), Polygon::new(vec![1, 2, 6, 5], false), Polygon::new(vec![2, 3, 7, 6], false), @@ -199,70 +202,70 @@ mod test { Polygon::new(vec![8, 9, 13, 12], false), Polygon::new(vec![10, 11, 15, 14], false), ], - ..Default::default() - } + ) + .unwrap() } #[test] fn merge_u() { let mut mesh = mesh_u_grid(); while mesh.merge_polygons() {} - mesh.bake(); - assert_eq!(mesh.polygons.len(), 3); + mesh.layers[0].bake(); + assert_eq!(mesh.layers[0].polygons.len(), 3); } #[test] fn merge_and_path() { let mut mesh = mesh_u_grid(); while mesh.merge_polygons() {} - mesh.bake(); - assert_eq!(mesh.polygons.len(), 3); + mesh.layers[0].bake(); + assert_eq!(mesh.layers[0].polygons.len(), 3); assert_eq!( - mesh.polygons[0], + mesh.layers[0].polygons[0], Polygon::new(vec![5, 4, 0, 1, 2, 6], false) ); assert_eq!( - mesh.polygons[1], + mesh.layers[0].polygons[1], Polygon::new(vec![10, 6, 2, 3, 7, 11, 15, 14], false) ); assert_eq!( - mesh.polygons[2], + mesh.layers[0].polygons[2], Polygon::new(vec![8, 4, 5, 9, 13, 12], false) ); assert_eq!( - mesh.vertices[0], + mesh.layers[0].vertices[0], Vertex::new(Vec2::new(0.0, 0.0), vec![0, -1]) ); assert_eq!( - mesh.vertices[1], + mesh.layers[0].vertices[1], Vertex::new(Vec2::new(1.0, 0.0), vec![0, -1]) ); assert_eq!( - mesh.vertices[2], + mesh.layers[0].vertices[2], Vertex::new(Vec2::new(2.0, 0.0), vec![0, 1, -1]) ); assert_eq!( - mesh.vertices[3], + mesh.layers[0].vertices[3], Vertex::new(Vec2::new(3.0, 0.0), vec![1, -1]) ); assert_eq!( - mesh.vertices[4], + mesh.layers[0].vertices[4], Vertex::new(Vec2::new(0.0, 1.0), vec![2, 0, -1]) ); assert_eq!( - mesh.vertices[5], + mesh.layers[0].vertices[5], Vertex::new(Vec2::new(1.0, 1.0), vec![2, 0, -1]) ); assert_eq!( - mesh.vertices[6], + mesh.layers[0].vertices[6], Vertex::new(Vec2::new(2.0, 1.0), vec![1, 0, -1]) ); assert_eq!( - mesh.vertices[7], + mesh.layers[0].vertices[7], Vertex::new(Vec2::new(3.0, 1.0), vec![1, -1]) ); assert_eq!( - mesh.vertices[8], + mesh.layers[0].vertices[8], Vertex::new(Vec2::new(0.0, 2.0), vec![2, -1]) ); dbg!(mesh.path(Vec2::new(0.5, 0.5), Vec2::new(2.5, 1.5))); @@ -288,8 +291,8 @@ mod test { while mesh.merge_polygons() { // println!("{:#?}", mesh); } - mesh.bake(); - assert_eq!(mesh.polygons.len(), 4); + mesh.layers[0].bake(); + assert_eq!(mesh.layers[0].polygons.len(), 4); dbg!(mesh.path(Vec2::new(0.5, 0.5), Vec2::new(9.5, 9.5))); } @@ -318,13 +321,13 @@ mod test { triangulation.simplify(0.001); let mut mesh = triangulation.as_navmesh(); - mesh.unbake(); + mesh.layers[0].unbake(); // println!("{:#?}", mesh); while mesh.merge_polygons() { // println!("{:#?}", mesh); } - mesh.bake(); - assert_eq!(mesh.polygons.len(), 6); + mesh.layers[0].bake(); + assert_eq!(mesh.layers[0].polygons.len(), 6); dbg!(mesh.path(Vec2::new(-4.5, 4.0), Vec2::new(-4.0, -4.5))); } } diff --git a/src/primitives.rs b/src/primitives.rs index f6c1f79..1cd2809 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -158,7 +158,7 @@ impl Polygon { self.vertices .iter() .map(|v| { - let c = mesh.vertices[*v as usize].coords; + let c = mesh.layers[0].vertices[*v as usize].coords; Coord::from((c.x, c.y)) }) .collect(), diff --git a/tests/arena-merged.rs b/tests/arena-merged.rs index cd2fe2b..f3a5cb7 100644 --- a/tests/arena-merged.rs +++ b/tests/arena-merged.rs @@ -203,7 +203,7 @@ fn arena_merged() { 21.0575 ); assert_delta!( - arena.path(Vec2::new(1.0, 10.0), Vec2::new(21.0, 2.0)), + dbg!(arena.path(Vec2::new(1.0, 10.0), Vec2::new(21.0, 2.0))), 21.5407 ); assert_delta!( diff --git a/tests/triangulation.rs b/tests/triangulation.rs index 6e9838a..9edd86c 100644 --- a/tests/triangulation.rs +++ b/tests/triangulation.rs @@ -62,7 +62,7 @@ fn is_in_mesh_4_obstacles() { triangulation.simplify(0.5); let mesh: Mesh = triangulation.as_navmesh(); - dbg!(mesh.polygons.len()); + dbg!(mesh.layers[0].polygons.len()); for i in 0..10 { for j in 0..10 { if i > 2 && i < 8 && j > 2 && j < 8 { @@ -182,10 +182,10 @@ fn is_in_mesh_simplified() { }) .collect(), ); - let polygons_before = triangulation.as_navmesh().polygons; + let polygons_before = triangulation.as_navmesh().layers[0].polygons.clone(); triangulation.simplify(0.1); let mesh: Mesh = triangulation.as_navmesh(); - assert!(dbg!(polygons_before.len()) > dbg!(mesh.polygons.len())); + assert!(dbg!(polygons_before.len()) > dbg!(mesh.layers[0].polygons.len())); for i in 0..20 { for j in 0..20 { let point = vec2(i as f32 / 2.0, j as f32 / 2.0); @@ -228,12 +228,19 @@ fn is_in_mesh_overlapping_simplified() { let mesh_before = triangulation.as_navmesh(); triangulation.simplify(0.01); let mesh: Mesh = triangulation.as_navmesh(); - assert!(dbg!(mesh_before.polygons.len()) > dbg!(mesh.polygons.len())); + assert!(dbg!(mesh_before.layers[0].polygons.len()) > dbg!(mesh.layers[0].polygons.len())); let resolution = 5; for i in 0..(10 * resolution) { for j in 0..(10 * resolution) { let point = vec2(i as f32 / resolution as f32, j as f32 / resolution as f32); assert_eq!(mesh.point_in_mesh(point), mesh_before.point_in_mesh(point)); + match (mesh.point_in_mesh(point), mesh_before.point_in_mesh(point)) { + (true, true) => print!(" "), + (true, false) => print!("."), + (false, true) => print!("^"), + (false, false) => print!("#"), + } } + println!(""); } }