An implementation of (randomized) incremental weighted Delaunay triangulations in safe rust.
You can create a two- or three-dimensional Delaunay triangulation, including weighted points, as follows.
let vertices = vec![
[0.0, 0.0],
[-0.5, 1.0],
[0.0, 2.5],
[2.0, 3.0],
[4.0, 2.5],
[5.0, 1.5],
[4.5, 0.5],
[2.5, -0.5],
[1.5, 1.5],
[3.0, 1.0],
];
let weights = vec![0.2, 0.3, 0.55, 0.5, 0.6, 0.4, 0.65, 0.7, 0.85, 0.35]; // or None
let mut triangulation = Triangulation::new(None); // specify epsilon here
let result = triangulation.insert_vertices(&vertices, Some(weights), true); // last parameter toggles spatial sortinglet vertices = vec![
[0.0, 0.0, 0.0],
[-0.5, 1.0, 0.5],
[0.0, 2.5, 2.5],
[2.0, 3.0, 5.0],
[4.0, 2.5, 6.5],
[5.0, 1.5, 6.5],
[4.5, 0.5, 5.0],
[2.5, -0.5, 2.0],
[1.5, 1.5, 3.0],
[3.0, 1.0, 4.0],
];
let weights = vec![0.2, 0.3, 0.55, 0.5, 0.6, 0.4, 0.65, 0.7, 0.85, 0.35]; // or None
let mut tetrahedralization = Tetrahedralization::new(None); // specify epsilon here
let result = tetrahedralization.insert_vertices(&vertices, Some(weights), true); // last parameter toggles spatial sortingThe eps parameter is used to perform an approximation technique, which leaves out certain vertices based on epsilon in the incremental insertion process.
Robustness is achieved through geogram_predicates, which itself uses cxx to make the geometric predicates from geogram available in rust.
In order to have an easy wasm compilable target it is necessary to have a rust only version of this crate. The usage of geogram_predicates makes this difficult as its an ffi to the geogram c++ library.
The workaround is to have an abstraction layer over the geometric predicates. For normal usage the geogram_predicates will be used.
When activating wasm the fallback rust-only predicates will be used. The downside of these is that they do not support lifted orientation test, i.e. we can not compute weighted Delaunay triangulations.
For the majority of the use cases however this is fine, and maybe robust can be extended in the future to support the weighted predicates as well.
The name rita is already taken on npm, so pass the scope at build time so the generated package.json gets a scoped name (e.g. @lempf/rita). If you build without --scope, the package name stays rita and publish will try to use the existing npm package.
Build with your npm scope (use -- so --no-default-features and --features go to cargo, not wasm-pack):
wasm-pack build rita --scope lempf --target web -- --no-default-features --features "std,wasm"Then publish (scoped packages require --access public):
cd rita/pkg && npm publish --access=publicInstall as npm install @lempf/rita.
To make sure both predicate libraries produce the same results tests can be run for both features.
cargo test -p rita --features logging
cargo test -p rita --no-default-features --features "std,wasm"
There is decent preliminary work done in the rust eco-system by Bastien Durix in the crate simple_delaunay_lib.
We forked this and re-fined by adding
- weighted triangulations for 2D and 3D
- adding geograms robust predicates
- adding novel method: eps-Circles
Theoretical Concepts
- extended for 2D weighted delaunay triangulations, which includes
- the flippability check (check for an edge to be flippable and only then and if it is not regular flip it)
- the 3->1 flip (with weights come possible redundant points, i.e. points not present in the final triangulation, which are achieved by 3->1 flips)
- the in_power_circler predicate via geogram_predicates (this is the "in_circle test" for weighted points)
- extend for 3D weighted Delaunay triangulations, which includes
- adding weights to the general data structure
- use regular "in-circle" predicates in the appropriate places
- do not insert redundant vertices
Code structure
- reused Node struct, for 3D (instead of duplicating)
- split each struct into own files for better readabilit and maintainability
- implement fmt::Display for structs that had print() or println()
- improved overall readabilit, e.g. by refactoring larger functions, documenting or adding comments
- ...
Conventions
- improved overall naming conventions
- applied clippy style guide, e.g. exchanging a lot of if else with match
- align naming in code with literature, i.e. flip namings, data structure namings etc.
Algorithmic Improvements
- remove unneccary push of 2 extra edges after 2->2 flip
- remove unused match case in should_flip_hedge()
- early out for match case in should_flip_hedge that always returns false i.e. Flip::None
- exchange geo::robust for geogram_predicates which has the same features plus:
- perurbation of simplicity
- arithmetic schemes
- add a naive version of last inserted triangle, which speeds up location (especially when using spatial sorting)
WIP
- add 3D Flipping Algo (there are just a few edge cases to fix. main work is done)
- extend 3D flipping algo for weighted cases
Thanks to Bastien Durix for his prior work on incremental Delaunay triangulations in rust.