1#![allow(clippy::type_complexity)]
2
3use num_traits::Num;
4use std::cmp::Ordering;
5use std::ops::{AddAssign, SubAssign};
6
7use crate::point::Point;
8use crate::vector2::Vector2;
9
10#[derive(Eq, Clone, Debug, Default)]
21pub struct Polygon<T> {
22 pub origin: Point<T, T>,
23 pub vecs: Vec<Vector2<T, T>>,
24}
25
26impl<T: Clone + Num + Ord + Copy + std::ops::AddAssign> Polygon<T> {
27 pub fn new(coords: &[Point<T, T>]) -> Self {
54 let (&origin, coords) = coords.split_first().unwrap();
55 let vecs = coords.iter().map(|pt| *pt - origin).collect();
56 Polygon { origin, vecs }
57 }
58
59 pub fn from_origin_and_vectors(origin: Point<T, T>, vecs: Vec<Vector2<T, T>>) -> Self {
66 Polygon { origin, vecs }
67 }
68
69 pub fn from_pointset(pointset: &[Point<T, T>]) -> Self {
74 Self::new(pointset)
75 }
76
77 pub fn add_assign(&mut self, rhs: Vector2<T, T>)
79 where
80 T: AddAssign,
81 {
82 self.origin += rhs;
83 }
84
85 pub fn sub_assign(&mut self, rhs: Vector2<T, T>)
87 where
88 T: SubAssign,
89 {
90 self.origin -= rhs;
91 }
92
93 pub fn signed_area_x2(&self) -> T {
119 let vecs = &self.vecs;
120 let n = vecs.len();
121 if n < 2 {
122 return T::zero();
123 }
124
125 let mut itr = vecs.iter();
126 let vec0 = itr.next().unwrap();
127 let vec1 = itr.next().unwrap();
128 let mut res = vec0.x_ * vec1.y_ - vecs[n - 1].x_ * vecs[n - 2].y_;
129
130 let mut vec0 = vec0;
131 let mut vec1 = vec1;
132
133 for vec2 in itr {
134 res += vec1.x_ * (vec2.y_ - vec0.y_);
135 vec0 = vec1;
136 vec1 = vec2;
137 }
138
139 res
140 }
141
142 pub fn vertices(&self) -> Vec<Point<T, T>> {
144 let mut result = Vec::with_capacity(self.vecs.len() + 1);
145 result.push(self.origin);
146
147 for vec in &self.vecs {
148 result.push(self.origin + *vec);
149 }
150
151 result
152 }
153
154 pub fn is_rectilinear(&self) -> bool {
182 if self.vecs.is_empty() {
183 return true;
184 }
185
186 if self.vecs[0].x_ != T::zero() && self.vecs[0].y_ != T::zero() {
188 return false;
189 }
190
191 for i in 0..self.vecs.len() - 1 {
193 let v1 = self.vecs[i];
194 let v2 = self.vecs[i + 1];
195 if v1.x_ != v2.x_ && v1.y_ != v2.y_ {
196 return false;
197 }
198 }
199
200 let last_vec = self.vecs.last().unwrap();
202 last_vec.x_ == T::zero() || last_vec.y_ == T::zero()
203 }
204
205 pub fn is_anticlockwise(&self) -> bool
207 where
208 T: PartialOrd,
209 {
210 let mut pointset = Vec::with_capacity(self.vecs.len() + 1);
211 pointset.push(Vector2::new(T::zero(), T::zero()));
212 pointset.extend(self.vecs.iter().cloned());
213
214 if pointset.len() < 3 {
215 panic!("Polygon must have at least 3 points");
216 }
217
218 let (min_index, _) = pointset
220 .iter()
221 .enumerate()
222 .min_by(|(_, a), (_, b)| {
223 a.x_.partial_cmp(&b.x_)
224 .unwrap_or(Ordering::Equal)
225 .then(a.y_.partial_cmp(&b.y_).unwrap_or(Ordering::Equal))
226 })
227 .unwrap();
228
229 let n = pointset.len();
231 let prev_point = pointset[(min_index + n - 1) % n];
232 let current_point = pointset[min_index];
233 let next_point = pointset[(min_index + 1) % n];
234
235 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
237 }
238
239 pub fn is_convex(&self) -> bool
241 where
242 T: PartialOrd,
243 {
244 let n = self.vecs.len() + 1;
245 if n < 3 {
246 return false;
247 }
248 if n == 3 {
249 return true;
250 }
251
252 let is_anticlockwise = self.is_anticlockwise();
253
254 let mut pointset = Vec::with_capacity(n + 2);
256 pointset.push(*self.vecs.last().unwrap());
257 pointset.push(Vector2::new(T::zero(), T::zero()));
258 pointset.extend(self.vecs.iter().cloned());
259 pointset.push(Vector2::new(T::zero(), T::zero()));
260
261 if is_anticlockwise {
262 for i in 1..pointset.len() - 1 {
263 let v1 = pointset[i] - pointset[i - 1];
264 let v2 = pointset[i + 1] - pointset[i];
265 if v1.cross(&v2) < T::zero() {
266 return false;
267 }
268 }
269 } else {
270 for i in 1..pointset.len() - 1 {
271 let v1 = pointset[i] - pointset[i - 1];
272 let v2 = pointset[i + 1] - pointset[i];
273 if v1.cross(&v2) > T::zero() {
274 return false;
275 }
276 }
277 }
278
279 true
280 }
281
282 pub fn bounding_box(&self) -> (Point<T, T>, Point<T, T>) {
284 let mut min_x = T::zero();
285 let mut min_y = T::zero();
286 let mut max_x = T::zero();
287 let mut max_y = T::zero();
288
289 for vec in &self.vecs {
290 if vec.x_ < min_x {
291 min_x = vec.x_;
292 }
293 if vec.y_ < min_y {
294 min_y = vec.y_;
295 }
296 if vec.x_ > max_x {
297 max_x = vec.x_;
298 }
299 if vec.y_ > max_y {
300 max_y = vec.y_;
301 }
302 }
303
304 (
305 Point::new(self.origin.xcoord + min_x, self.origin.ycoord + min_y),
306 Point::new(self.origin.xcoord + max_x, self.origin.ycoord + max_y),
307 )
308 }
309}
310
311pub fn create_mono_polygon<T, F>(pointset: &[Point<T, T>], f: F) -> Vec<Point<T, T>>
318where
319 T: Clone + Num + Ord + Copy + PartialOrd,
320 F: Fn(&Point<T, T>) -> (T, T),
321{
322 let max_pt = pointset
323 .iter()
324 .max_by(|a, b| f(a).partial_cmp(&f(b)).unwrap())
325 .unwrap();
326 let min_pt = pointset
327 .iter()
328 .min_by(|a, b| f(a).partial_cmp(&f(b)).unwrap())
329 .unwrap();
330 let d = *max_pt - *min_pt;
331
332 let (mut lst1, mut lst2): (Vec<Point<T, T>>, Vec<Point<T, T>>) = pointset
333 .iter()
334 .partition(|&a| d.cross(&(*a - *min_pt)) <= T::zero());
335
336 lst1.sort_by_key(|a| f(a));
337 lst2.sort_by_key(|a| f(a));
338 lst2.reverse();
339 lst1.append(&mut lst2);
340 lst1
341}
342
343#[inline]
347pub fn create_xmono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
348where
349 T: Clone + Num + Ord + Copy + PartialOrd,
350{
351 create_mono_polygon(pointset, |a| (a.xcoord, a.ycoord))
352}
353
354#[inline]
358pub fn create_ymono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
359where
360 T: Clone + Num + Ord + Copy + PartialOrd,
361{
362 create_mono_polygon(pointset, |a| (a.ycoord, a.xcoord))
363}
364
365pub fn polygon_is_monotone<T, F>(lst: &[Point<T, T>], dir: F) -> bool
367where
368 T: Clone + Num + Ord + Copy + PartialOrd,
369 F: Fn(&Point<T, T>) -> (T, T),
370{
371 if lst.len() <= 3 {
372 return true;
373 }
374
375 let (min_index, _) = lst
376 .iter()
377 .enumerate()
378 .min_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
379 .unwrap();
380
381 let (max_index, _) = lst
382 .iter()
383 .enumerate()
384 .max_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
385 .unwrap();
386
387 let n = lst.len();
388
389 let mut i = min_index;
391 while i != max_index {
392 let next_i = (i + 1) % n;
393 if dir(&lst[i]).0 > dir(&lst[next_i]).0 {
394 return false;
395 }
396 i = next_i;
397 }
398
399 let mut i = max_index;
401 while i != min_index {
402 let next_i = (i + 1) % n;
403 if dir(&lst[i]).0 < dir(&lst[next_i]).0 {
404 return false;
405 }
406 i = next_i;
407 }
408
409 true
410}
411
412pub fn polygon_is_xmonotone<T>(lst: &[Point<T, T>]) -> bool
414where
415 T: Clone + Num + Ord + Copy + PartialOrd,
416{
417 polygon_is_monotone(lst, |pt| (pt.xcoord, pt.ycoord))
418}
419
420pub fn polygon_is_ymonotone<T>(lst: &[Point<T, T>]) -> bool
422where
423 T: Clone + Num + Ord + Copy + PartialOrd,
424{
425 polygon_is_monotone(lst, |pt| (pt.ycoord, pt.xcoord))
426}
427
428pub fn point_in_polygon<T>(pointset: &[Point<T, T>], ptq: &Point<T, T>) -> bool
430where
431 T: Clone + Num + Ord + Copy + PartialOrd,
432{
433 let n = pointset.len();
434 if n == 0 {
435 return false;
436 }
437
438 let mut pt0 = &pointset[n - 1];
439 let mut res = false;
440
441 for pt1 in pointset.iter() {
442 if (pt1.ycoord <= ptq.ycoord && ptq.ycoord < pt0.ycoord)
443 || (pt0.ycoord <= ptq.ycoord && ptq.ycoord < pt1.ycoord)
444 {
445 let det = (*ptq - *pt0).cross(&(*pt1 - *pt0));
446 if pt1.ycoord > pt0.ycoord {
447 if det < T::zero() {
448 res = !res;
449 }
450 } else if det > T::zero() {
451 res = !res;
452 }
453 }
454 pt0 = pt1;
455 }
456
457 res
458}
459
460pub fn polygon_is_anticlockwise<T>(pointset: &[Point<T, T>]) -> bool
462where
463 T: Clone + Num + Ord + Copy + PartialOrd,
464{
465 if pointset.len() < 3 {
466 panic!("Polygon must have at least 3 points");
467 }
468
469 let (min_index, _) = pointset
471 .iter()
472 .enumerate()
473 .min_by(|(_, a), (_, b)| {
474 a.xcoord
475 .partial_cmp(&b.xcoord)
476 .unwrap_or(Ordering::Equal)
477 .then(a.ycoord.partial_cmp(&b.ycoord).unwrap_or(Ordering::Equal))
478 })
479 .unwrap();
480
481 let n = pointset.len();
483 let prev_point = pointset[(min_index + n - 1) % n];
484 let current_point = pointset[min_index];
485 let next_point = pointset[(min_index + 1) % n];
486
487 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
489}
490
491impl<T: PartialEq> PartialEq for Polygon<T> {
493 fn eq(&self, other: &Self) -> bool {
494 self.origin == other.origin && self.vecs == other.vecs
495 }
496}
497
498impl<T: AddAssign + Clone + Num> AddAssign<Vector2<T, T>> for Polygon<T> {
500 fn add_assign(&mut self, rhs: Vector2<T, T>) {
501 self.origin += rhs;
502 }
503}
504
505impl<T: SubAssign + Clone + Num> SubAssign<Vector2<T, T>> for Polygon<T> {
506 fn sub_assign(&mut self, rhs: Vector2<T, T>) {
507 self.origin -= rhs;
508 }
509}
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514 use crate::point::Point;
515 use crate::vector2::Vector2;
516
517 #[test]
518 fn test_polygon() {
519 let coords = [
520 (-2, 2),
521 (0, -1),
522 (-5, 1),
523 (-2, 4),
524 (0, -4),
525 (-4, 3),
526 (-6, -2),
527 (5, 1),
528 (2, 2),
529 (3, -3),
530 (-3, -3),
531 (3, 3),
532 (-3, -4),
533 (1, 4),
534 ];
535
536 let mut pointset = Vec::new();
537 for (x, y) in coords.iter() {
538 pointset.push(Point::new(*x, *y));
539 }
540
541 let s = create_xmono_polygon(&pointset);
542 assert!(polygon_is_anticlockwise(&s));
543
544 let p = Polygon::from_pointset(&s);
545 let mut q = Polygon::from_pointset(&s);
546 q.add_assign(Vector2::new(4, 5));
547 q.sub_assign(Vector2::new(4, 5));
548 assert_eq!(q, p);
549 }
550
551 #[test]
552 fn test_ymono_polygon() {
553 let coords = [
554 (-2, 2),
555 (0, -1),
556 (-5, 1),
557 (-2, 4),
558 (0, -4),
559 (-4, 3),
560 (-6, -2),
561 (5, 1),
562 (2, 2),
563 (3, -3),
564 (-3, -3),
565 (3, 3),
566 (-3, -4),
567 (1, 4),
568 ];
569
570 let mut pointset = Vec::new();
571 for (x, y) in coords.iter() {
572 pointset.push(Point::new(*x, *y));
573 }
574
575 let s = create_ymono_polygon(&pointset);
576 assert!(polygon_is_ymonotone(&s));
577 assert!(!polygon_is_xmonotone(&s));
578 assert!(polygon_is_anticlockwise(&s));
579
580 let p = Polygon::from_pointset(&s);
581 assert_eq!(p.signed_area_x2(), 102);
582 assert!(p.is_anticlockwise());
583 }
584
585 #[test]
586 fn test_xmono_polygon() {
587 let coords = [
588 (-2, 2),
589 (0, -1),
590 (-5, 1),
591 (-2, 4),
592 (0, -4),
593 (-4, 3),
594 (-6, -2),
595 (5, 1),
596 (2, 2),
597 (3, -3),
598 (-3, -3),
599 (3, 3),
600 (-3, -4),
601 (1, 4),
602 ];
603
604 let mut pointset = Vec::new();
605 for (x, y) in coords.iter() {
606 pointset.push(Point::new(*x, *y));
607 }
608
609 let s = create_xmono_polygon(&pointset);
610 assert!(polygon_is_xmonotone(&s));
611 assert!(!polygon_is_ymonotone(&s));
612 assert!(polygon_is_anticlockwise(&s));
613
614 let p = Polygon::from_pointset(&s);
615 assert_eq!(p.signed_area_x2(), 111);
616 assert!(p.is_anticlockwise());
617 }
618
619 #[test]
620 fn test_is_rectilinear() {
621 let rectilinear_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
623 let rectilinear_points: Vec<Point<i32, i32>> = rectilinear_coords
624 .iter()
625 .map(|(x, y)| Point::new(*x, *y))
626 .collect();
627 let rectilinear_polygon = Polygon::from_pointset(&rectilinear_points);
628 assert!(rectilinear_polygon.is_rectilinear());
629
630 let non_rectilinear_coords = [(0, 0), (1, 1), (2, 0)];
632 let non_rectilinear_points: Vec<Point<i32, i32>> = non_rectilinear_coords
633 .iter()
634 .map(|(x, y)| Point::new(*x, *y))
635 .collect();
636 let non_rectilinear_polygon = Polygon::from_pointset(&non_rectilinear_points);
637 assert!(!non_rectilinear_polygon.is_rectilinear());
638 }
639
640 #[test]
641 fn test_is_convex() {
642 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
644 let convex_points: Vec<Point<i32, i32>> = convex_coords
645 .iter()
646 .map(|(x, y)| Point::new(*x, *y))
647 .collect();
648 let convex_polygon = Polygon::from_pointset(&convex_points);
649 assert!(convex_polygon.is_convex());
650
651 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
653 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
654 .iter()
655 .map(|(x, y)| Point::new(*x, *y))
656 .collect();
657 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
658 assert!(!non_convex_polygon.is_convex());
659
660 let triangle_coords = [(0, 0), (2, 0), (1, 2)];
662 let triangle_points: Vec<Point<i32, i32>> = triangle_coords
663 .iter()
664 .map(|(x, y)| Point::new(*x, *y))
665 .collect();
666 let triangle = Polygon::from_pointset(&triangle_points);
667 assert!(triangle.is_convex());
668 }
669
670 #[test]
671 fn test_is_anticlockwise() {
672 let clockwise_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
674 let clockwise_points: Vec<Point<i32, i32>> = clockwise_coords
675 .iter()
676 .map(|(x, y)| Point::new(*x, *y))
677 .collect();
678 let clockwise_polygon = Polygon::from_pointset(&clockwise_points);
679 assert!(!clockwise_polygon.is_anticlockwise());
680
681 let counter_clockwise_coords = [(0, 0), (1, 0), (1, 1), (0, 1)];
683 let counter_clockwise_points: Vec<Point<i32, i32>> = counter_clockwise_coords
684 .iter()
685 .map(|(x, y)| Point::new(*x, *y))
686 .collect();
687 let counter_clockwise_polygon = Polygon::from_pointset(&counter_clockwise_points);
688 assert!(counter_clockwise_polygon.is_anticlockwise());
689 }
690
691 #[test]
692 fn test_is_convex_clockwise() {
693 let convex_coords = [(0, 0), (0, 2), (2, 2), (2, 0)];
695 let convex_points: Vec<Point<i32, i32>> = convex_coords
696 .iter()
697 .map(|(x, y)| Point::new(*x, *y))
698 .collect();
699 let convex_polygon = Polygon::from_pointset(&convex_points);
700 assert!(convex_polygon.is_convex());
701
702 let non_convex_coords = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0)];
704 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
705 .iter()
706 .map(|(x, y)| Point::new(*x, *y))
707 .collect();
708 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
709 assert!(!non_convex_polygon.is_convex());
710 }
711
712 #[test]
713 fn test_point_in_polygon_missed_branches() {
714 let coords = [(0, 0), (10, 0), (10, 10), (0, 10)];
715 let pointset: Vec<Point<i32, i32>> =
716 coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
717
718 assert!(!point_in_polygon(&pointset, &Point::new(5, 10)));
720
721 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
723
724 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
726 }
727
728 #[test]
729 #[should_panic(expected = "Polygon must have at least 3 points")]
730 fn test_polygon_is_anticlockwise_less_than_3_points() {
731 let coords = [(0, 0), (0, 1)];
732 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
733 polygon_is_anticlockwise(&points);
734 }
735
736 #[test]
737 #[should_panic(expected = "Polygon must have at least 3 points")]
738 fn test_is_anticlockwise_less_than_3_points() {
739 let coords = [(0, 0), (0, 1)];
740 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
741 let polygon = Polygon::from_pointset(&points);
742 polygon.is_anticlockwise();
743 }
744
745 #[test]
746 fn test_is_convex_more() {
747 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
749 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
750 .iter()
751 .map(|(x, y)| Point::new(*x, *y))
752 .collect();
753 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
754 assert!(!non_convex_polygon.is_convex());
755
756 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
758 let convex_points: Vec<Point<i32, i32>> = convex_coords
759 .iter()
760 .map(|(x, y)| Point::new(*x, *y))
761 .collect();
762 let convex_polygon = Polygon::from_pointset(&convex_points);
763 assert!(convex_polygon.is_convex());
764 }
765
766 #[test]
767 fn test_point_in_polygon_more() {
768 let coords = [(0, 0), (10, 5), (0, 10)];
770 let pointset: Vec<Point<i32, i32>> =
771 coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
772
773 assert!(point_in_polygon(&pointset, &Point::new(1, 5)));
775
776 let coords_cw = [(0, 0), (0, 10), (10, 5)];
778 let pointset_cw: Vec<Point<i32, i32>> =
779 coords_cw.iter().map(|(x, y)| Point::new(*x, *y)).collect();
780 assert!(point_in_polygon(&pointset_cw, &Point::new(1, 5)));
781 }
782}