Polyanya - Compromise-free Pathfinding on a Navigation Mesh
Implementation of Polyanya in Rust! Polyanya is a any-angle path planning algorithm.
WASM demos made with Bevy are available here.
Features
- Pathfinding using Polyanya: Efficient any-angle path planning algorithm for navigation meshes.
- Multi-layer Navigation Mesh Support:
- Overlapping navmeshes for 3D navigation (floors, bridges, ...).
- One-way layers for directional movement.
- Conditional layer traversal with the ability to enable or disable layers.
- Layers with different traversal costs for more realistic pathfinding.
Usage
Navigation meshes can be built by specifying their outer edges and inner obstacles:
use vec2;
use *;
// Build a mesh from its outer edge
let triangulation = from_outer_edges;
let mesh = triangulation.as_navmesh;
// Get the path between two points
let from = vec2;
let to = vec2;
let path = mesh.path;
assert_eq!;
They can also be built by manually specifying vertices and polygons for complete control. The following produces the same mesh
use vec2;
use *;
// Build a mesh from a list of vertices and polygons
let mesh = new.unwrap;
The code above will build the following mesh, with polygons marked in green, and vertices in red:

Original Work
Check the cpp implementation.
index;micro;successor_calls;generated;pushed;popped;pruned_post_pop;length;gridcost
0;4960.92;6974;4368;4313;3823;21;1123.222637572437;1199.73
This crate seems to generate a few more nodes, but tends to be faster than the cpp implementation. There are a few known cases to still improve it:
- collinear optimisation, when a search node root and interval are all on a same line
- triangle optimisation, when searching in a triangle polygon
- when an intersection is very close to a vertex, it sometimes generates an extra slim search node
- searching start and end nodes is costlier
Compiling this crate with feature stats will output almost the same level of information as the default cpp implementation output.
index;micros;successor_calls;generated;pushed;popped;pruned_post_pop;length
0;2990.083;6983;7748;4314;3828;21;1123.2228
The verbose feature will give the same output as setting verbose to 1.
pushing: root=(993, 290); left=(989, 303); right=(1001, 288); f=1020.21, g=0.00
pushing: root=(993, 290); left=(984, 301); right=(988, 303); f=1016.98, g=0.00
pushing: root=(993, 290); left=(982, 300); right=(984, 301); f=1016.06, g=0.00
pushing: root=(993, 290); left=(994, 285); right=(981, 299); f=1014.84, g=0.00
popped off: root=(993, 290); left=(994, 285); right=(981, 299); f=1014.84, g=0.00
intermediate: root=(993, 290); left=(988, 282); right=(981, 299); f=1014.84, g=0.00
pushing: root=(993, 290); left=(977, 299); right=(980, 299); f=1015.14, g=0.00
pushing: root=(993, 290); left=(984, 280); right=(976, 297); f=1014.84, g=0.00
popped off: root=(993, 290); left=(984, 280); right=(976, 297); f=1014.84, g=0.00
pushing: root=(993, 290); left=(973, 296); right=(976, 297); f=1014.84, g=0.00
pushing: root=(993, 290); left=(970, 295); right=(973, 296); f=1014.86, g=0.00
pushing: root=(993, 290); left=(967, 294); right=(970, 295); f=1015.01, g=0.00
pushing: root=(993, 290); left=(965, 293); right=(967, 294); f=1015.28, g=0.00
pushing: root=(993, 290); left=(977, 276); right=(965, 293); f=1015.58, g=0.00
pushing: root=(993, 290); left=(983, 279); right=(979, 277); f=1023.95, g=0.00
popped off: root=(993, 290); left=(973, 296); right=(976, 297); f=1014.84, g=0.00
popped off: root=(993, 290); left=(970, 295); right=(973, 296); f=1014.86, g=0.00
popped off: root=(993, 290); left=(967, 294); right=(970, 295); f=1015.01, g=0.00
popped off: root=(993, 290); left=(977, 299); right=(980, 299); f=1015.14, g=0.00
popped off: root=(993, 290); left=(965, 293); right=(967, 294); f=1015.28, g=0.00
popped off: root=(993, 290); left=(977, 276); right=(965, 293); f=1015.58, g=0.00
pushing: root=(993, 290); left=(963, 292); right=(965, 293); f=1015.58, g=0.00
pushing: root=(993, 290); left=(961, 291); right=(963, 292); f=1015.94, g=0.00
pushing: root=(993, 290); left=(971, 273); right=(959, 289); f=1017.13, g=0.00
...
The mesh files used in tests are coming from the cpp implementation and are available under MIT license.