use crate::geometry::primitives::Point;
use crate::geometry::primitives::SPolygon;
use ordered_float::OrderedFloat;
use anyhow::{Result, bail};
pub fn convex_hull_indices(shape: &SPolygon) -> Vec<usize> {
let c_hull = convex_hull_from_points(shape.vertices.clone());
let mut indices = vec![];
for p in c_hull.iter() {
indices.push(shape.vertices.iter().position(|x| x == p).unwrap());
}
indices
}
pub fn convex_hull_from_surrogate(s: &SPolygon) -> Result<Vec<Point>> {
if let Some(surr) = s.surrogate.as_ref() {
Ok(surr
.convex_hull_indices
.iter()
.map(|&i| s.vertices[i])
.collect())
} else {
bail!("no surrogate present")
}
}
pub fn convex_hull_from_points(mut points: Vec<Point>) -> Vec<Point> {
points.sort_by_key(|p| OrderedFloat(p.0));
let mut lower_hull = points
.iter()
.fold(vec![], |hull, p| grow_convex_hull(hull, *p));
let mut upper_hull = points
.iter()
.rev()
.fold(vec![], |hull, p| grow_convex_hull(hull, *p));
upper_hull.pop();
lower_hull.pop();
lower_hull.append(&mut upper_hull);
lower_hull
}
fn grow_convex_hull(mut h: Vec<Point>, next: Point) -> Vec<Point> {
while h.len() >= 2 && cross(h[h.len() - 2], h[h.len() - 1], next) <= 0.0 {
h.pop();
}
h.push(next);
h
}
fn cross(a: Point, b: Point, c: Point) -> f32 {
(b.0 - a.0) * (c.1 - a.1) - (b.1 - a.1) * (c.0 - a.0)
}