1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use use_point::Point2;
5
6#[derive(Debug, Clone, PartialEq)]
8pub struct Polygon {
9 vertices: Vec<Point2>,
10}
11
12impl Polygon {
13 #[must_use]
15 pub const fn new(vertices: Vec<Point2>) -> Self {
16 Self { vertices }
17 }
18
19 #[must_use]
21 pub fn vertices(&self) -> &[Point2] {
22 &self.vertices
23 }
24
25 #[must_use]
27 pub fn vertex_count(&self) -> usize {
28 self.vertices.len()
29 }
30
31 #[must_use]
33 pub fn is_empty(&self) -> bool {
34 self.vertices.is_empty()
35 }
36
37 #[must_use]
39 pub fn twice_signed_area(&self) -> f64 {
40 if self.vertices.len() < 3 {
41 return 0.0;
42 }
43
44 self.vertices
45 .iter()
46 .zip(self.vertices.iter().cycle().skip(1))
47 .take(self.vertices.len())
48 .map(|(a, b)| a.x() * b.y() - a.y() * b.x())
49 .sum()
50 }
51
52 #[must_use]
54 pub fn area(&self) -> f64 {
55 self.twice_signed_area().abs() * 0.5
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::Polygon;
62 use use_point::Point2;
63
64 #[test]
65 fn computes_polygon_area() {
66 let polygon = Polygon::new(vec![
67 Point2::new(0.0, 0.0),
68 Point2::new(4.0, 0.0),
69 Point2::new(0.0, 3.0),
70 ]);
71
72 assert_eq!(polygon.vertex_count(), 3);
73 assert_eq!(polygon.area(), 6.0);
74 assert!(!polygon.is_empty());
75 }
76}