| Crates.io | planar_convex_hull |
| lib.rs | planar_convex_hull |
| version | 0.2.1 |
| created_at | 2025-08-31 10:44:44.848112+00 |
| updated_at | 2025-10-21 08:20:17.293666+00 |
| description | A trait for implementing a planar convex hull algorithm for your own collection type |
| homepage | |
| repository | https://github.com/StefanMathis/planar_convex_hull.git |
| max_upload_size | |
| id | 1818399 |
| size | 60,591 |
A lightweight library providing a trait for implementing convex hull algorithm on your own datatype.
This library offers the ConvexHull trait which provides a divide-and-conquer convex hull algorithm in O(n log h) [1, 2]
via the convex_hull method. The trait can be implemented easily for any collection type holding point-like types
which fulfills the following conditions:
Into<[f64; 2]>, Sync and Clone,usize index,The full API documentation is available at https://docs.rs/planar_convex_hull/0.2.1/planar_convex_hull/.
Let's assume we want to implement ConvexHull for a newtype wrapper around a slice of [f64; 2]. All we need to do is to tell the trait how to randomly access the data and how to iterate over the collection:
use planar_convex_hull::{ConvexHull, Index, reinterpret, reinterpret_ref};
struct MySlice<'a>(&'a[[f64; 2]]);
impl<'a> ConvexHull for MySlice<'a> {
/// Index is a newtype of usize and is used to make sure that only indices returned
/// by convex_hull_iter can be used for random data access. It can be converted into
/// usize via the corresponding `From` implementation.
fn convex_hull_get(&self, key: Index) -> [f64; 2] {
// SAFETY: Index is only generated within the convex_hull method out of indices
// returned by convex_hull_iter (which are known to be valid)
return unsafe { self.0.get_unchecked(usize::from(key)) }
.clone()
.into();
}
fn convex_hull_iter(&self) -> impl Iterator<Item = (usize, [f64; 2])> {
return self.0.iter().cloned().map(Into::into).enumerate();
}
}
// Rhombus with two points in its middle
let my_slice = MySlice(&[
[10.0, 4.0],
[-10.0, 4.0],
[0.0, 6.0],
[0.0, 2.0],
[4.0, 4.0], // Not part of the convex hull
[-4.0, 4.0], // Not part of the convex hull
]);
// Returns a `Vec<Index>`. This vector can now be used to access the points via `convex_hull_get`:
let hull = my_slice.convex_hull();
let pts: Vec<[f64; 2]> = hull.iter().map(|i| my_slice.convex_hull_get(*i)).collect();
assert_eq!(pts, vec![[10.0, 4.0], [0.0, 6.0], [-10.0, 4.0], [0.0, 2.0]]);
// Now we want to use the raw usize indices for something else. We can either reinterpret
// a `&'a [Index]` as a `&'a [usize]` ...
let hull_usize_slice = reinterpret_ref(hull.as_slice());
assert_eq!(hull_usize_slice, &[0, 2, 1, 3]);
// ... or convert the `Vec<Index>` into a `Vec<usize>`. Both operations do simply reinterpret
// the bits, since `Index` is defined as a transparent newtype around usize.
let hull_usize_vec = reinterpret(hull);
assert_eq!(hull_usize_vec, vec![0, 2, 1, 3]);
The imp module contains implementations of ConvexHull for the following collection types with P: Into<[f64; 2]>:
Vec<P>HashMap<usize, P>[P; N] with N being the size of the array&[P]Slab<P> (only available with feature flag slab enabled)AHashMap<usize, P> (only available with feature flag ahash enabled)Please open an issue on the repository website https://github.com/StefanMathis/planar_convex_hull if you need an implementation of ConvexHull for additional collection types. You can also use
the newtype idiom as shown in the example for a reference
of a foreign collection instead (since all methods of ConvexHull operate on shared references).
All features are disabled by default.
Enabling the rayon feature parallelizes the divide-and-conquer algorithm.
The flags slab and ahash provide ConvexHull implementations for foreign data types. See Predefined implementations.