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#[derive(Debug, PartialEq)]
64pub struct Path {
65 pub length: f32,
67 pub path: Vec<Vec2>,
69 #[cfg(feature = "detailed-layers")]
71 #[cfg_attr(docsrs, doc(cfg(feature = "detailed-layers")))]
72 pub path_with_layers: Vec<(Vec2, u8)>,
73 path_through_polygons: Vec<u32>,
75}
76
77impl Path {
78 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 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 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#[derive(Debug, Clone)]
185#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
186pub struct Mesh {
187 pub layers: Vec<Layer>,
189 pub search_delta: f32,
191 pub search_steps: u32,
193 #[cfg(feature = "stats")]
194 pub(crate) scenarios: Cell<u32>,
195}
196
197#[derive(Debug, PartialEq, Clone, Copy)]
199pub struct Coords {
200 pos: Vec2,
202 layer: Option<u8>,
206 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 pub fn on_mesh(pos: Vec2) -> Self {
225 pos.into()
226 }
227
228 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 #[inline]
239 pub fn position(&self) -> Vec2 {
240 self.pos
241 }
242
243 #[inline]
245 pub fn layer(&self) -> Option<u8> {
246 self.layer
247 }
248
249 #[inline]
251 pub fn polygon(&self) -> u32 {
252 self.polygon_index
253 }
254
255 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 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 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 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#[derive(Error, Debug, Copy, Clone, PartialEq)]
346pub enum MeshError {
347 #[error("The mesh is empty")]
349 EmptyMesh,
350 #[error("The mesh is invalid")]
352 InvalidMesh,
353 #[error("One layer has too many polygons")]
355 TooManyPolygons,
356}
357
358impl Mesh {
359 pub fn bake(&mut self) {
363 for layer in self.layers.iter_mut() {
364 layer.bake();
365 }
366 }
367
368 #[inline]
370 pub fn unbake(&mut self) {
371 for layer in self.layers.iter_mut() {
372 layer.unbake();
373 }
374 }
375
376 #[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 #[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 #[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 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 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 pub fn search_delta(&self) -> f32 {
514 self.search_delta
515 }
516
517 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 pub fn search_steps(&self) -> u32 {
529 self.search_steps
530 }
531
532 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 pub fn point_in_mesh(&self, point: impl Into<Coords>) -> bool {
620 self.get_point_location(point) != u32::MAX
621 }
622
623 #[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 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 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 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 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 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 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 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]), Vertex::new(vec2(2., 5.), vec![0, u32::MAX, 2]), Vertex::new(vec2(5., 7.), vec![0, 2, u32::MAX]), Vertex::new(vec2(5., 8.), vec![0, u32::MAX]), Vertex::new(vec2(0., 8.), vec![0, u32::MAX]), Vertex::new(vec2(1., 4.), vec![1, u32::MAX]), Vertex::new(vec2(2., 1.), vec![1, u32::MAX]), Vertex::new(vec2(4., 1.), vec![1, u32::MAX]), Vertex::new(vec2(4., 2.), vec![1, u32::MAX, 2]), Vertex::new(vec2(2., 4.), vec![1, 2, u32::MAX]), Vertex::new(vec2(7., 4.), vec![2, u32::MAX, 4]), Vertex::new(vec2(10., 7.), vec![2, 4, 6, u32::MAX, 3]), Vertex::new(vec2(7., 7.), vec![2, 3, u32::MAX]), Vertex::new(vec2(11., 8.), vec![3, u32::MAX]), Vertex::new(vec2(7., 8.), vec![3, u32::MAX]), Vertex::new(vec2(7., 0.), vec![5, 4, u32::MAX]), Vertex::new(vec2(11., 3.), vec![4, 5, u32::MAX]), Vertex::new(vec2(11., 5.), vec![4, u32::MAX, 6]), Vertex::new(vec2(12., 0.), vec![5, u32::MAX]), Vertex::new(vec2(12., 3.), vec![5, u32::MAX]), Vertex::new(vec2(13., 5.), vec![6, u32::MAX]), Vertex::new(vec2(13., 7.), vec![6, u32::MAX]), Vertex::new(vec2(1., 3.), vec![1, u32::MAX]), ],
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[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}