1use crate::Polygon;
6
7pub fn point_in_polygon<T>(point: &crate::Point<T, T>, polygon: &Polygon<T>) -> bool
40where
41 T: Clone
42 + Copy
43 + PartialOrd
44 + std::ops::Sub<Output = T>
45 + std::ops::Mul<Output = T>
46 + std::ops::Div<Output = T>
47 + std::ops::Add<Output = T>
48 + num_traits::Zero
49 + num_traits::Num
50 + std::ops::AddAssign
51 + Ord,
52{
53 let vertices = polygon.get_vertices();
54 let n = vertices.len();
55
56 if n < 3 {
57 return false;
58 }
59
60 let mut inside = false;
61 let mut j = n - 1;
62
63 for i in 0..n {
64 let xi = vertices[i].xcoord;
65 let yi = vertices[i].ycoord;
66 let xj = vertices[j].xcoord;
67 let yj = vertices[j].ycoord;
68
69 let intersect = ((yi > point.ycoord) != (yj > point.ycoord))
70 && (point.xcoord < (xj - xi) * (point.ycoord - yi) / (yj - yi) + xi);
71
72 if intersect {
73 inside = !inside;
74 }
75
76 j = i;
77 }
78
79 inside
80}
81
82pub fn polygon_centroid<T>(polygon: &Polygon<T>) -> crate::Point<T, T>
113where
114 T: Clone
115 + Copy
116 + std::ops::Add<Output = T>
117 + std::ops::Div<Output = T>
118 + From<i32>
119 + num_traits::Zero
120 + num_traits::Num
121 + std::ops::AddAssign
122 + Ord,
123{
124 let vertices = polygon.get_vertices();
125 let n = vertices.len();
126
127 if n == 0 {
128 return crate::Point::new(T::from(0), T::from(0));
129 }
130
131 let mut sum_x = T::from(0);
132 let mut sum_y = T::from(0);
133
134 for vertex in &vertices {
135 sum_x += vertex.xcoord;
136 sum_y += vertex.ycoord;
137 }
138
139 let n_t = T::from(n as i32);
140 crate::Point::new(sum_x / n_t, sum_y / n_t)
141}
142
143pub fn polygon_perimeter<T>(polygon: &Polygon<T>) -> T
177where
178 T: Clone
179 + Copy
180 + std::ops::Add<Output = T>
181 + std::ops::Sub<Output = T>
182 + std::ops::Mul<Output = T>
183 + num_traits::Zero
184 + num_traits::Num
185 + std::ops::AddAssign
186 + Ord,
187{
188 let vertices = polygon.get_vertices();
189 let n = vertices.len();
190
191 if n < 2 {
192 return T::zero();
193 }
194
195 let mut perimeter = T::zero();
196
197 for i in 0..n {
198 let current = vertices[i];
199 let next = vertices[(i + 1) % n];
200
201 let dx = if current.xcoord > next.xcoord {
202 current.xcoord - next.xcoord
203 } else {
204 next.xcoord - current.xcoord
205 };
206
207 let dy = if current.ycoord > next.ycoord {
208 current.ycoord - next.ycoord
209 } else {
210 next.ycoord - current.ycoord
211 };
212
213 perimeter = perimeter + dx + dy;
214 }
215
216 perimeter
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn test_point_in_polygon() {
225 let points = vec![
226 crate::Point::new(0, 0),
227 crate::Point::new(10, 0),
228 crate::Point::new(10, 10),
229 crate::Point::new(0, 10),
230 ];
231 let polygon = Polygon::new(&points);
232
233 assert!(point_in_polygon(&crate::Point::new(5, 5), &polygon));
234 assert!(!point_in_polygon(&crate::Point::new(15, 15), &polygon));
235 assert!(!point_in_polygon(&crate::Point::new(-5, 5), &polygon));
236 }
237
238 #[test]
239 fn test_polygon_centroid() {
240 let points = vec![
241 crate::Point::new(0, 0),
242 crate::Point::new(3, 0),
243 crate::Point::new(3, 3),
244 ];
245 let polygon = Polygon::new(&points);
246
247 let centroid = polygon_centroid(&polygon);
248 assert_eq!(centroid.xcoord, 2);
249 assert_eq!(centroid.ycoord, 1);
250 }
251
252 #[test]
253 fn test_polygon_perimeter() {
254 let points = vec![
255 crate::Point::new(0, 0),
256 crate::Point::new(3, 0),
257 crate::Point::new(3, 4),
258 crate::Point::new(0, 4),
259 ];
260 let polygon = Polygon::new(&points);
261
262 let perimeter = polygon_perimeter(&polygon);
263 assert_eq!(perimeter, 14);
264 }
265
266 #[test]
267 fn test_point_in_polygon_less_than_3_points() {
268 let pts = vec![crate::Point::new(0, 0), crate::Point::new(1, 0)];
269 let polygon = Polygon::new(&pts);
270 assert!(!point_in_polygon(&crate::Point::new(0, 0), &polygon));
271 }
272
273 #[test]
274 fn test_polygon_centroid_empty() {
275 let polygon = Polygon::from_origin_and_vectors(crate::Point::new(0, 0), vec![]);
276 let result = polygon_centroid(&polygon);
277 assert_eq!(result, crate::Point::new(0, 0));
278 }
279
280 #[test]
281 fn test_polygon_perimeter_less_than_2_points() {
282 let polygon = Polygon::from_origin_and_vectors(crate::Point::new(0, 0), vec![]);
283 assert_eq!(polygon_perimeter(&polygon), 0);
284
285 let polygon2 = Polygon::new(&[crate::Point::new(0, 0)]);
286 assert_eq!(polygon_perimeter(&polygon2), 0);
287 }
288}