use core::cmp::Ordering;
use crate::{GeometryError, Point, line::point_on_segment, orientation::orientation_sign};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Polygon<'a> {
points: &'a [Point],
}
impl<'a> Polygon<'a> {
pub fn new(points: &'a [Point]) -> Result<Self, GeometryError> {
if points.len() < 3 {
return Err(GeometryError::TooFewPoints);
}
Ok(Self { points })
}
#[must_use]
pub const fn points(self) -> &'a [Point] {
self.points
}
#[must_use]
pub fn contains(self, point: Point) -> bool {
let mut inside = false;
for index in 0..self.points.len() {
let start = self.points[index];
let end = self.points[(index + 1) % self.points.len()];
if point_on_segment(start, end, point) {
return true;
}
if (start.y() > point.y()) != (end.y() > point.y()) {
let side = orientation_sign(start, end, point);
if (end.y() > start.y() && side == Ordering::Greater)
|| (end.y() < start.y() && side == Ordering::Less)
{
inside = !inside;
}
}
}
inside
}
}