use crate::GeoNum;
use crate::geometry::{Coord, LineString, Polygon};
use crate::kernels::*;
pub trait ConvexHull<'a, T> {
type Scalar: GeoNum;
fn convex_hull(&'a self) -> Polygon<Self::Scalar>;
}
use crate::algorithm::CoordsIter;
use crate::utils::lex_cmp;
impl<'a, T, G> ConvexHull<'a, T> for G
where
T: GeoNum,
G: CoordsIter<Scalar = T>,
{
type Scalar = T;
fn convex_hull(&'a self) -> Polygon<T> {
let mut exterior: Vec<_> = self.exterior_coords_iter().collect();
Polygon::new(quick_hull(&mut exterior), vec![])
}
}
pub mod qhull;
pub use qhull::quick_hull;
pub mod graham;
pub use graham::graham_hull;
fn trivial_hull<T>(points: &mut [Coord<T>], include_on_hull: bool) -> LineString<T>
where
T: GeoNum,
{
assert!(points.len() < 4);
let mut ls: Vec<Coord<T>> = points.to_vec();
if !include_on_hull {
ls.sort_unstable_by(lex_cmp);
if ls.len() == 3 && T::Ker::orient2d(ls[0], ls[1], ls[2]) == Orientation::Collinear {
ls.remove(1);
}
}
if ls.len() == 1 {
ls.push(ls[0]);
}
let mut ls = LineString::new(ls);
ls.close();
use super::winding_order::Winding;
ls.make_ccw_winding();
ls
}
fn swap_with_first_and_remove<'a, T>(slice: &mut &'a mut [T], idx: usize) -> &'a mut T {
let tmp = std::mem::take(slice);
tmp.swap(0, idx);
let (h, t) = tmp.split_first_mut().unwrap();
*slice = t;
h
}
#[cfg(test)]
mod test;