Skip to content

Commit

Permalink
Use Polyanya for path finding
Browse files Browse the repository at this point in the history
  • Loading branch information
Indy2222 committed Oct 9, 2023
1 parent 7f12f79 commit 65199e3
Show file tree
Hide file tree
Showing 13 changed files with 1,235 additions and 776 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/pathing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ spade.workspace = true
futures-lite.workspace = true

[dev-dependencies]
# DE
de_test_utils.workspace = true

# Other
ntest.workspace = true
criterion.workspace = true

Expand Down
57 changes: 22 additions & 35 deletions crates/pathing/benches/pathing.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
use std::{
fs::File,
io::{BufRead, BufReader},
path::PathBuf,
};

use bevy::prelude::Transform;
use criterion::{
criterion_group, criterion_main, AxisScale, BenchmarkId, Criterion, PlotConfiguration,
Expand All @@ -12,29 +6,13 @@ use criterion::{
use de_map::size::MapBounds;
use de_objects::Ichnography;
use de_pathing::{create_finder, ExclusionArea, PathQueryProps, PathTarget};
use de_test_utils::{load_points, NumPoints};
use glam::Vec2;
use parry2d::{math::Point, shape::ConvexPolygon};

const MAP_SIZE: f32 = 8000.;
const MAP_HALF_SIZE: f32 = 4000.;

fn load_points(number: u32) -> Vec<Vec2> {
let mut points_path: PathBuf = env!("CARGO_MANIFEST_DIR").into();
points_path.push("test_data");
points_path.push(format!("{number}-points.txt"));
let reader = BufReader::new(File::open(points_path).unwrap());

let mut points = Vec::with_capacity(number as usize);
for line in reader.lines() {
let line = line.unwrap();
let mut numbers = line.split_whitespace();
let x: f32 = numbers.next().unwrap().parse().unwrap();
let y: f32 = numbers.next().unwrap().parse().unwrap();
points.push(MAP_SIZE * Vec2::new(x, y));
}
points
}

fn load_exclusions(number: u32) -> Vec<ExclusionArea> {
fn load_exclusions(number: &NumPoints) -> Vec<ExclusionArea> {
let ichnography = Ichnography::from(
ConvexPolygon::from_convex_hull(&[
Point::new(-8., 8.),
Expand All @@ -44,7 +22,8 @@ fn load_exclusions(number: u32) -> Vec<ExclusionArea> {
])
.unwrap(),
);
load_points(number)

load_points(number, MAP_HALF_SIZE - 20.)
.iter()
.map(|p| ExclusionArea::from_ichnography(&Transform::from_xyz(p.x, 0., -p.y), &ichnography))
.collect()
Expand All @@ -55,13 +34,17 @@ fn create_finder_benchmark(c: &mut Criterion) {
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);
group.plot_config(plot_config);

for num_entities in [100, 1000, 10_000, 100_000] {
let exclusions = load_exclusions(num_entities);
for number in [
NumPoints::OneHundred,
NumPoints::OneThousand,
NumPoints::TenThousand,
] {
let exclusions = load_exclusions(&number);

let bounds = MapBounds::new(Vec2::splat(MAP_SIZE));
let bounds = MapBounds::new(Vec2::splat(2. * MAP_HALF_SIZE));

group.throughput(Throughput::Elements(1));
group.bench_function(BenchmarkId::from_parameter(num_entities), |b| {
group.bench_function(BenchmarkId::from_parameter(usize::from(number)), |b| {
b.iter(|| {
create_finder(bounds, exclusions.clone());
});
Expand All @@ -74,15 +57,19 @@ fn find_path_benchmark(c: &mut Criterion) {
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);
group.plot_config(plot_config);

let points = load_points(100_000);
let points = load_points(&NumPoints::OneHundredThousand, MAP_HALF_SIZE);
let mut index = 0;

for num_entities in [100, 1000, 10_000, 100_000] {
let bounds = MapBounds::new(Vec2::splat(MAP_SIZE));
let finder = create_finder(bounds, load_exclusions(num_entities));
for number in [
NumPoints::OneHundred,
NumPoints::OneThousand,
NumPoints::TenThousand,
] {
let bounds = MapBounds::new(Vec2::splat(2. * MAP_HALF_SIZE));
let finder = create_finder(bounds, load_exclusions(&number));

group.throughput(Throughput::Elements(1));
group.bench_function(BenchmarkId::from_parameter(num_entities), |b| {
group.bench_function(BenchmarkId::from_parameter(usize::from(number)), |b| {
b.iter(|| {
let start = points[index];
index = (index + 1) % points.len();
Expand Down
35 changes: 1 addition & 34 deletions crates/pathing/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ use std::rc::Rc;
use de_types::path::Path;
use parry2d::math::Point;

use crate::geometry::{which_side, Side};

/// A linked list of points which keeps track of its length in meters.
#[derive(Clone)]
pub(crate) struct PointChain {
prev: Option<Rc<Self>>,
point: Point<f32>,
Expand Down Expand Up @@ -58,26 +57,6 @@ impl PointChain {
self.length
}

/// Returns true if the point has no predecessor.
pub(crate) fn is_first(&self) -> bool {
self.prev.is_none()
}

/// Returns relative side of a point to `self` from the perspective of the
/// parent point. Returns `None` if `self` has no parent.
///
/// See [`crate::geometry::which_side`].
///
/// # Panics
///
/// May panic if self is a degenerate point chain or of `point` coincides
/// with last but one point in self.
pub(crate) fn which_side(&self, point: Point<f32>) -> Option<Side> {
self.prev
.as_ref()
.map(|p| which_side(p.point(), self.point, point))
}

/// Returns an iterator over points in this linked list. The iterator
/// starts at `self` and traverses all predecessors.
pub(crate) fn iter(&self) -> Predecessors {
Expand Down Expand Up @@ -123,31 +102,19 @@ mod tests {
fn test_chain() {
let chain = PointChain::first(Point::new(1., 2.));
assert!(chain.prev().is_none());
assert!(chain.is_first());
assert_eq!(chain.point(), Point::new(1., 2.));
assert_eq!(chain.length(), 0.);
let collected: Vec<Point<f32>> = chain.iter().map(|p| p.point()).collect();
assert_eq!(collected, vec![Point::new(1., 2.)]);

let chain = PointChain::extended(&Rc::new(chain), Point::new(3., 2.));
assert!(chain.prev().is_some());
assert!(!chain.is_first());
assert_eq!(chain.point(), Point::new(3., 2.));
assert_eq!(chain.length(), 2.);
let collected: Vec<Point<f32>> = chain.iter().map(|p| p.point()).collect();
assert_eq!(collected, vec![Point::new(3., 2.), Point::new(1., 2.)]);
}

#[test]
fn test_which_side() {
let chain = PointChain::first(Point::new(1., 2.));
assert!(chain.which_side(Point::new(2., 1.)).is_none());

let chain = PointChain::extended(&Rc::new(chain), Point::new(3., 2.));
assert_eq!(chain.which_side(Point::new(2., 1.)).unwrap(), Side::Left);
assert_eq!(chain.which_side(Point::new(2., 3.)).unwrap(), Side::Right);
}

#[test]
fn test_to_path() {
let chain = PointChain::extended(
Expand Down
Loading

0 comments on commit 65199e3

Please sign in to comment.