use crate::{line, sort_around, Polygon};
use euclid::{point2, Point2D};
use fart_aabb::{Aabb, ToAabb};
use fart_utils::NoMorePartial;
use num_traits::{Bounded, Num, NumAssign, NumCast, Signed};
use std::fmt;
use std::ops::Deref;
#[derive(Clone)]
pub struct ConvexPolygon<T, U> {
inner: Polygon<T, U>,
}
impl<T, U> fmt::Debug for ConvexPolygon<T, U>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ConvexPolygon")
.field("inner", &self.inner)
.finish()
}
}
impl<T, U> AsRef<Polygon<T, U>> for ConvexPolygon<T, U> {
fn as_ref(&self) -> &Polygon<T, U> {
&self.inner
}
}
impl<T, U> Deref for ConvexPolygon<T, U> {
type Target = Polygon<T, U>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T, U> From<ConvexPolygon<T, U>> for Polygon<T, U> {
#[inline]
fn from(c: ConvexPolygon<T, U>) -> Polygon<T, U> {
c.inner
}
}
impl<T, U> ConvexPolygon<T, U>
where
T: Copy + NumAssign + PartialOrd + Signed + Bounded + fmt::Debug,
{
pub fn hull(mut vertices: Vec<Point2D<T, U>>) -> Option<ConvexPolygon<T, U>> {
let max = vertices
.iter()
.cloned()
.fold(point2(T::min_value(), T::min_value()), |a, b| {
if NoMorePartial((a.x, a.y)) > NoMorePartial((b.x, b.y)) {
a
} else {
b
}
});
sort_around(max, &mut vertices);
vertices.dedup();
if vertices.len() < 3 {
return None;
}
debug_assert_eq!(max, vertices.last().cloned().unwrap());
let mut stack = vec![max, vertices[0]];
let mut i = 1;
while i < vertices.len() - 1 {
assert!(stack.len() >= 2);
let v = vertices[i];
let l = line(stack[stack.len() - 2], stack[stack.len() - 1]);
if l.is_left(v) {
stack.push(v);
i += 1;
} else if stack.len() == 2 {
i += 1;
} else {
stack.pop();
}
}
if stack.len() < 3 {
return None;
}
Some(ConvexPolygon {
inner: Polygon::new(stack),
})
}
pub fn contains_point(&self, point: Point2D<T, U>) -> bool {
self.edges().all(|e| e.is_left(point))
}
pub fn improperly_contains_point(&self, point: Point2D<T, U>) -> bool {
self.edges().all(|e| e.is_left_or_collinear(point))
}
}
impl<T, U> ConvexPolygon<T, U>
where
T: Copy + NumCast,
{
#[inline]
pub fn cast<V>(&self) -> ConvexPolygon<V, U>
where
V: NumCast + Copy,
{
ConvexPolygon {
inner: self.inner.cast(),
}
}
}
impl<T, U> ConvexPolygon<T, U>
where
T: Copy + Num + PartialOrd + euclid::Trig,
{
pub fn transform<V>(
&self,
transformation: &euclid::Transform2D<T, U, V>,
) -> ConvexPolygon<T, V> {
ConvexPolygon {
inner: self.inner.transform(transformation),
}
}
pub fn transform_in_place(&mut self, transformation: &euclid::Transform2D<T, U, U>) {
self.inner.transform_in_place(transformation);
}
}
impl<T, U> ToAabb<T, U> for ConvexPolygon<T, U>
where
T: Copy + Num + PartialOrd,
{
fn to_aabb(&self) -> Aabb<T, U> {
self.inner.to_aabb()
}
}
impl<T, U> From<Aabb<T, U>> for ConvexPolygon<T, U>
where
T: Copy + NumAssign + PartialOrd + Signed + fmt::Debug,
{
fn from(aabb: Aabb<T, U>) -> Self {
ConvexPolygon {
inner: Polygon::from(aabb),
}
}
}