sightloom_core/
polygon.rs1use core::cmp::Ordering;
4
5use crate::{GeometryError, Point, line::point_on_segment, orientation::orientation_sign};
6
7#[derive(Clone, Copy, Debug, PartialEq)]
9pub struct Polygon<'a> {
10 points: &'a [Point],
11}
12
13impl<'a> Polygon<'a> {
14 pub fn new(points: &'a [Point]) -> Result<Self, GeometryError> {
21 if points.len() < 3 {
22 return Err(GeometryError::TooFewPoints);
23 }
24
25 Ok(Self { points })
26 }
27
28 #[must_use]
30 pub const fn points(self) -> &'a [Point] {
31 self.points
32 }
33
34 #[must_use]
36 pub fn contains(self, point: Point) -> bool {
37 let mut inside = false;
38
39 for index in 0..self.points.len() {
40 let start = self.points[index];
41 let end = self.points[(index + 1) % self.points.len()];
42 if point_on_segment(start, end, point) {
43 return true;
44 }
45
46 if (start.y() > point.y()) != (end.y() > point.y()) {
47 let side = orientation_sign(start, end, point);
48 if (end.y() > start.y() && side == Ordering::Greater)
49 || (end.y() < start.y() && side == Ordering::Less)
50 {
51 inside = !inside;
52 }
53 }
54 }
55
56 inside
57 }
58}