polyanya/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(
3    missing_debug_implementations,
4    missing_copy_implementations,
5    trivial_casts,
6    trivial_numeric_casts,
7    unsafe_code,
8    unstable_features,
9    unused_import_braces,
10    unused_qualifications,
11    missing_docs
12)]
13#![cfg_attr(docsrs, feature(doc_cfg))]
14
15const PRECISION: f32 = 1000.0;
16
17#[cfg(feature = "stats")]
18use std::{cell::Cell, time::Instant};
19use std::{
20    cmp::Ordering,
21    collections::HashSet,
22    fmt::{self, Debug, Display},
23};
24
25use bvh2d::aabb::{Bounded, AABB};
26use glam::{FloatExt, Vec2, Vec3, Vec3Swizzles};
27
28use helpers::{line_intersect_segment, Vec2Helper, EPSILON};
29use instance::{InstanceStep, U32Layer};
30use log::error;
31use thiserror::Error;
32#[cfg(feature = "tracing")]
33use tracing::instrument;
34
35#[cfg(feature = "serde")]
36use serde::{Deserialize, Serialize};
37
38#[cfg(feature = "async")]
39mod async_helpers;
40mod helpers;
41mod input;
42mod instance;
43mod layers;
44mod merger;
45mod mesh_cleanup;
46mod primitives;
47mod stitching;
48
49#[cfg(feature = "async")]
50pub use async_helpers::FuturePath;
51pub use geo;
52pub use input::polyanya_file::PolyanyaFile;
53#[cfg(feature = "recast")]
54pub use input::recast::{RecastFullMesh, RecastPolyMesh, RecastPolyMeshDetail};
55pub use input::triangulation::Triangulation;
56pub use input::trimesh::Trimesh;
57pub use layers::Layer;
58pub use primitives::{Polygon, Vertex};
59
60use crate::instance::SearchInstance;
61
62/// A path between two points.
63#[derive(Debug, PartialEq)]
64pub struct Path {
65    /// Length of the path.
66    pub length: f32,
67    /// Coordinates for each step of the path. The destination is the last step.
68    pub path: Vec<Vec2>,
69    /// Coordinates for each step of the path, including when changing layer. The destination is the last step.
70    #[cfg(feature = "detailed-layers")]
71    #[cfg_attr(docsrs, doc(cfg(feature = "detailed-layers")))]
72    pub path_with_layers: Vec<(Vec2, u8)>,
73    /// Indices of the polygons through which the path passes.
74    path_through_polygons: Vec<u32>,
75}
76
77impl Path {
78    /// Returns the path with height information on the Y axis.
79    ///
80    /// This can add points to the path when needed to follow the terrain height.
81    pub fn path_with_height(&self, start: Vec3, end: Vec3, mesh: &Mesh) -> Vec<Vec3> {
82        let mut heighted_path = Vec::with_capacity(self.path.len());
83        let mut current = start;
84        let mut next_i = 0;
85        let mut next_coords: Coords = Coords::on_mesh(self.path[next_i]);
86        for polygon_index in &self.path_through_polygons {
87            let layer = &mesh.layers[polygon_index.layer() as usize];
88            let polygon = &layer.polygons[polygon_index.polygon() as usize];
89            if polygon.contains(layer, self.path[next_i]) {
90                next_coords = Coords {
91                    pos: self.path[next_i],
92                    layer: Some(polygon_index.layer()),
93                    polygon_index: *polygon_index,
94                };
95                break;
96            }
97        }
98        let mut next = next_coords.position_with_height(mesh);
99        for (step, polygon_index) in self
100            .path_through_polygons
101            .iter()
102            .enumerate()
103            .take(self.path_through_polygons.len() - 1)
104        {
105            let layer = &mesh.layers[polygon_index.layer() as usize];
106
107            let polygon = &layer.polygons[polygon_index.polygon() as usize];
108            if *polygon_index == next_coords.polygon_index {
109                next_i += 1;
110                heighted_path.push(next);
111                current = next;
112                for polygon_index in &self.path_through_polygons[step..] {
113                    let layer = &mesh.layers[polygon_index.layer() as usize];
114                    let polygon = &layer.polygons[polygon_index.polygon() as usize];
115                    if self.path.len() < next_i {
116                        // TODO: shouldn't happen
117                        break;
118                    }
119                    if polygon.contains(layer, self.path[next_i]) {
120                        next_coords = Coords {
121                            pos: self.path[next_i],
122                            layer: Some(polygon_index.layer()),
123                            polygon_index: *polygon_index,
124                        };
125                        break;
126                    }
127                }
128                next = next_coords.position_with_height(mesh);
129            }
130            let a = layer.vertices[polygon.vertices[0] as usize]
131                .coords
132                .extend(layer.height[polygon.vertices[0] as usize])
133                .xzy();
134            let b = layer.vertices[polygon.vertices[1] as usize]
135                .coords
136                .extend(layer.height[polygon.vertices[1] as usize])
137                .xzy();
138            let c = layer.vertices[polygon.vertices[2] as usize]
139                .coords
140                .extend(layer.height[polygon.vertices[2] as usize])
141                .xzy();
142            let polygon_normal = (b - a).cross(c - a);
143            let path_direction = next - current;
144            if path_direction.dot(polygon_normal).abs() > EPSILON {
145                let poly_coords = polygon.coords(layer);
146                let closing = vec![*poly_coords.last().unwrap(), *poly_coords.first().unwrap()];
147
148                if let Some(new) = poly_coords
149                    .windows(2)
150                    .chain([closing.as_slice()])
151                    .filter_map(|edge| {
152                        line_intersect_segment((current.xz(), next.xz()), (edge[0], edge[1]))
153                    })
154                    .filter(|p| p.in_bounding_box((current.xz(), next.xz())))
155                    .max_by_key(|p| (current.xz().distance_squared(*p) / EPSILON) as u32)
156                {
157                    if new.distance_squared(current.xz()) > EPSILON {
158                        let new = Coords {
159                            pos: new,
160                            layer: Some(polygon_index.layer()),
161                            polygon_index: *polygon_index,
162                        }
163                        .position_with_height(mesh);
164                        heighted_path.push(new);
165                        current = new;
166                    }
167                }
168            }
169        }
170        heighted_path.push(end);
171        heighted_path
172    }
173
174    /// Returns the polygons that the path goes through.
175    pub fn polygons(&self) -> Vec<(u8, u32)> {
176        self.path_through_polygons
177            .iter()
178            .map(|poly_index| (poly_index.layer(), poly_index.polygon()))
179            .collect()
180    }
181}
182
183/// A navigation mesh
184#[derive(Debug, Clone)]
185#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
186pub struct Mesh {
187    /// Layers of the NavMesh
188    pub layers: Vec<Layer>,
189    /// Precision used when searching for a point in a mesh
190    pub search_delta: f32,
191    /// Number of steps before stopping searching for a point in a mesh
192    pub search_steps: u32,
193    #[cfg(feature = "stats")]
194    pub(crate) scenarios: Cell<u32>,
195}
196
197/// A point in the navigation mesh
198#[derive(Debug, PartialEq, Clone, Copy)]
199pub struct Coords {
200    /// The position
201    pos: Vec2,
202    /// The layer
203    ///
204    /// If specified, the point will be searched in that layer only.
205    layer: Option<u8>,
206    /// internal: this coords have been built by a search on the mesh that found the polygon index
207    /// if used for a path, this will be used directly instead of searching for it again in the mesh
208    /// default value is u32::MAX which means it hasn't been searched
209    polygon_index: u32,
210}
211
212impl From<Vec2> for Coords {
213    fn from(value: Vec2) -> Self {
214        Coords {
215            pos: value,
216            layer: None,
217            polygon_index: u32::MAX,
218        }
219    }
220}
221
222impl Coords {
223    /// A point on the navigation mesh
224    pub fn on_mesh(pos: Vec2) -> Self {
225        pos.into()
226    }
227
228    /// A point on the navigation mesh on the specified layer
229    pub fn on_layer(pos: Vec2, layer: u8) -> Self {
230        Coords {
231            pos,
232            layer: Some(layer),
233            polygon_index: u32::MAX,
234        }
235    }
236
237    /// Position of this point
238    #[inline]
239    pub fn position(&self) -> Vec2 {
240        self.pos
241    }
242
243    /// Layer of this point, if known
244    #[inline]
245    pub fn layer(&self) -> Option<u8> {
246        self.layer
247    }
248
249    /// Polygon index of this point
250    #[inline]
251    pub fn polygon(&self) -> u32 {
252        self.polygon_index
253    }
254
255    /// Height of this point
256    pub fn height(&self, mesh: &Mesh) -> f32 {
257        if self.polygon_index == u32::MAX {
258            return 0.0;
259        }
260        let layer = &mesh.layers[self.layer().unwrap_or(0) as usize];
261        let poly = &layer.polygons[self.polygon_index.polygon() as usize];
262
263        let closing = vec![
264            *poly.vertices.last().unwrap(),
265            *poly.vertices.first().unwrap(),
266        ];
267
268        if let Some(segment) = poly
269            .vertices
270            .windows(2)
271            .chain([closing.as_slice()])
272            .find(|edge| {
273                self.pos.on_segment((
274                    layer.vertices[edge[0] as usize].coords,
275                    layer.vertices[edge[1] as usize].coords,
276                ))
277            })
278        {
279            let (a, b) = (
280                layer.vertices[segment[0] as usize].coords,
281                layer.vertices[segment[1] as usize].coords,
282            );
283            let t = (self.pos - a).dot(b - a) / (b - a).dot(b - a);
284            return layer.height[segment[0] as usize].lerp(layer.height[segment[1] as usize], t);
285        }
286
287        // TODO: should find the position of the point within the polygon and weight each polygonpoint height based on its distance to the point
288        poly.vertices
289            .iter()
290            .map(|i| *layer.height.get(*i as usize).unwrap_or(&0.0))
291            .sum::<f32>()
292            / poly.vertices.len() as f32
293    }
294
295    /// Position of the point within the mesh, including its height on the Y axis.
296    pub fn position_with_height(&self, mesh: &Mesh) -> Vec3 {
297        Vec3::new(self.pos.x, self.height(mesh), self.pos.y)
298    }
299}
300
301impl Display for Coords {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        if let Some(layer) = self.layer {
304            write!(f, "({}, {})[{}]", self.pos.x, self.pos.y, layer)
305        } else {
306            write!(f, "({}, {})", self.pos.x, self.pos.y)
307        }
308    }
309}
310
311impl Default for Mesh {
312    fn default() -> Self {
313        Self {
314            layers: vec![],
315            search_delta: 0.1,
316            search_steps: 2,
317            #[cfg(feature = "stats")]
318            scenarios: Cell::new(0),
319        }
320    }
321}
322
323impl Mesh {
324    /// Create a new single layer NavMesh
325    pub fn new(vertices: Vec<Vertex>, polygons: Vec<Polygon>) -> Result<Self, MeshError> {
326        let layer = Layer::new(vertices, polygons)?;
327        Ok(Mesh {
328            layers: vec![layer],
329            ..Default::default()
330        })
331    }
332}
333
334struct BoundedPolygon {
335    aabb: (Vec2, Vec2),
336}
337
338impl Bounded for BoundedPolygon {
339    fn aabb(&self) -> AABB {
340        AABB::with_bounds(self.aabb.0, self.aabb.1)
341    }
342}
343
344/// Errors that can happen when working creating a [`Mesh`]
345#[derive(Error, Debug, Copy, Clone, PartialEq)]
346pub enum MeshError {
347    /// The mesh is empty.
348    #[error("The mesh is empty")]
349    EmptyMesh,
350    /// The mesh is invalid, such as having a vertex that does not belong to any polygon.
351    #[error("The mesh is invalid")]
352    InvalidMesh,
353    /// One of the layer has too many polygons (more than 2^24-1).
354    #[error("One layer has too many polygons")]
355    TooManyPolygons,
356}
357
358impl Mesh {
359    /// Pre-compute optimizations on the mesh
360    ///
361    /// Call [Layer::bake] on each layer. If the mesh has several layers, it must be called before stitching.
362    pub fn bake(&mut self) {
363        for layer in self.layers.iter_mut() {
364            layer.bake();
365        }
366    }
367
368    /// Remove pre-computed optimizations from the mesh. Call this if you modified the [`Mesh`].
369    #[inline]
370    pub fn unbake(&mut self) {
371        for layer in self.layers.iter_mut() {
372            layer.unbake();
373        }
374    }
375
376    /// Compute a path between two points.
377    ///
378    /// This method returns a `Future`, to get the path in a blocking way use [`Self::path`].
379    #[cfg(feature = "async")]
380    #[cfg_attr(feature = "tracing", instrument(skip_all))]
381    pub fn get_path(&self, from: Vec2, to: Vec2) -> FuturePath<'_> {
382        FuturePath {
383            from,
384            to,
385            mesh: self,
386            instance: None,
387            ending_polygon: u32::MAX,
388        }
389    }
390
391    /// Compute a path between two points.
392    ///
393    /// This will be a [`Path`] if a path is found, or `None` if not.
394    ///
395    /// This method is blocking, to get the path in an async way use [`Self::get_path`].
396    #[cfg_attr(feature = "tracing", instrument(skip_all))]
397    #[inline(always)]
398    pub fn path(&self, from: impl Into<Coords>, to: impl Into<Coords>) -> Option<Path> {
399        self.path_on_layers(from, to, HashSet::default())
400    }
401
402    /// Compute a path between two points.
403    ///
404    /// This will be a [`Path`] if a path is found, or `None` if not.
405    ///
406    /// This method is blocking, to get the path in an async way use [`Self::get_path`].
407    #[cfg_attr(feature = "tracing", instrument(skip_all))]
408    #[inline(always)]
409    pub fn path_on_layers(
410        &self,
411        from: impl Into<Coords>,
412        to: impl Into<Coords>,
413        blocked_layers: HashSet<u8>,
414    ) -> Option<Path> {
415        #[cfg(feature = "stats")]
416        let start = Instant::now();
417
418        let from = from.into();
419        let to = to.into();
420
421        let starting_polygon_index = if from.polygon_index != u32::MAX {
422            from.polygon_index
423        } else {
424            self.get_closest_point_on_layers(from, blocked_layers.clone())?
425                .polygon_index
426        };
427        let ending_polygon = if to.polygon_index != u32::MAX {
428            to.polygon_index
429        } else {
430            self.get_closest_point_on_layers(to, blocked_layers.clone())?
431                .polygon_index
432        };
433        // TODO: fix islands detection with multiple layers, even if start and end are on the same layer
434        if self.layers.len() == 1 {
435            if let Some(islands) = self.layers[starting_polygon_index.layer() as usize]
436                .islands
437                .as_ref()
438            {
439                let start_island = islands.get(starting_polygon_index.polygon() as usize);
440                let end_island = islands.get(ending_polygon.polygon() as usize);
441                if start_island.is_some() && end_island.is_some() && start_island != end_island {
442                    return None;
443                }
444            }
445        }
446
447        if starting_polygon_index == ending_polygon {
448            #[cfg(feature = "stats")]
449            {
450                if self.scenarios.get() == 0 {
451                    eprintln!(
452                    "index;micros;successor_calls;generated;pushed;popped;pruned_post_pop;length",
453                );
454                }
455                eprintln!(
456                    "{};{};0;0;0;0;0;{}",
457                    self.scenarios.get(),
458                    start.elapsed().as_secs_f32() * 1_000_000.0,
459                    from.pos.distance(to.pos),
460                );
461                self.scenarios.set(self.scenarios.get() + 1);
462            }
463            return Some(Path {
464                length: from.pos.distance(to.pos),
465                path: vec![to.pos],
466                #[cfg(feature = "detailed-layers")]
467                path_with_layers: vec![(to.pos, ending_polygon.layer())],
468                path_through_polygons: vec![ending_polygon],
469            });
470        }
471
472        let mut search_instance = SearchInstance::setup(
473            self,
474            (from.pos, starting_polygon_index),
475            (to.pos, ending_polygon),
476            blocked_layers,
477            #[cfg(feature = "stats")]
478            start,
479        );
480
481        let mut paths: Vec<Path> = vec![];
482        // Limit search to avoid an infinite loop.
483        for _ in 0..self.layers.iter().map(|l| l.polygons.len()).sum::<usize>() * 10 {
484            let _potential_path = match search_instance.next() {
485                #[cfg(not(feature = "detailed-layers"))]
486                InstanceStep::Found(path) => return Some(path),
487                #[cfg(feature = "detailed-layers")]
488                InstanceStep::Found(path) => Some(path),
489                InstanceStep::NotFound => {
490                    if paths.is_empty() {
491                        None
492                    } else {
493                        Some(paths.remove(0))
494                    }
495                }
496                InstanceStep::Continue => None,
497            };
498            #[cfg(feature = "detailed-layers")]
499            if let Some(path) = _potential_path {
500                paths.push(path);
501            }
502        }
503        #[cfg(feature = "detailed-layers")]
504        paths.sort_by(|p1, p2| p1.length.partial_cmp(&p2.length).unwrap());
505        if paths.is_empty() {
506            None
507        } else {
508            Some(paths.remove(0))
509        }
510    }
511
512    /// The delta set by [`Mesh::set_delta`]
513    pub fn search_delta(&self) -> f32 {
514        self.search_delta
515    }
516
517    /// Set the delta for search with [`Mesh::path`], [`Mesh::get_path`], and [`Mesh::point_in_mesh`].
518    /// A given point P(x, y) will be searched in concentric circles around P of radius `delta` * ([`Mesh::search_steps`] - 1).
519    ///
520    /// Default is 0.1
521    pub fn set_search_delta(&mut self, delta: f32) -> &mut Self {
522        assert!(delta >= 0.0);
523        self.search_delta = delta;
524        self
525    }
526
527    /// The steps set by [`Mesh::set_steps`]
528    pub fn search_steps(&self) -> u32 {
529        self.search_steps
530    }
531
532    /// Set the steps for search with [`Mesh::path`], [`Mesh::get_path`], and [`Mesh::point_in_mesh`].
533    /// A given point P(x, y) will be searched in concentric circles around P of radius [`Mesh::search_delta`] * (`steps` - 1).
534    ///
535    /// Default is 2
536    pub fn set_search_steps(&mut self, steps: u32) -> &mut Self {
537        assert!(steps != 0);
538        self.search_steps = steps;
539        self
540    }
541
542    #[cfg_attr(feature = "tracing", instrument(skip_all))]
543    #[cfg(test)]
544    fn successors(&self, node: SearchNode, to: Vec2) -> Vec<SearchNode> {
545        use hashbrown::HashMap;
546        use std::collections::BinaryHeap;
547
548        let mut search_instance = SearchInstance {
549            #[cfg(feature = "stats")]
550            start: Instant::now(),
551            queue: BinaryHeap::new(),
552            node_buffer: Vec::new(),
553            root_history: HashMap::new(),
554            #[cfg(feature = "detailed-layers")]
555            from: (node.root, 0),
556            to,
557            polygon_to: self.get_point_location(to),
558            polygon_from: 0,
559            mesh: self,
560            blocked_layers: HashSet::default(),
561            #[cfg(feature = "stats")]
562            pushed: 0,
563            #[cfg(feature = "stats")]
564            popped: 0,
565            #[cfg(feature = "stats")]
566            successors_called: 0,
567            #[cfg(feature = "stats")]
568            nodes_generated: 0,
569            #[cfg(feature = "stats")]
570            nodes_pruned_post_pop: 0,
571            #[cfg(debug_assertions)]
572            debug: false,
573            #[cfg(debug_assertions)]
574            fail_fast: -1,
575        };
576        search_instance.successors(node);
577        search_instance.queue.drain().collect()
578    }
579
580    #[cfg_attr(feature = "tracing", instrument(skip_all))]
581    #[cfg(test)]
582    fn edges_between(&self, node: &SearchNode) -> Vec<instance::Successor> {
583        use glam::vec2;
584        use hashbrown::HashMap;
585        use std::collections::BinaryHeap;
586
587        let search_instance = SearchInstance {
588            #[cfg(feature = "stats")]
589            start: Instant::now(),
590            queue: BinaryHeap::new(),
591            node_buffer: Vec::new(),
592            root_history: HashMap::new(),
593            #[cfg(feature = "detailed-layers")]
594            from: (Vec2::ZERO, 0),
595            to: Vec2::ZERO,
596            polygon_to: self.get_point_location(vec2(0.0, 0.0)),
597            polygon_from: self.get_point_location(vec2(0.0, 0.0)),
598            mesh: self,
599            blocked_layers: HashSet::default(),
600            #[cfg(feature = "stats")]
601            pushed: 0,
602            #[cfg(feature = "stats")]
603            popped: 0,
604            #[cfg(feature = "stats")]
605            successors_called: 0,
606            #[cfg(feature = "stats")]
607            nodes_generated: 0,
608            #[cfg(feature = "stats")]
609            nodes_pruned_post_pop: 0,
610            #[cfg(debug_assertions)]
611            debug: false,
612            #[cfg(debug_assertions)]
613            fail_fast: -1,
614        };
615        search_instance.edges_between(node).to_vec()
616    }
617
618    /// Check if a given point is in a `Mesh`
619    pub fn point_in_mesh(&self, point: impl Into<Coords>) -> bool {
620        self.get_point_location(point) != u32::MAX
621    }
622
623    /// Get the positions of a point, including its layer.
624    ///
625    /// If the point can be in multiple layers, in case of overlapping layers, returns all possible layers.
626    #[cfg_attr(feature = "tracing", instrument(skip_all))]
627    pub fn get_point_layer(&self, point: impl Into<Coords>) -> Vec<Coords> {
628        let coords = point.into();
629        self.get_point_locations(coords)
630            .iter()
631            .map(|p| Coords {
632                pos: coords.pos,
633                layer: Some(p.layer()),
634                polygon_index: *p,
635            })
636            .collect()
637    }
638
639    #[cfg_attr(feature = "tracing", instrument(skip_all))]
640    fn get_point_location(&self, point: impl Into<Coords>) -> u32 {
641        let point = point.into();
642        if let Some(layer_index) = point.layer {
643            self.layers
644                .get(layer_index as usize)
645                .and_then(|layer| {
646                    Some(U32Layer::from_layer_and_polygon(
647                        layer_index,
648                        layer.get_point_location(point.pos - layer.offset, self.search_delta)?,
649                    ))
650                })
651                .unwrap_or(u32::MAX)
652        } else {
653            self.layers
654                .iter()
655                .enumerate()
656                .flat_map(|(index, layer)| {
657                    Some(U32Layer::from_layer_and_polygon(
658                        index as u8,
659                        layer.get_point_location(point.pos - layer.offset, self.search_delta)?,
660                    ))
661                })
662                .find(|poly| poly != &u32::MAX)
663                .unwrap_or(u32::MAX)
664        }
665    }
666
667    #[cfg_attr(feature = "tracing", instrument(skip_all))]
668    fn get_point_locations(&self, point: impl Into<Coords>) -> Vec<u32> {
669        let point = point.into();
670        if let Some(layer_index) = point.layer {
671            self.layers
672                .get(layer_index as usize)
673                .and_then(|layer| {
674                    Some(U32Layer::from_layer_and_polygon(
675                        layer_index,
676                        layer.get_point_location(point.pos - layer.offset, self.search_delta)?,
677                    ))
678                })
679                .into_iter()
680                .collect()
681        } else {
682            self.layers
683                .iter()
684                .enumerate()
685                .flat_map(|(index, layer)| {
686                    Some(U32Layer::from_layer_and_polygon(
687                        index as u8,
688                        layer.get_point_location(point.pos - layer.offset, self.search_delta)?,
689                    ))
690                })
691                .filter(|poly| poly != &u32::MAX)
692                .collect()
693        }
694    }
695
696    /// Find the closest point in the mesh
697    ///
698    /// This will search in circles up to `Mesh::delta` * `Mesh::steps` distance away from the point
699    pub fn get_closest_point(&self, point: impl Into<Coords>) -> Option<Coords> {
700        self.get_closest_point_on_layers(point, HashSet::default())
701    }
702
703    /// Find the closest point in the mesh
704    ///
705    /// This will search in circles up to `Mesh::delta` * `Mesh::steps` distance away from the point
706    pub fn get_closest_point_on_layers(
707        &self,
708        point: impl Into<Coords>,
709        blocked_layers: HashSet<u8>,
710    ) -> Option<Coords> {
711        let point = point.into();
712        if let Some(layer_index) = point.layer {
713            let layer = &self.layers[layer_index as usize];
714            for step in 0..self.search_steps {
715                if let Some((new_point, polygon)) =
716                    layer.get_closest_point_inner(point.pos - layer.offset, self.search_delta, step)
717                {
718                    return Some(Coords {
719                        pos: new_point + layer.offset,
720                        layer: Some(layer_index),
721                        polygon_index: U32Layer::from_layer_and_polygon(layer_index, polygon),
722                    });
723                }
724            }
725        } else {
726            for step in 0..self.search_steps {
727                for (index, layer) in self
728                    .layers
729                    .iter()
730                    .enumerate()
731                    .filter(|(index, _)| !blocked_layers.contains(&(*index as u8)))
732                {
733                    if let Some((new_point, polygon)) = layer.get_closest_point_inner(
734                        point.pos - layer.offset,
735                        self.search_delta,
736                        step,
737                    ) {
738                        return Some(Coords {
739                            pos: new_point + layer.offset,
740                            layer: Some(index as u8),
741                            polygon_index: U32Layer::from_layer_and_polygon(index as u8, polygon),
742                        });
743                    }
744                }
745            }
746        }
747        None
748    }
749
750    /// Find the closest points in the mesh
751    ///
752    /// If there are several points at the same distance, all of them will be returned.
753    /// This can happen when a layer have overlapping polygons.
754    ///
755    /// This will search in circles up to `Mesh::delta` * `Mesh::steps` distance away from the point
756    pub fn get_closest_points(&self, point: impl Into<Coords>) -> Vec<Coords> {
757        self.get_closest_points_on_layers(point, HashSet::default())
758    }
759
760    /// Find the closest point in the mesh, discriminating by height if there are several polygon overlapping.
761    ///
762    /// This will search in circles up to `Mesh::delta` * `Mesh::steps` distance away from the point
763    pub fn get_closest_point_at_height(
764        &self,
765        point: impl Into<Coords>,
766        height: f32,
767    ) -> Option<Coords> {
768        self.get_closest_points_on_layers_at_height(point, HashSet::default(), height)
769    }
770
771    /// Find the closest point in the mesh, discriminating by height if there are several polygon overlapping.
772    ///
773    /// If there are several points at the same distance, all of them will be returned.
774    /// This can happen when a layer have overlapping polygons.
775    ///
776    /// This will search in circles up to `Mesh::delta` * `Mesh::steps` distance away from the point
777    pub fn get_closest_points_on_layers_at_height(
778        &self,
779        point: impl Into<Coords>,
780        blocked_layers: HashSet<u8>,
781        height: f32,
782    ) -> Option<Coords> {
783        self.get_closest_points_on_layers(point, blocked_layers)
784            .iter()
785            .fold(None, |acc: Option<(Coords, f32)>, &coord| {
786                let coord_height = coord.height(self);
787                if acc
788                    .map(|(_, closest_height)| (closest_height - height).abs())
789                    .unwrap_or(f32::MAX)
790                    > (coord_height - height).abs()
791                {
792                    Some((coord, coord_height))
793                } else {
794                    acc
795                }
796            })
797            .map(|acc| acc.0)
798    }
799
800    /// Find the closest point in the mesh
801    ///
802    /// If there are several points at the same distance, all of them will be returned.
803    /// This can happen when a layer have overlapping polygons.
804    ///
805    /// This will search in circles up to `Mesh::delta` * `Mesh::steps` distance away from the point
806    pub fn get_closest_points_on_layers(
807        &self,
808        point: impl Into<Coords>,
809        blocked_layers: HashSet<u8>,
810    ) -> Vec<Coords> {
811        let point = point.into();
812        if let Some(layer_index) = point.layer {
813            let layer = &self.layers[layer_index as usize];
814            for step in 0..self.search_steps {
815                let coords: Vec<Coords> = layer
816                    .get_closest_points_inner(point.pos - layer.offset, self.search_delta, step)
817                    .iter()
818                    .map(|(new_point, polygon)| Coords {
819                        pos: new_point + layer.offset,
820                        layer: Some(layer_index),
821                        polygon_index: U32Layer::from_layer_and_polygon(layer_index, *polygon),
822                    })
823                    .collect();
824                if !coords.is_empty() {
825                    return coords;
826                }
827            }
828        } else {
829            for step in 0..self.search_steps {
830                for (layer_index, layer) in self
831                    .layers
832                    .iter()
833                    .enumerate()
834                    .filter(|(index, _)| !blocked_layers.contains(&(*index as u8)))
835                {
836                    let coords: Vec<Coords> = layer
837                        .get_closest_points_inner(point.pos - layer.offset, self.search_delta, step)
838                        .iter()
839                        .map(|(new_point, polygon)| Coords {
840                            pos: new_point + layer.offset,
841                            layer: Some(layer_index as u8),
842                            polygon_index: U32Layer::from_layer_and_polygon(
843                                layer_index as u8,
844                                *polygon,
845                            ),
846                        })
847                        .collect();
848                    if !coords.is_empty() {
849                        return coords;
850                    }
851                }
852            }
853        }
854        vec![]
855    }
856
857    /// Find the closest point in the mesh in the given direction
858    ///
859    /// This will search in a line up to `Mesh::delta` * `Mesh::steps` distance away from the point
860    pub fn get_closest_point_towards(
861        &self,
862        point: impl Into<Coords>,
863        towards: Vec2,
864    ) -> Option<Coords> {
865        let point = point.into();
866        let direction = -(point.pos - towards).normalize();
867        if let Some(layer_index) = point.layer {
868            let layer = &self.layers[layer_index as usize];
869            for step in 0..self.search_steps {
870                if let Some((new_point, polygon)) = layer.get_closest_point_towards_inner(
871                    point.pos - layer.offset,
872                    self.search_delta,
873                    direction,
874                    step,
875                ) {
876                    return Some(Coords {
877                        pos: new_point + layer.offset,
878                        layer: Some(layer_index),
879                        polygon_index: U32Layer::from_layer_and_polygon(layer_index, polygon),
880                    });
881                }
882            }
883        } else {
884            for step in 0..self.search_steps {
885                for (index, layer) in self.layers.iter().enumerate() {
886                    if let Some((new_point, polygon)) = layer.get_closest_point_towards_inner(
887                        point.pos - layer.offset,
888                        self.search_delta,
889                        direction,
890                        step,
891                    ) {
892                        return Some(Coords {
893                            pos: new_point + layer.offset,
894                            layer: Some(index as u8),
895                            polygon_index: U32Layer::from_layer_and_polygon(index as u8, polygon),
896                        });
897                    }
898                }
899            }
900        }
901        None
902    }
903}
904
905#[derive(PartialEq, Debug)]
906struct SearchNode {
907    path: Vec<Vec2>,
908    #[cfg(feature = "detailed-layers")]
909    path_with_layers: Vec<(Vec2, Vec2, u8)>,
910    path_through_polygons: Vec<u32>,
911    root: Vec2,
912    interval: (Vec2, Vec2),
913    edge: (u32, u32),
914    polygon_from: u32,
915    polygon_to: u32,
916    previous_polygon_layer: u8,
917    distance_start_to_root: f32,
918    heuristic: f32,
919}
920
921impl Display for SearchNode {
922    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
923        f.write_str(&format!("root=({}, {}); ", self.root.x, self.root.y))?;
924        f.write_str(&format!(
925            "left=({}, {}); ",
926            self.interval.1.x, self.interval.1.y
927        ))?;
928        f.write_str(&format!(
929            "right=({}, {}); ",
930            self.interval.0.x, self.interval.0.y
931        ))?;
932        f.write_str(&format!(
933            "f={:.2}, g={:.2} ",
934            self.distance_start_to_root + self.heuristic,
935            self.distance_start_to_root
936        ))?;
937        Ok(())
938    }
939}
940
941impl PartialOrd for SearchNode {
942    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
943        Some(self.cmp(other))
944    }
945}
946
947impl Eq for SearchNode {}
948
949impl Ord for SearchNode {
950    fn cmp(&self, other: &Self) -> Ordering {
951        match (self.distance_start_to_root + self.heuristic)
952            .total_cmp(&(other.distance_start_to_root + other.heuristic))
953        {
954            Ordering::Less => Ordering::Greater,
955            Ordering::Equal => self
956                .distance_start_to_root
957                .total_cmp(&other.distance_start_to_root),
958            Ordering::Greater => Ordering::Less,
959        }
960    }
961}
962
963#[cfg(test)]
964mod tests {
965    macro_rules! assert_delta {
966        ($x:expr, $y:expr) => {
967            let val = $x;
968            let expected = $y;
969            if !((val - expected).abs() < 0.01) {
970                assert_eq!(val, expected);
971            }
972        };
973    }
974
975    use std::vec;
976
977    use glam::{vec2, Vec2};
978
979    use crate::{helpers::*, Layer, Mesh, Path, Polygon, SearchNode, Vertex};
980
981    fn mesh_u_grid() -> Mesh {
982        let layer = Layer {
983            vertices: vec![
984                Vertex::new(vec2(0., 0.), vec![0, u32::MAX]),
985                Vertex::new(vec2(1., 0.), vec![0, 1, u32::MAX]),
986                Vertex::new(vec2(2., 0.), vec![1, 2, u32::MAX]),
987                Vertex::new(vec2(3., 0.), vec![2, u32::MAX]),
988                Vertex::new(vec2(0., 1.), vec![3, 0, u32::MAX]),
989                Vertex::new(vec2(1., 1.), vec![3, 1, 0, u32::MAX]),
990                Vertex::new(vec2(2., 1.), vec![4, 2, 1, u32::MAX]),
991                Vertex::new(vec2(3., 1.), vec![4, 2, u32::MAX]),
992                Vertex::new(vec2(0., 2.), vec![3, u32::MAX]),
993                Vertex::new(vec2(1., 2.), vec![3, u32::MAX]),
994                Vertex::new(vec2(2., 2.), vec![4, u32::MAX]),
995                Vertex::new(vec2(3., 2.), vec![4, u32::MAX]),
996            ],
997            polygons: vec![
998                Polygon::new(vec![0, 1, 5, 4], false),
999                Polygon::new(vec![1, 2, 6, 5], false),
1000                Polygon::new(vec![2, 3, 7, 6], false),
1001                Polygon::new(vec![4, 5, 9, 8], true),
1002                Polygon::new(vec![6, 7, 11, 10], true),
1003            ],
1004            ..Default::default()
1005        };
1006        Mesh {
1007            layers: vec![layer],
1008            ..Default::default()
1009        }
1010    }
1011
1012    #[test]
1013    fn point_in_polygon() {
1014        let mut mesh = mesh_u_grid();
1015        mesh.bake();
1016        assert_eq!(mesh.get_point_location(vec2(0.5, 0.5)), 0);
1017        assert_eq!(mesh.get_point_location(vec2(1.5, 0.5)), 1);
1018        assert_eq!(mesh.get_point_location(vec2(0.5, 1.5)), 3);
1019        assert_eq!(mesh.get_point_location(vec2(1.5, 1.5)), u32::MAX);
1020        assert_eq!(mesh.get_point_location(vec2(2.5, 1.5)), 4);
1021    }
1022
1023    #[test]
1024    fn successors_straight_line_ahead() {
1025        let mesh = mesh_u_grid();
1026
1027        let from = vec2(0.1, 0.1);
1028        let to = vec2(2.9, 0.9);
1029        let search_node = SearchNode {
1030            path: vec![],
1031            #[cfg(feature = "detailed-layers")]
1032            path_with_layers: vec![],
1033            path_through_polygons: vec![],
1034            root: from,
1035            interval: (vec2(1.0, 0.0), vec2(1.0, 1.0)),
1036            edge: (1, 5),
1037            polygon_from: mesh.get_point_location(from),
1038            polygon_to: 1,
1039            previous_polygon_layer: 0,
1040            distance_start_to_root: from.distance(to),
1041            heuristic: 0.0,
1042        };
1043        let successors = dbg!(mesh.successors(search_node, to));
1044        assert_eq!(successors.len(), 1);
1045        assert_eq!(successors[0].root, from);
1046        assert_eq!(successors[0].distance_start_to_root, from.distance(to));
1047        assert_eq!(successors[0].heuristic, from.distance(to));
1048        assert_eq!(successors[0].polygon_from, 1);
1049        assert_eq!(successors[0].polygon_to, 2);
1050        assert_eq!(successors[0].interval, (vec2(2.0, 0.0), vec2(2.0, 1.0)));
1051        assert_eq!(successors[0].edge, (2, 6));
1052
1053        assert_eq!(successors[0].path, Vec::<Vec2>::new());
1054
1055        assert_eq!(
1056            mesh.path(from, to).unwrap(),
1057            Path {
1058                path: vec![to],
1059                length: from.distance(to),
1060                #[cfg(feature = "detailed-layers")]
1061                path_with_layers: vec![(to, 0)],
1062                path_through_polygons: vec![0, 1, 2],
1063            }
1064        );
1065    }
1066
1067    #[test]
1068    fn successors_straight_line_reversed() {
1069        let mesh = mesh_u_grid();
1070
1071        let to = vec2(0.1, 0.1);
1072        let from = vec2(2.9, 0.9);
1073        let search_node = SearchNode {
1074            path: vec![],
1075            #[cfg(feature = "detailed-layers")]
1076            path_with_layers: vec![],
1077            path_through_polygons: vec![],
1078            root: from,
1079            interval: (vec2(2.0, 1.0), vec2(2.0, 0.0)),
1080            edge: (6, 2),
1081            polygon_from: mesh.get_point_location(from),
1082            polygon_to: 1,
1083            previous_polygon_layer: 0,
1084            distance_start_to_root: 0.0,
1085            heuristic: from.distance(to),
1086        };
1087        let successors = dbg!(mesh.successors(search_node, to));
1088        assert_eq!(successors.len(), 1);
1089        assert_eq!(successors[0].root, from);
1090        assert_eq!(successors[0].distance_start_to_root, 0.0);
1091        assert_eq!(successors[0].heuristic, to.distance(from));
1092        assert_eq!(successors[0].polygon_from, 1);
1093        assert_eq!(successors[0].polygon_to, 0);
1094        assert_eq!(successors[0].interval, (vec2(1.0, 1.0), vec2(1.0, 0.0)));
1095        assert_eq!(successors[0].edge, (5, 1));
1096        assert_eq!(successors[0].path, Vec::<Vec2>::new());
1097
1098        assert_eq!(
1099            mesh.path(from, to).unwrap(),
1100            Path {
1101                path: vec![to],
1102                length: from.distance(to),
1103                #[cfg(feature = "detailed-layers")]
1104                path_with_layers: vec![(to, 0)],
1105                path_through_polygons: vec![2, 1, 0],
1106            }
1107        );
1108    }
1109
1110    #[test]
1111    fn successors_corner_first_step() {
1112        let mesh = mesh_u_grid();
1113
1114        let from = vec2(0.1, 1.9);
1115        let to = vec2(2.1, 1.9);
1116        let search_node = SearchNode {
1117            path: vec![],
1118            #[cfg(feature = "detailed-layers")]
1119            path_with_layers: vec![],
1120            path_through_polygons: vec![],
1121            root: from,
1122            interval: (vec2(0.0, 1.0), vec2(1.0, 1.0)),
1123            edge: (4, 5),
1124            polygon_from: mesh.get_point_location(from),
1125            polygon_to: 0,
1126            previous_polygon_layer: 0,
1127            distance_start_to_root: 0.0,
1128            heuristic: from.distance(to),
1129        };
1130        let successors = dbg!(mesh.successors(search_node, to));
1131        assert_eq!(successors.len(), 1);
1132        assert_eq!(successors[0].root, vec2(2.0, 1.0));
1133        assert_eq!(
1134            successors[0].distance_start_to_root,
1135            from.distance(vec2(1.0, 1.0)) + vec2(1.0, 1.0).distance(vec2(2.0, 1.0))
1136        );
1137        assert_eq!(successors[0].heuristic, vec2(2.0, 1.0).distance(to));
1138        assert_eq!(successors[0].polygon_from, 2);
1139        assert_eq!(successors[0].polygon_to, 4);
1140        assert_eq!(successors[0].interval, (vec2(3.0, 1.0), vec2(2.0, 1.0)));
1141        assert_eq!(successors[0].edge, (7, 6));
1142        assert_eq!(successors[0].path, vec![vec2(1.0, 1.0), vec2(2.0, 1.0)]);
1143
1144        assert_eq!(
1145            mesh.path(from, to).unwrap(),
1146            Path {
1147                path: vec![vec2(1.0, 1.0), vec2(2.0, 1.0), to],
1148                length: from.distance(vec2(1.0, 1.0))
1149                    + vec2(1.0, 1.0).distance(vec2(2.0, 1.0))
1150                    + vec2(2.0, 1.0).distance(to),
1151                #[cfg(feature = "detailed-layers")]
1152                path_with_layers: vec![(vec2(1.0, 1.0), 0), (vec2(2.0, 1.0), 0), (to, 0)],
1153                path_through_polygons: vec![3, 0, 1, 2, 4],
1154            }
1155        );
1156    }
1157
1158    #[test]
1159    fn successors_corner_observable_second_step() {
1160        let mesh = mesh_u_grid();
1161
1162        let from = vec2(0.1, 1.9);
1163        let to = vec2(2.1, 1.9);
1164        let search_node = SearchNode {
1165            path: vec![],
1166            #[cfg(feature = "detailed-layers")]
1167            path_with_layers: vec![],
1168            path_through_polygons: vec![],
1169            root: from,
1170            interval: (vec2(1.0, 0.0), vec2(1.0, 1.0)),
1171            edge: (1, 5),
1172            polygon_from: 0,
1173            polygon_to: 1,
1174            previous_polygon_layer: 0,
1175            distance_start_to_root: 0.0,
1176            heuristic: from.distance(to),
1177        };
1178        let successors = dbg!(mesh.successors(search_node, to));
1179        assert_eq!(successors.len(), 1);
1180        assert_eq!(successors[0].root, vec2(2.0, 1.0));
1181        assert_eq!(
1182            successors[0].distance_start_to_root,
1183            from.distance(vec2(1.0, 1.0)) + vec2(1.0, 1.0).distance(vec2(2.0, 1.0))
1184        );
1185        assert_eq!(successors[0].heuristic, vec2(2.0, 1.0).distance(to));
1186        assert_eq!(successors[0].polygon_from, 2);
1187        assert_eq!(successors[0].polygon_to, 4);
1188        assert_eq!(successors[0].interval, (vec2(3.0, 1.0), vec2(2.0, 1.0)));
1189        assert_eq!(successors[0].edge, (7, 6));
1190        assert_eq!(successors[0].path, vec![vec2(1.0, 1.0), vec2(2.0, 1.0)]);
1191
1192        assert_eq!(
1193            mesh.path(from, to).unwrap(),
1194            Path {
1195                path: vec![vec2(1.0, 1.0), vec2(2.0, 1.0), to],
1196                length: from.distance(vec2(1.0, 1.0))
1197                    + vec2(1.0, 1.0).distance(vec2(2.0, 1.0))
1198                    + vec2(2.0, 1.0).distance(to),
1199                #[cfg(feature = "detailed-layers")]
1200                path_with_layers: vec![(vec2(1.0, 1.0), 0), (vec2(2.0, 1.0), 0), (to, 0)],
1201                path_through_polygons: vec![3, 0, 1, 2, 4],
1202            }
1203        );
1204    }
1205
1206    #[test]
1207    fn empty_mesh_fails() {
1208        let layer = Layer::new(vec![], vec![]);
1209        assert!(matches!(layer, Err(crate::MeshError::EmptyMesh)));
1210    }
1211
1212    fn mesh_from_paper() -> Mesh {
1213        let layer = Layer {
1214            vertices: vec![
1215                Vertex::new(vec2(0., 6.), vec![0, u32::MAX]),    // 0
1216                Vertex::new(vec2(2., 5.), vec![0, u32::MAX, 2]), // 1
1217                Vertex::new(vec2(5., 7.), vec![0, 2, u32::MAX]), // 2
1218                Vertex::new(vec2(5., 8.), vec![0, u32::MAX]),    // 3
1219                Vertex::new(vec2(0., 8.), vec![0, u32::MAX]),    // 4
1220                Vertex::new(vec2(1., 4.), vec![1, u32::MAX]),    // 5
1221                Vertex::new(vec2(2., 1.), vec![1, u32::MAX]),    // 6
1222                Vertex::new(vec2(4., 1.), vec![1, u32::MAX]),    // 7
1223                Vertex::new(vec2(4., 2.), vec![1, u32::MAX, 2]), // 8
1224                Vertex::new(vec2(2., 4.), vec![1, 2, u32::MAX]), // 9
1225                Vertex::new(vec2(7., 4.), vec![2, u32::MAX, 4]), // 10
1226                Vertex::new(vec2(10., 7.), vec![2, 4, 6, u32::MAX, 3]), // 11
1227                Vertex::new(vec2(7., 7.), vec![2, 3, u32::MAX]), // 12
1228                Vertex::new(vec2(11., 8.), vec![3, u32::MAX]),   // 13
1229                Vertex::new(vec2(7., 8.), vec![3, u32::MAX]),    // 14
1230                Vertex::new(vec2(7., 0.), vec![5, 4, u32::MAX]), // 15
1231                Vertex::new(vec2(11., 3.), vec![4, 5, u32::MAX]), // 16
1232                Vertex::new(vec2(11., 5.), vec![4, u32::MAX, 6]), // 17
1233                Vertex::new(vec2(12., 0.), vec![5, u32::MAX]),   // 18
1234                Vertex::new(vec2(12., 3.), vec![5, u32::MAX]),   // 19
1235                Vertex::new(vec2(13., 5.), vec![6, u32::MAX]),   // 20
1236                Vertex::new(vec2(13., 7.), vec![6, u32::MAX]),   // 21
1237                Vertex::new(vec2(1., 3.), vec![1, u32::MAX]),    // 22
1238            ],
1239            polygons: vec![
1240                Polygon::new(vec![0, 1, 2, 3, 4], true),
1241                Polygon::new(vec![5, 22, 6, 7, 8, 9], true),
1242                Polygon::new(vec![1, 9, 8, 10, 11, 12, 2], false),
1243                Polygon::new(vec![12, 11, 13, 14], true),
1244                Polygon::new(vec![10, 15, 16, 17, 11], false),
1245                Polygon::new(vec![15, 18, 19, 16], true),
1246                Polygon::new(vec![11, 17, 20, 21], true),
1247            ],
1248            ..Default::default()
1249        };
1250        Mesh {
1251            layers: vec![layer],
1252            ..Default::default()
1253        }
1254    }
1255
1256    #[test]
1257    fn paper_point_in_polygon() {
1258        let mut mesh = mesh_from_paper();
1259        mesh.bake();
1260        assert_eq!(mesh.get_point_location(vec2(0.5, 0.5)), u32::MAX);
1261        assert_eq!(mesh.get_point_location(vec2(2.0, 6.0)), 0);
1262        assert_eq!(mesh.get_point_location(vec2(2.0, 5.1)), 0);
1263        assert_eq!(mesh.get_point_location(vec2(2.0, 1.5)), 1);
1264        assert_eq!(mesh.get_point_location(vec2(4.0, 2.1)), 2);
1265    }
1266
1267    #[test]
1268    fn paper_straight() {
1269        let mesh = mesh_from_paper();
1270
1271        let from = vec2(12.0, 0.0);
1272        let to = vec2(7.0, 6.9);
1273        let search_node = SearchNode {
1274            path: vec![],
1275            #[cfg(feature = "detailed-layers")]
1276            path_with_layers: vec![],
1277            path_through_polygons: vec![],
1278            root: from,
1279            interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)),
1280            edge: (16, 15),
1281            polygon_from: mesh.get_point_location(from),
1282            polygon_to: 4,
1283            previous_polygon_layer: 0,
1284            distance_start_to_root: 0.0,
1285            heuristic: from.distance(to),
1286        };
1287        let successors = dbg!(mesh.successors(search_node, to));
1288        assert_eq!(successors.len(), 2);
1289
1290        assert_eq!(successors[1].root, vec2(11.0, 3.0));
1291        assert_eq!(
1292            successors[1].distance_start_to_root,
1293            from.distance(vec2(11.0, 3.0))
1294        );
1295        assert_eq!(
1296            successors[1].heuristic,
1297            vec2(11.0, 3.0).distance(vec2(9.75, 6.75)) + vec2(9.75, 6.75).distance(to)
1298        );
1299        assert_eq!(successors[1].polygon_from, 4);
1300        assert_eq!(successors[1].polygon_to, 2);
1301        assert_eq!(successors[1].interval, (vec2(10.0, 7.0), vec2(9.75, 6.75)));
1302        assert_eq!(successors[1].edge, (11, 10));
1303        assert_eq!(successors[1].path, vec![vec2(11.0, 3.0)]);
1304
1305        assert_eq!(successors[0].root, from);
1306        assert_eq!(successors[0].distance_start_to_root, 0.0);
1307        assert_eq!(successors[0].heuristic, from.distance(to));
1308        assert_eq!(successors[0].polygon_from, 4);
1309        assert_eq!(successors[0].polygon_to, 2);
1310        assert_eq!(successors[0].interval, (vec2(9.75, 6.75), vec2(7.0, 4.0)));
1311        assert_eq!(successors[0].edge, (11, 10));
1312        assert_eq!(successors[0].path, Vec::<Vec2>::new());
1313
1314        assert_eq!(mesh.path(from, to).unwrap().length, from.distance(to));
1315        assert_eq!(mesh.path(from, to).unwrap().path, vec![to]);
1316    }
1317
1318    #[test]
1319    fn paper_corner_right() {
1320        let mesh = mesh_from_paper();
1321
1322        let from = vec2(12.0, 0.0);
1323        let to = vec2(13.0, 6.0);
1324        let search_node = SearchNode {
1325            path: vec![],
1326            #[cfg(feature = "detailed-layers")]
1327            path_with_layers: vec![],
1328            path_through_polygons: vec![],
1329            root: from,
1330            interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)),
1331            edge: (16, 15),
1332            polygon_from: mesh.get_point_location(from),
1333            polygon_to: 4,
1334            previous_polygon_layer: 0,
1335            distance_start_to_root: 0.0,
1336            heuristic: from.distance(to),
1337        };
1338        let successors = dbg!(mesh.successors(search_node, to));
1339        assert_eq!(successors.len(), 3);
1340
1341        assert_eq!(successors[0].root, vec2(11.0, 3.0));
1342        assert_eq!(
1343            successors[0].distance_start_to_root,
1344            from.distance(vec2(11.0, 3.0))
1345        );
1346        assert_eq!(
1347            successors[0].heuristic,
1348            vec2(11.0, 3.0).distance(vec2(11.0, 5.0)) + vec2(11.0, 5.0).distance(to)
1349        );
1350        assert_eq!(successors[0].polygon_from, 4);
1351        assert_eq!(successors[0].polygon_to, 6);
1352        assert_eq!(successors[0].interval, (vec2(11.0, 5.0), vec2(10.0, 7.0)));
1353        assert_eq!(successors[0].edge, (17, 11));
1354        assert_eq!(successors[0].path, vec![vec2(11.0, 3.0)]);
1355
1356        assert_eq!(successors[1].root, vec2(11.0, 3.0));
1357        assert_eq!(
1358            successors[1].distance_start_to_root,
1359            from.distance(vec2(11.0, 3.0))
1360        );
1361        assert_eq!(
1362            successors[1].heuristic,
1363            vec2(11.0, 3.0).distance(to.mirror((vec2(10.0, 7.0), vec2(9.75, 6.75))))
1364        );
1365        assert_eq!(successors[1].polygon_from, 4);
1366        assert_eq!(successors[1].polygon_to, 2);
1367        assert_eq!(successors[1].interval, (vec2(10.0, 7.0), vec2(9.75, 6.75)));
1368        assert_eq!(successors[1].edge, (11, 10));
1369        assert_eq!(successors[1].path, vec![vec2(11.0, 3.0)]);
1370
1371        assert_eq!(successors[2].root, from);
1372        assert_eq!(successors[2].distance_start_to_root, 0.0);
1373        assert_eq!(
1374            successors[2].heuristic,
1375            from.distance(vec2(9.75, 6.75))
1376                + vec2(9.75, 6.75).distance(to.mirror((vec2(9.75, 6.75), vec2(7.0, 4.0))))
1377        );
1378        assert_eq!(successors[2].polygon_from, 4);
1379        assert_eq!(successors[2].polygon_to, 2);
1380        assert_eq!(successors[2].interval, (vec2(9.75, 6.75), vec2(7.0, 4.0)));
1381        assert_eq!(successors[2].edge, (11, 10));
1382        assert_eq!(successors[2].path, Vec::<Vec2>::new());
1383
1384        assert_delta!(
1385            mesh.path(from, to).unwrap().length,
1386            from.distance(vec2(11.0, 3.0))
1387                + vec2(11.0, 3.0).distance(vec2(11.0, 5.0))
1388                + vec2(11.0, 5.0).distance(to)
1389        );
1390        assert_eq!(
1391            mesh.path(from, to).unwrap().path,
1392            vec![vec2(11.0, 3.0), vec2(11.0, 5.0), to]
1393        );
1394    }
1395
1396    #[test]
1397    fn paper_corner_left() {
1398        let mesh = mesh_from_paper();
1399
1400        let from = vec2(12.0, 0.0);
1401        let to = vec2(5.0, 3.0);
1402        let search_node = SearchNode {
1403            path: vec![],
1404            #[cfg(feature = "detailed-layers")]
1405            path_with_layers: vec![],
1406            path_through_polygons: vec![],
1407            root: from,
1408            interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)),
1409            edge: (16, 15),
1410            polygon_from: mesh.get_point_location(from),
1411            polygon_to: 4,
1412            previous_polygon_layer: 0,
1413            distance_start_to_root: 0.0,
1414            heuristic: from.distance(to),
1415        };
1416        let successors = dbg!(mesh.successors(search_node, to));
1417        assert_eq!(successors.len(), 2);
1418
1419        assert_eq!(successors[1].root, vec2(11.0, 3.0));
1420        assert_eq!(
1421            successors[1].distance_start_to_root,
1422            from.distance(vec2(11.0, 3.0))
1423        );
1424        assert_eq!(
1425            successors[1].heuristic,
1426            vec2(11.0, 3.0).distance(vec2(9.75, 6.75)) + vec2(9.75, 6.75).distance(to)
1427        );
1428        assert_eq!(successors[1].polygon_from, 4);
1429        assert_eq!(successors[1].polygon_to, 2);
1430        assert_eq!(successors[1].interval, (vec2(10.0, 7.0), vec2(9.75, 6.75)));
1431        assert_eq!(successors[1].edge, (11, 10));
1432        assert_eq!(successors[1].path, vec![vec2(11.0, 3.0)]);
1433
1434        assert_eq!(successors[0].root, from);
1435        assert_eq!(successors[0].distance_start_to_root, 0.0);
1436        assert_eq!(
1437            successors[0].heuristic,
1438            from.distance(vec2(7.0, 4.0)) + vec2(7.0, 4.0).distance(to)
1439        );
1440        assert_eq!(successors[0].polygon_from, 4);
1441        assert_eq!(successors[0].polygon_to, 2);
1442        assert_eq!(successors[0].interval, (vec2(9.75, 6.75), vec2(7.0, 4.0)));
1443        assert_eq!(successors[0].edge, (11, 10));
1444        assert_eq!(successors[0].path, Vec::<Vec2>::new());
1445
1446        assert_delta!(
1447            mesh.path(from, to).unwrap().length,
1448            from.distance(vec2(7.0, 4.0)) + vec2(7.0, 4.0).distance(to)
1449        );
1450        assert_eq!(mesh.path(from, to).unwrap().path, vec![vec2(7.0, 4.0), to]);
1451    }
1452
1453    #[test]
1454    fn paper_going_to_one_way_polygon() {
1455        let mesh = mesh_from_paper();
1456
1457        let from = vec2(11., 0.);
1458        let to = vec2(9., 3.);
1459        let path = mesh.path(from, to);
1460
1461        assert_eq!(path.unwrap().path, vec![to]);
1462
1463        let path = mesh.path(to, from);
1464
1465        assert_eq!(path.unwrap().path, vec![from]);
1466    }
1467
1468    #[test]
1469    fn paper_corner_left_twice() {
1470        let mesh = mesh_from_paper();
1471
1472        let from = vec2(12.0, 0.0);
1473        let to = vec2(3.0, 1.0);
1474        let search_node = SearchNode {
1475            path: vec![],
1476            #[cfg(feature = "detailed-layers")]
1477            path_with_layers: vec![],
1478            path_through_polygons: vec![],
1479            root: from,
1480            interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)),
1481            edge: (16, 15),
1482            polygon_from: mesh.get_point_location(from),
1483            polygon_to: 4,
1484            previous_polygon_layer: 0,
1485            distance_start_to_root: 0.0,
1486            heuristic: from.distance(to),
1487        };
1488        let successors = dbg!(mesh.successors(search_node, to));
1489        assert_eq!(successors.len(), 2);
1490
1491        assert_eq!(successors[1].root, vec2(11.0, 3.0));
1492        assert_eq!(
1493            successors[1].distance_start_to_root,
1494            from.distance(vec2(11.0, 3.0))
1495        );
1496        assert_eq!(
1497            successors[1].heuristic,
1498            vec2(11.0, 3.0).distance(vec2(9.75, 6.75)) + vec2(9.75, 6.75).distance(to)
1499        );
1500        assert_eq!(successors[1].polygon_from, 4);
1501        assert_eq!(successors[1].polygon_to, 2);
1502        assert_eq!(successors[1].interval, (vec2(10.0, 7.0), vec2(9.75, 6.75)));
1503        assert_eq!(successors[1].edge, (11, 10));
1504        // assert_eq!(successors[1].path, vec![from]);
1505
1506        assert_eq!(successors[0].root, from);
1507        assert_eq!(successors[0].distance_start_to_root, 0.0);
1508        assert_eq!(
1509            successors[0].heuristic,
1510            from.distance(vec2(7.0, 4.0)) + vec2(7.0, 4.0).distance(to)
1511        );
1512        assert_eq!(successors[0].polygon_from, 4);
1513        assert_eq!(successors[0].polygon_to, 2);
1514        assert_eq!(successors[0].interval, (vec2(9.75, 6.75), vec2(7.0, 4.0)));
1515        assert_eq!(successors[0].edge, (11, 10));
1516        assert_eq!(successors[0].path, Vec::<Vec2>::new());
1517
1518        let successor = successors.into_iter().next().unwrap();
1519        let successors = dbg!(mesh.successors(successor, to));
1520        dbg!(&successors[0]);
1521        assert_eq!(successors.len(), 1);
1522
1523        assert_delta!(
1524            mesh.path(from, to).unwrap().length,
1525            from.distance(vec2(7.0, 4.0))
1526                + vec2(7.0, 4.0).distance(vec2(4.0, 2.0))
1527                + vec2(4.0, 2.0).distance(to)
1528        );
1529
1530        assert_eq!(
1531            mesh.path(from, to).unwrap().path,
1532            vec![vec2(7.0, 4.0), vec2(4.0, 2.0), to]
1533        );
1534        assert_eq!(
1535            mesh.path(from, to).unwrap().path_through_polygons,
1536            vec![5, 4, 2, 1]
1537        );
1538    }
1539
1540    #[test]
1541    fn edges_between_simple() {
1542        let mesh = mesh_from_paper();
1543
1544        let from = vec2(12.0, 0.0);
1545        let to = vec2(3.0, 1.0);
1546        let search_node = SearchNode {
1547            path: vec![],
1548            #[cfg(feature = "detailed-layers")]
1549            path_with_layers: vec![],
1550            path_through_polygons: vec![],
1551            root: from,
1552            interval: (vec2(11.0, 3.0), vec2(7.0, 0.0)),
1553            edge: (16, 15),
1554            polygon_from: mesh.get_point_location(from),
1555            polygon_to: 4,
1556            previous_polygon_layer: 0,
1557            distance_start_to_root: 0.0,
1558            heuristic: from.distance(to),
1559        };
1560
1561        let successors = mesh.edges_between(&search_node);
1562
1563        for successor in &successors {
1564            println!("{successor:?}");
1565        }
1566
1567        println!("=========================");
1568
1569        let search_node = SearchNode {
1570            path: vec![],
1571            #[cfg(feature = "detailed-layers")]
1572            path_with_layers: vec![],
1573            path_through_polygons: vec![],
1574            root: from,
1575            interval: (vec2(9.75, 6.75), vec2(7.0, 4.0)),
1576            edge: (11, 10),
1577            polygon_from: 4,
1578            polygon_to: 2,
1579            previous_polygon_layer: 0,
1580            distance_start_to_root: 0.0,
1581            heuristic: from.distance(to),
1582        };
1583
1584        let successors = mesh.edges_between(&search_node);
1585
1586        for successor in &successors {
1587            println!("{successor:?}");
1588        }
1589
1590        println!("=========================");
1591
1592        let search_node = SearchNode {
1593            path: vec![],
1594            #[cfg(feature = "detailed-layers")]
1595            path_with_layers: vec![],
1596            path_through_polygons: vec![],
1597            root: vec2(11.0, 3.0),
1598            interval: (vec2(10.0, 7.0), vec2(7.0, 4.0)),
1599            edge: (11, 10),
1600            polygon_from: 4,
1601            polygon_to: 2,
1602            previous_polygon_layer: 0,
1603            distance_start_to_root: 0.0,
1604            heuristic: from.distance(to),
1605        };
1606
1607        let successors = mesh.edges_between(&search_node);
1608
1609        for successor in &successors {
1610            println!("{successor:?}");
1611        }
1612    }
1613
1614    #[test]
1615    fn edges_between_simple_u() {
1616        let mesh = mesh_u_grid();
1617
1618        let search_node = SearchNode {
1619            path: vec![],
1620            #[cfg(feature = "detailed-layers")]
1621            path_with_layers: vec![],
1622            path_through_polygons: vec![],
1623            root: vec2(0.0, 0.0),
1624            interval: (vec2(1.0, 0.0), vec2(1.0, 1.0)),
1625            edge: (1, 5),
1626            polygon_from: 0,
1627            polygon_to: 1,
1628            previous_polygon_layer: 0,
1629            distance_start_to_root: 0.0,
1630            heuristic: 1.0,
1631        };
1632
1633        let successors = mesh.edges_between(&search_node);
1634
1635        for successor in &successors {
1636            println!("{successor:?}");
1637        }
1638    }
1639
1640    #[test]
1641    fn get_closest_point() {
1642        let mesh = mesh_u_grid();
1643        let point_location = mesh.get_point_location(vec2(0.5, 0.5));
1644        let closest_point = mesh.get_closest_point(vec2(0.5, 0.5)).unwrap();
1645        assert_eq!(point_location, closest_point.polygon_index);
1646    }
1647
1648    #[test]
1649    fn polygon_contains() {
1650        let mesh = mesh_u_grid();
1651        let layer = &mesh.layers[0];
1652        let polygon = &layer.polygons[0];
1653        assert!(polygon.contains(layer, vec2(0.0, 0.5)));
1654        assert!(polygon.contains(layer, vec2(0.5, 0.0)));
1655        assert!(polygon.contains(layer, vec2(0.5, 0.5)));
1656        assert!(!polygon.contains(layer, vec2(0.5, 1.5)));
1657        let polygon = &layer.polygons[3];
1658        assert!(polygon.contains(layer, vec2(0.5, 1.5)));
1659    }
1660}