Skip to content

Commit

Permalink
support layers (#58)
Browse files Browse the repository at this point in the history
* base layer

* followup

* layers

* default derive

* intermediate type for searching with layers

* pathfinding across layers works

* typo

* more layers

* remove stray dbg

* remove extra changes

* stitching

* factor some code

* limit number of polygons in one layer

* auto stitch

* typo

* baking on layers

* typo

* change auto_stitch

* refactor

* refactor

* search for point on a given layer

* move from isize to u32

* clippy

* remove intermediate type

* merge layers

* unified api to query with/without layers

* fix doc

* stop condition support layers

* more tests (currently failing)

* oo

* fix paths on overlapping layers

* clippy

* friendlier intersection

* refactor

* can get the path with layer change details

* can block layers

* feature to limit impact

* fix no-default-baking feature

* make more things pub

* can remove_useless_vertices

* more detailed debug info

* fix ccw order after stitching, and don't trust is_corner

* can stitch layers only one way

* clippy

* set is_corner when cleaning polygons of a mesh

* put cleanup methods together

* fix tests

* get some perf back

* add tests in ci for new feature

* keep edges_index on iterator

* add traceable example of getting a path

* more iterators

* don't do island detection when there are multiple layers

* unused dependency
  • Loading branch information
mockersf authored Jul 29, 2024
1 parent 22bd7ae commit 1394d2b
Show file tree
Hide file tree
Showing 17 changed files with 2,157 additions and 676 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ jobs:
- name: Run tests
run: |
cargo test
tests-detailed-layers:
name: Tests (detailed layers)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable

- name: Run tests
run: |
cargo test --features detailed-layers
tests-aurora:
name: Tests Aurora Map
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ stats = []
verbose = []
async = []
no-default-baking = []
detailed-layers = []
serde = ["glam/serde", "bvh2d/serde", "dep:serde"]

[dependencies]
Expand Down
46 changes: 23 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,29 @@ use polyanya::*;
// Build a mesh from a list of vertices and polygons
let mesh = Mesh::new(
vec![
Vertex::new(Vec2::new(0., 6.), vec![0, -1]), // 0
Vertex::new(Vec2::new(2., 5.), vec![0, -1, 2]), // 1
Vertex::new(Vec2::new(5., 7.), vec![0, 2, -1]), // 2
Vertex::new(Vec2::new(5., 8.), vec![0, -1]), // 3
Vertex::new(Vec2::new(0., 8.), vec![0, -1]), // 4
Vertex::new(Vec2::new(1., 4.), vec![1, -1]), // 5
Vertex::new(Vec2::new(2., 1.), vec![1, -1]), // 6
Vertex::new(Vec2::new(4., 1.), vec![1, -1]), // 7
Vertex::new(Vec2::new(4., 2.), vec![1, -1, 2]), // 8
Vertex::new(Vec2::new(2., 4.), vec![1, 2, -1]), // 9
Vertex::new(Vec2::new(7., 4.), vec![2, -1, 4]), // 10
Vertex::new(Vec2::new(10., 7.), vec![2, 4, 6, -1, 3]), // 11
Vertex::new(Vec2::new(7., 7.), vec![2, 3, -1]), // 12
Vertex::new(Vec2::new(11., 8.), vec![3, -1]), // 13
Vertex::new(Vec2::new(7., 8.), vec![3, -1]), // 14
Vertex::new(Vec2::new(7., 0.), vec![5, 4, -1]), // 15
Vertex::new(Vec2::new(11., 3.), vec![4, 5, -1]), // 16
Vertex::new(Vec2::new(11., 5.), vec![4, -1, 6]), // 17
Vertex::new(Vec2::new(12., 0.), vec![5, -1]), // 18
Vertex::new(Vec2::new(12., 3.), vec![5, -1]), // 19
Vertex::new(Vec2::new(13., 5.), vec![6, -1]), // 20
Vertex::new(Vec2::new(13., 7.), vec![6, -1]), // 21
Vertex::new(Vec2::new(1., 3.), vec![1, -1]), // 22
Vertex::new(Vec2::new(0., 6.), vec![0, u32::MAX]), // 0
Vertex::new(Vec2::new(2., 5.), vec![0, u32::MAX, 2]), // 1
Vertex::new(Vec2::new(5., 7.), vec![0, 2, u32::MAX]), // 2
Vertex::new(Vec2::new(5., 8.), vec![0, u32::MAX]), // 3
Vertex::new(Vec2::new(0., 8.), vec![0, u32::MAX]), // 4
Vertex::new(Vec2::new(1., 4.), vec![1, u32::MAX]), // 5
Vertex::new(Vec2::new(2., 1.), vec![1, u32::MAX]), // 6
Vertex::new(Vec2::new(4., 1.), vec![1, u32::MAX]), // 7
Vertex::new(Vec2::new(4., 2.), vec![1, u32::MAX, 2]), // 8
Vertex::new(Vec2::new(2., 4.), vec![1, 2, u32::MAX]), // 9
Vertex::new(Vec2::new(7., 4.), vec![2, u32::MAX, 4]), // 10
Vertex::new(Vec2::new(10., 7.), vec![2, 4, 6, u32::MAX, 3]), // 11
Vertex::new(Vec2::new(7., 7.), vec![2, 3, u32::MAX]), // 12
Vertex::new(Vec2::new(11., 8.), vec![3, u32::MAX]), // 13
Vertex::new(Vec2::new(7., 8.), vec![3, u32::MAX]), // 14
Vertex::new(Vec2::new(7., 0.), vec![5, 4, u32::MAX]), // 15
Vertex::new(Vec2::new(11., 3.), vec![4, 5, u32::MAX]), // 16
Vertex::new(Vec2::new(11., 5.), vec![4, u32::MAX, 6]), // 17
Vertex::new(Vec2::new(12., 0.), vec![5, u32::MAX]), // 18
Vertex::new(Vec2::new(12., 3.), vec![5, u32::MAX]), // 19
Vertex::new(Vec2::new(13., 5.), vec![6, u32::MAX]), // 20
Vertex::new(Vec2::new(13., 7.), vec![6, u32::MAX]), // 21
Vertex::new(Vec2::new(1., 3.), vec![1, u32::MAX]), // 22
],
vec![
Polygon::new(vec![0, 1, 2, 3, 4], true), // 0
Expand Down
25 changes: 25 additions & 0 deletions examples/traced/src/bin/paths.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use glam::Vec2;
use polyanya::{Mesh, PolyanyaFile};
use tracing_subscriber::layer::SubscriberExt;

fn main() {
tracing::subscriber::set_global_default(
tracing_subscriber::registry().with(tracing_tracy::TracyLayer::default()),
)
.expect("set up the subscriber");
let mesh: Mesh = {
let _execution_span: tracing::span::EnteredSpan =
tracing::info_span!("loading mesh").entered();
PolyanyaFile::from_file("meshes/aurora-merged.mesh")
.try_into()
.unwrap()
};
println!("loaded mesh");

for _i in 0..1000 {
let _execution_span: tracing::span::EnteredSpan =
tracing::info_span!("getting path").entered();
mesh.path(Vec2::new(233.0, 323.0), Vec2::new(422.0, 650.0))
.unwrap();
}
}
27 changes: 18 additions & 9 deletions src/async_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#[cfg(feature = "stats")]
use std::time::Instant;
use std::{fmt, future::Future, task::Poll};
use std::{collections::HashSet, fmt, future::Future, task::Poll};

use glam::Vec2;

use crate::{
instance::{InstanceStep, SearchInstance},
instance::{InstanceStep, SearchInstance, U32Layer},
Mesh, Path,
};

Expand All @@ -17,7 +17,7 @@ pub struct FuturePath<'m> {
pub(crate) to: Vec2,
pub(crate) mesh: &'m Mesh,
pub(crate) instance: Option<SearchInstance<'m>>,
pub(crate) ending_polygon: isize,
pub(crate) ending_polygon: u32,
}

impl<'m> fmt::Debug for FuturePath<'m> {
Expand Down Expand Up @@ -58,11 +58,17 @@ impl<'m> Future for FuturePath<'m> {
if ending_polygon == u32::MAX {
return Poll::Ready(None);
}
if let Some(islands) = self.mesh.islands.as_ref() {
let start_island = islands.get(starting_polygon_index as usize);
let end_island = islands.get(ending_polygon as usize);
if start_island.is_some() && end_island.is_some() && start_island != end_island {
return Poll::Ready(None);
if starting_polygon_index.layer() == ending_polygon.layer() {
if let Some(islands) = self.mesh.layers[starting_polygon_index.layer() as usize]
.islands
.as_ref()
{
let start_island = islands.get(starting_polygon_index as usize);
let end_island = islands.get(ending_polygon as usize);
if start_island.is_some() && end_island.is_some() && start_island != end_island
{
return Poll::Ready(None);
}
}
}

Expand All @@ -85,17 +91,20 @@ impl<'m> Future for FuturePath<'m> {
return Poll::Ready(Some(Path {
length: self.from.distance(self.to),
path: vec![self.to],
#[cfg(feature = "detailed-layers")]
path_with_layers: vec![(self.to, ending_polygon.layer())],
}));
}

self.instance = Some(SearchInstance::setup(
self.mesh,
(self.from, starting_polygon_index),
(self.to, ending_polygon),
HashSet::default(),
#[cfg(feature = "stats")]
start,
));
self.ending_polygon = ending_polygon as isize;
self.ending_polygon = ending_polygon;
cx.waker().wake_by_ref();
Poll::Pending
}
Expand Down
4 changes: 2 additions & 2 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tracing::instrument;

use crate::instance::EdgeSide;

const EPSILON: f32 = 1e-4;
pub(crate) const EPSILON: f32 = 1e-4;

pub(crate) trait Vec2Helper {
fn side(self, edge: (Vec2, Vec2)) -> EdgeSide;
Expand Down Expand Up @@ -172,7 +172,7 @@ pub(crate) fn intersection_time(line: (Vec2, Vec2), segment: (Vec2, Vec2)) -> f3
pub(crate) fn line_intersect_segment(line: (Vec2, Vec2), segment: (Vec2, Vec2)) -> Option<Vec2> {
let intersection_time = intersection_time(line, segment);

if !(0.0..=1.0).contains(&intersection_time) || intersection_time.is_nan() {
if !(-EPSILON..=(1.0 + EPSILON)).contains(&intersection_time) || intersection_time.is_nan() {
None
} else {
Some(segment.0 + intersection_time * (segment.1 - segment.0))
Expand Down
9 changes: 5 additions & 4 deletions src/input/polyanya_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl PolyanyaFile {
let _ = values.next();
let vertex = Vertex::new(
Vec2::new(x, y),
values.map(|v| v.parse().unwrap()).collect(),
values.map(|v| v.parse().unwrap_or(u32::MAX)).collect(),
);
mesh.vertices.push(vertex);
} else {
Expand Down Expand Up @@ -147,10 +147,11 @@ impl TryFrom<PolyanyaFile> for Mesh {
}

impl From<Mesh> for PolyanyaFile {
fn from(mesh: Mesh) -> Self {
fn from(mut mesh: Mesh) -> Self {
let last_layer = mesh.layers.pop().unwrap();
PolyanyaFile {
vertices: mesh.vertices,
polygons: mesh.polygons,
vertices: last_layer.vertices,
polygons: last_layer.polygons,
}
}
}
32 changes: 18 additions & 14 deletions src/input/triangulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use geo::{Contains, Coord, Polygon as GeoPolygon, SimplifyVwPreserve};
use glam::{vec2, Vec2};
use spade::{ConstrainedDelaunayTriangulation, Point2, Triangulation as SpadeTriangulation};

use crate::{Mesh, Polygon, Vertex};
use crate::{Layer, Mesh, Polygon, Vertex};

/// An helper to create a [`Mesh`] from a list of edges and obstacle, using a constrained Delaunay triangulation.
#[derive(Clone)]
Expand Down Expand Up @@ -174,7 +174,7 @@ impl Triangulation {
#[cfg(feature = "tracing")]
let polygon_span = tracing::info_span!("listing polygons").entered();

let mut face_to_polygon: Vec<isize> = vec![-1; cdt.all_faces().len()];
let mut face_to_polygon: Vec<u32> = vec![u32::MAX; cdt.all_faces().len()];
let mut i = 0;
let polygons = cdt
.inner_faces()
Expand Down Expand Up @@ -220,16 +220,17 @@ impl Triangulation {
.out_edges()
.map(|out_edge| face_to_polygon[out_edge.face().index()])
.collect::<VecDeque<_>>();
let neighbour_polygons: Vec<_> = if neighbour_polygons.iter().all(|i| *i == -1) {
vec![-1]
} else {
while neighbour_polygons[0] == -1 {
neighbour_polygons.rotate_left(1);
}
let mut neighbour_polygons: Vec<_> = neighbour_polygons.into();
neighbour_polygons.dedup();
neighbour_polygons
};
let neighbour_polygons: Vec<_> =
if neighbour_polygons.iter().all(|i| *i == u32::MAX) {
vec![u32::MAX]
} else {
while neighbour_polygons[0] == u32::MAX {
neighbour_polygons.rotate_left(1);
}
let mut neighbour_polygons: Vec<_> = neighbour_polygons.into();
neighbour_polygons.dedup();
neighbour_polygons
};
let point = point.position();
Vertex::new(vec2(point.x, point.y), neighbour_polygons)
})
Expand All @@ -239,8 +240,11 @@ impl Triangulation {
drop(vertex_span);

Mesh {
vertices,
polygons,
layers: vec![Layer {
vertices,
polygons,
..Default::default()
}],
..Default::default()
}
}
Expand Down
Loading

0 comments on commit 1394d2b

Please sign in to comment.