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)]
44#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
45pub struct Polygon<T> {
46 pub origin: Point<T, T>,
47 pub vecs: Vec<Vector2<T, T>>,
48}
49
50impl<T: Clone + Num + Ord + Copy + std::ops::AddAssign> Polygon<T> {
51 pub fn new(coords: &[Point<T, T>]) -> Self {
78 let (&origin, coords) = coords.split_first().unwrap();
79 let vecs = coords.iter().map(|pt| *pt - origin).collect();
80 Polygon { origin, vecs }
81 }
82
83 pub fn from_origin_and_vectors(origin: Point<T, T>, vecs: Vec<Vector2<T, T>>) -> Self {
90 Polygon { origin, vecs }
91 }
92
93 pub fn from_pointset(pointset: &[Point<T, T>]) -> Self {
98 Self::new(pointset)
99 }
100
101 pub fn area(&self) -> T
129 where
130 T: std::ops::Sub<Output = T> + std::ops::AddAssign + std::ops::Mul<Output = T> + Copy,
131 {
132 let n = self.vecs.len();
133 if n < 2 {
134 return T::zero();
135 }
136
137 let vec0 = self.vecs[0];
138 let vec1 = self.vecs[1];
139 let itr = self.vecs.iter().skip(2);
140
141 let mut res = vec0.x_ * vec1.y_ - self.vecs[n - 1].x_ * self.vecs[n - 2].y_;
142
143 let mut vec0 = vec0;
144 let mut vec1 = vec1;
145
146 for vec2 in itr {
147 res += vec1.x_ * (vec2.y_ - vec0.y_);
148 vec0 = vec1;
149 vec1 = *vec2;
150 }
151
152 res
153 }
154
155 pub fn vertices(&self) -> Vec<Point<T, T>> {
179 let mut result = Vec::with_capacity(self.vecs.len() + 1);
180 result.push(self.origin);
181
182 for vec in &self.vecs {
183 result.push(self.origin + *vec);
184 }
185
186 result
187 }
188
189 pub fn add_assign(&mut self, rhs: Vector2<T, T>)
191 where
192 T: AddAssign,
193 {
194 self.origin += rhs;
195 }
196
197 pub fn sub_assign(&mut self, rhs: Vector2<T, T>)
199 where
200 T: SubAssign,
201 {
202 self.origin -= rhs;
203 }
204
205 pub fn signed_area_x2(&self) -> T {
233 let vecs = &self.vecs;
234 let n = vecs.len();
235 if n < 2 {
236 return T::zero();
237 }
238
239 let mut itr = vecs.iter();
240 let vec0 = itr.next().unwrap();
241 let vec1 = itr.next().unwrap();
242 let mut res = vec0.x_ * vec1.y_ - vecs[n - 1].x_ * vecs[n - 2].y_;
243
244 let mut vec0 = vec0;
245 let mut vec1 = vec1;
246
247 for vec2 in itr {
248 res += vec1.x_ * (vec2.y_ - vec0.y_);
249 vec0 = vec1;
250 vec1 = vec2;
251 }
252
253 res
254 }
255
256 pub fn get_vertices(&self) -> Vec<Point<T, T>> {
258 let mut result = Vec::with_capacity(self.vecs.len() + 1);
259 result.push(self.origin);
260
261 for vec in &self.vecs {
262 result.push(self.origin + *vec);
263 }
264
265 result
266 }
267
268 pub fn bounding_box(&self) -> (Point<T, T>, Point<T, T>)
292 where
293 T: Ord + Copy,
294 {
295 let vertices = self.vertices();
296 let mut min_x = vertices[0].xcoord;
297 let mut min_y = vertices[0].ycoord;
298 let mut max_x = vertices[0].xcoord;
299 let mut max_y = vertices[0].ycoord;
300
301 for pt in &vertices {
302 if pt.xcoord < min_x {
303 min_x = pt.xcoord;
304 }
305 if pt.ycoord < min_y {
306 min_y = pt.ycoord;
307 }
308 if pt.xcoord > max_x {
309 max_x = pt.xcoord;
310 }
311 if pt.ycoord > max_y {
312 max_y = pt.ycoord;
313 }
314 }
315
316 (Point::new(min_x, min_y), Point::new(max_x, max_y))
317 }
318
319 pub fn is_rectilinear(&self) -> bool {
347 if self.vecs.is_empty() {
348 return true;
349 }
350
351 if self.vecs[0].x_ != T::zero() && self.vecs[0].y_ != T::zero() {
353 return false;
354 }
355
356 for i in 0..self.vecs.len() - 1 {
358 let v1 = self.vecs[i];
359 let v2 = self.vecs[i + 1];
360 if v1.x_ != v2.x_ && v1.y_ != v2.y_ {
361 return false;
362 }
363 }
364
365 let last_vec = self.vecs.last().unwrap();
367 last_vec.x_ == T::zero() || last_vec.y_ == T::zero()
368 }
369
370 pub fn is_anticlockwise(&self) -> bool
377 where
378 T: PartialOrd,
379 {
380 let mut pointset = Vec::with_capacity(self.vecs.len() + 1);
381 pointset.push(Vector2::new(T::zero(), T::zero()));
382 pointset.extend(self.vecs.iter().cloned());
383
384 if pointset.len() < 3 {
385 panic!("Polygon must have at least 3 points");
386 }
387
388 let (min_index, _) = pointset
390 .iter()
391 .enumerate()
392 .min_by(|(_, a), (_, b)| {
393 a.x_.partial_cmp(&b.x_)
394 .unwrap_or(Ordering::Equal)
395 .then(a.y_.partial_cmp(&b.y_).unwrap_or(Ordering::Equal))
396 })
397 .unwrap();
398
399 let n = pointset.len();
401 let prev_point = pointset[(min_index + n - 1) % n];
402 let current_point = pointset[min_index];
403 let next_point = pointset[(min_index + 1) % n];
404
405 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
407 }
408
409 pub fn is_convex(&self) -> bool
449 where
450 T: PartialOrd,
451 {
452 let n = self.vecs.len();
453 if n < 2 {
454 return false;
455 }
456 if n == 2 {
457 return true;
458 }
459
460 let cross_product_sign =
464 self.vecs[n - 2].y_ * self.vecs[0].x_ - self.vecs[n - 2].x_ * self.vecs[0].y_;
465
466 for i in 0..n - 1 {
467 let v0 = if i == 0 {
468 Vector2::new(T::zero(), T::zero())
469 } else {
470 self.vecs[i - 1]
471 };
472 let v1 = self.vecs[i];
473 let v2 = self.vecs[i + 1];
474
475 let current_cross =
476 (v1.x_ - v0.x_) * (v2.y_ - v1.y_) - (v1.y_ - v0.y_) * (v2.x_ - v1.x_);
477
478 if (cross_product_sign > T::zero()) != (current_cross > T::zero()) {
479 return false;
480 }
481 }
482
483 true
484 }
485}
486
487pub fn create_mono_polygon<T, F>(pointset: &[Point<T, T>], func: F) -> Vec<Point<T, T>>
498where
499 T: Clone + Num + Ord + Copy + PartialOrd,
500 F: Fn(&Point<T, T>) -> (T, T),
501{
502 let max_pt = pointset
503 .iter()
504 .max_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
505 .unwrap();
506 let min_pt = pointset
507 .iter()
508 .min_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
509 .unwrap();
510 let diff = *max_pt - *min_pt;
511
512 let (mut lst1, mut lst2): (Vec<Point<T, T>>, Vec<Point<T, T>>) = pointset
513 .iter()
514 .partition(|&a| diff.cross(&(*a - *min_pt)) <= T::zero());
515
516 lst1.sort_by_key(|a| func(a));
517 lst2.sort_by_key(|a| func(a));
518 lst2.reverse();
519 lst1.append(&mut lst2);
520 lst1
521}
522
523#[inline]
552pub fn create_xmono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
553where
554 T: Clone + Num + Ord + Copy + PartialOrd,
555{
556 create_mono_polygon(pointset, |a| (a.xcoord, a.ycoord))
557}
558
559#[inline]
588pub fn create_ymono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
589where
590 T: Clone + Num + Ord + Copy + PartialOrd,
591{
592 create_mono_polygon(pointset, |a| (a.ycoord, a.xcoord))
593}
594
595pub fn polygon_is_monotone<T, F>(lst: &[Point<T, T>], dir: F) -> bool
600where
601 T: Clone + Num + Ord + Copy + PartialOrd,
602 F: Fn(&Point<T, T>) -> (T, T),
603{
604 if lst.len() <= 3 {
605 return true;
606 }
607
608 let (min_index, _) = lst
609 .iter()
610 .enumerate()
611 .min_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
612 .unwrap();
613
614 let (max_index, _) = lst
615 .iter()
616 .enumerate()
617 .max_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
618 .unwrap();
619
620 let n = lst.len();
621
622 let mut i = min_index;
624 while i != max_index {
625 let next_i = (i + 1) % n;
626 if dir(&lst[i]).0 > dir(&lst[next_i]).0 {
627 return false;
628 }
629 i = next_i;
630 }
631
632 let mut i = max_index;
634 while i != min_index {
635 let next_i = (i + 1) % n;
636 if dir(&lst[i]).0 < dir(&lst[next_i]).0 {
637 return false;
638 }
639 i = next_i;
640 }
641
642 true
643}
644
645pub fn polygon_is_xmonotone<T>(lst: &[Point<T, T>]) -> bool
647where
648 T: Clone + Num + Ord + Copy + PartialOrd,
649{
650 polygon_is_monotone(lst, |pt| (pt.xcoord, pt.ycoord))
651}
652
653pub fn polygon_is_ymonotone<T>(lst: &[Point<T, T>]) -> bool
655where
656 T: Clone + Num + Ord + Copy + PartialOrd,
657{
658 polygon_is_monotone(lst, |pt| (pt.ycoord, pt.xcoord))
659}
660
661pub fn point_in_polygon<T>(pointset: &[Point<T, T>], ptq: &Point<T, T>) -> bool
667where
668 T: Clone + Num + Ord + Copy + PartialOrd,
669{
670 let n = pointset.len();
671 if n == 0 {
672 return false;
673 }
674
675 let mut pt0 = &pointset[n - 1];
676 let mut res = false;
677
678 for pt1 in pointset.iter() {
679 if (pt1.ycoord <= ptq.ycoord && ptq.ycoord < pt0.ycoord)
680 || (pt0.ycoord <= ptq.ycoord && ptq.ycoord < pt1.ycoord)
681 {
682 let det = (*ptq - *pt0).cross(&(*pt1 - *pt0));
683 if pt1.ycoord > pt0.ycoord {
684 if det < T::zero() {
685 res = !res;
686 }
687 } else if det > T::zero() {
688 res = !res;
689 }
690 }
691 pt0 = pt1;
692 }
693
694 res
695}
696
697pub fn polygon_is_anticlockwise<T>(pointset: &[Point<T, T>]) -> bool
702where
703 T: Clone + Num + Ord + Copy + PartialOrd,
704{
705 if pointset.len() < 3 {
706 panic!("Polygon must have at least 3 points");
707 }
708
709 let (min_index, _) = pointset
711 .iter()
712 .enumerate()
713 .min_by(|(_, a), (_, b)| {
714 a.xcoord
715 .partial_cmp(&b.xcoord)
716 .unwrap_or(Ordering::Equal)
717 .then(a.ycoord.partial_cmp(&b.ycoord).unwrap_or(Ordering::Equal))
718 })
719 .unwrap();
720
721 let n = pointset.len();
723 let prev_point = pointset[(min_index + n - 1) % n];
724 let current_point = pointset[min_index];
725 let next_point = pointset[(min_index + 1) % n];
726
727 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
729}
730
731impl<T: PartialEq> PartialEq for Polygon<T> {
733 fn eq(&self, other: &Self) -> bool {
735 self.origin == other.origin && self.vecs == other.vecs
736 }
737}
738
739impl<T: AddAssign + Clone + Num> AddAssign<Vector2<T, T>> for Polygon<T> {
741 fn add_assign(&mut self, rhs: Vector2<T, T>) {
743 self.origin += rhs;
744 }
745}
746
747impl<T: SubAssign + Clone + Num> SubAssign<Vector2<T, T>> for Polygon<T> {
748 fn sub_assign(&mut self, rhs: Vector2<T, T>) {
750 self.origin -= rhs;
751 }
752}
753
754#[cfg(test)]
755mod tests {
756 use super::*;
757 use crate::point::Point;
758 use crate::vector2::Vector2;
759
760 #[test]
761 fn test_polygon() {
762 let coords = [
763 (-2, 2),
764 (0, -1),
765 (-5, 1),
766 (-2, 4),
767 (0, -4),
768 (-4, 3),
769 (-6, -2),
770 (5, 1),
771 (2, 2),
772 (3, -3),
773 (-3, -3),
774 (3, 3),
775 (-3, -4),
776 (1, 4),
777 ];
778
779 let mut pointset = Vec::new();
780 for (x_coord, y_coord) in coords.iter() {
781 pointset.push(Point::new(*x_coord, *y_coord));
782 }
783
784 let poly_points = create_xmono_polygon(&pointset);
785 assert!(polygon_is_anticlockwise(&poly_points));
786
787 let poly = Polygon::from_pointset(&poly_points);
788 let mut poly2 = Polygon::from_pointset(&poly_points);
789 poly2.add_assign(Vector2::new(4, 5));
790 poly2.sub_assign(Vector2::new(4, 5));
791 assert_eq!(poly2, poly);
792 }
793
794 #[test]
795 fn test_ymono_polygon() {
796 let coords = [
797 (-2, 2),
798 (0, -1),
799 (-5, 1),
800 (-2, 4),
801 (0, -4),
802 (-4, 3),
803 (-6, -2),
804 (5, 1),
805 (2, 2),
806 (3, -3),
807 (-3, -3),
808 (3, 3),
809 (-3, -4),
810 (1, 4),
811 ];
812
813 let mut pointset = Vec::new();
814 for (x_coord, y_coord) in coords.iter() {
815 pointset.push(Point::new(*x_coord, *y_coord));
816 }
817
818 let poly_points = create_ymono_polygon(&pointset);
819 assert!(polygon_is_ymonotone(&poly_points));
820 assert!(!polygon_is_xmonotone(&poly_points));
821 assert!(polygon_is_anticlockwise(&poly_points));
822
823 let poly = Polygon::from_pointset(&poly_points);
824 assert_eq!(poly.signed_area_x2(), 102);
825 assert!(poly.is_anticlockwise());
826 }
827
828 #[test]
829 fn test_xmono_polygon() {
830 let coords = [
831 (-2, 2),
832 (0, -1),
833 (-5, 1),
834 (-2, 4),
835 (0, -4),
836 (-4, 3),
837 (-6, -2),
838 (5, 1),
839 (2, 2),
840 (3, -3),
841 (-3, -3),
842 (3, 3),
843 (-3, -4),
844 (1, 4),
845 ];
846
847 let mut pointset = Vec::new();
848 for (x_coord, y_coord) in coords.iter() {
849 pointset.push(Point::new(*x_coord, *y_coord));
850 }
851
852 let poly_points = create_xmono_polygon(&pointset);
853 assert!(polygon_is_xmonotone(&poly_points));
854 assert!(!polygon_is_ymonotone(&poly_points));
855 assert!(polygon_is_anticlockwise(&poly_points));
856
857 let poly = Polygon::from_pointset(&poly_points);
858 assert_eq!(poly.signed_area_x2(), 111);
859 assert!(poly.is_anticlockwise());
860 }
861
862 #[test]
863 fn test_is_rectilinear() {
864 let rectilinear_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
866 let rectilinear_points: Vec<Point<i32, i32>> = rectilinear_coords
867 .iter()
868 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
869 .collect();
870 let rectilinear_polygon = Polygon::from_pointset(&rectilinear_points);
871 assert!(rectilinear_polygon.is_rectilinear());
872
873 let non_rectilinear_coords = [(0, 0), (1, 1), (2, 0)];
875 let non_rectilinear_points: Vec<Point<i32, i32>> = non_rectilinear_coords
876 .iter()
877 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
878 .collect();
879 let non_rectilinear_polygon = Polygon::from_pointset(&non_rectilinear_points);
880 assert!(!non_rectilinear_polygon.is_rectilinear());
881 }
882
883 #[test]
884 fn test_is_convex() {
885 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
887 let convex_points: Vec<Point<i32, i32>> = convex_coords
888 .iter()
889 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
890 .collect();
891 let convex_polygon = Polygon::from_pointset(&convex_points);
892 assert!(convex_polygon.is_convex());
893
894 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
896 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
897 .iter()
898 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
899 .collect();
900 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
901 assert!(!non_convex_polygon.is_convex());
902
903 let triangle_coords = [(0, 0), (2, 0), (1, 2)];
905 let triangle_points: Vec<Point<i32, i32>> = triangle_coords
906 .iter()
907 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
908 .collect();
909 let triangle = Polygon::from_pointset(&triangle_points);
910 assert!(triangle.is_convex());
911 }
912
913 #[test]
914 fn test_is_anticlockwise() {
915 let clockwise_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
917 let clockwise_points: Vec<Point<i32, i32>> = clockwise_coords
918 .iter()
919 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
920 .collect();
921 let clockwise_polygon = Polygon::from_pointset(&clockwise_points);
922 assert!(!clockwise_polygon.is_anticlockwise());
923
924 let counter_clockwise_coords = [(0, 0), (1, 0), (1, 1), (0, 1)];
926 let counter_clockwise_points: Vec<Point<i32, i32>> = counter_clockwise_coords
927 .iter()
928 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
929 .collect();
930 let counter_clockwise_polygon = Polygon::from_pointset(&counter_clockwise_points);
931 assert!(counter_clockwise_polygon.is_anticlockwise());
932 }
933
934 #[test]
935 fn test_is_convex_clockwise() {
936 let convex_coords = [(0, 0), (0, 2), (2, 2), (2, 0)];
938 let convex_points: Vec<Point<i32, i32>> = convex_coords
939 .iter()
940 .map(|(x, y)| Point::new(*x, *y))
941 .collect();
942 let convex_polygon = Polygon::from_pointset(&convex_points);
943 assert!(convex_polygon.is_convex());
944
945 let non_convex_coords = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0)];
947 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
948 .iter()
949 .map(|(x, y)| Point::new(*x, *y))
950 .collect();
951 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
952 assert!(!non_convex_polygon.is_convex());
953 }
954
955 #[test]
956 fn test_point_in_polygon_missed_branches() {
957 let coords = [(0, 0), (10, 0), (10, 10), (0, 10)];
958 let pointset: Vec<Point<i32, i32>> = coords
959 .iter()
960 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
961 .collect();
962
963 assert!(!point_in_polygon(&pointset, &Point::new(5, 10)));
965
966 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
968
969 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
971 }
972
973 #[test]
974 #[should_panic(expected = "Polygon must have at least 3 points")]
975 fn test_polygon_is_anticlockwise_less_than_3_points() {
976 let coords = [(0, 0), (0, 1)];
977 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
978 polygon_is_anticlockwise(&points);
979 }
980
981 #[test]
982 #[should_panic(expected = "Polygon must have at least 3 points")]
983 fn test_is_anticlockwise_less_than_3_points() {
984 let coords = [(0, 0), (0, 1)];
985 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
986 let polygon = Polygon::from_pointset(&points);
987 polygon.is_anticlockwise();
988 }
989
990 #[test]
991 fn test_is_convex_more() {
992 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
994 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
995 .iter()
996 .map(|(x, y)| Point::new(*x, *y))
997 .collect();
998 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
999 assert!(!non_convex_polygon.is_convex());
1000
1001 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
1003 let convex_points: Vec<Point<i32, i32>> = convex_coords
1004 .iter()
1005 .map(|(x, y)| Point::new(*x, *y))
1006 .collect();
1007 let convex_polygon = Polygon::from_pointset(&convex_points);
1008 assert!(convex_polygon.is_convex());
1009 }
1010
1011 #[test]
1012 fn test_point_in_polygon_more() {
1013 let coords = [(0, 0), (10, 5), (0, 10)];
1015 let pointset: Vec<Point<i32, i32>> = coords
1016 .iter()
1017 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
1018 .collect();
1019
1020 assert!(point_in_polygon(&pointset, &Point::new(1, 5)));
1022
1023 let coords_cw = [(0, 0), (0, 10), (10, 5)];
1025 let pointset_cw: Vec<Point<i32, i32>> = coords_cw
1026 .iter()
1027 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
1028 .collect();
1029 assert!(point_in_polygon(&pointset_cw, &Point::new(1, 5)));
1030 }
1031
1032 #[test]
1033 fn test_is_rectilinear_non_rectilinear_last_edge() {
1034 let coords = [(0, 0), (4, 0), (4, 4), (1, 3)];
1036 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1037 let poly = Polygon::from_pointset(&points);
1038 assert!(!poly.is_rectilinear());
1039 }
1040
1041 #[test]
1042 fn test_is_convex_less_than_two_vecs() {
1043 let origin = Point::new(0, 0);
1045 let vecs = vec![Vector2::new(4, 0)];
1046 let poly = Polygon::from_origin_and_vectors(origin, vecs);
1047 assert!(!poly.is_convex());
1048 }
1049
1050 #[test]
1051 fn test_bounding_box_branches() {
1052 let coords = [(3, 5), (8, 2), (10, 7), (6, 9), (1, 4)];
1054 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1055 let poly = Polygon::from_pointset(&points);
1056 let (min_pt, max_pt) = poly.bounding_box();
1057 assert_eq!(min_pt, Point::new(1, 2));
1058 assert_eq!(max_pt, Point::new(10, 9));
1059 }
1060}
1061
1062#[test]
1063fn test_polygon_signed_area_x2() {
1064 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1066 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1067 let poly = Polygon::from_pointset(&pointset);
1068 assert_eq!(poly.signed_area_x2(), 24); }
1070
1071#[test]
1072fn test_polygon_vertices() {
1073 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1074 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1075 let poly = Polygon::from_pointset(&pointset);
1076 let vertices = poly.vertices();
1077 assert_eq!(vertices.len(), 4);
1078}
1079
1080#[test]
1081fn test_polygon_bounding_box() {
1082 let coords = [(1, 1), (5, 1), (5, 4), (1, 4)];
1083 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1084 let poly = Polygon::from_pointset(&pointset);
1085 let (min, max) = poly.bounding_box();
1086 assert_eq!(min, Point::new(1, 1));
1087 assert_eq!(max, Point::new(5, 4));
1088}
1089
1090#[test]
1091fn test_polygon_add_assign() {
1092 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1093 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1094 let mut poly = Polygon::from_pointset(&pointset);
1095 poly.add_assign(Vector2::new(1, 2));
1096 assert_eq!(poly.origin, Point::new(1, 2));
1097}
1098
1099#[test]
1100fn test_polygon_sub_assign() {
1101 let coords = [(1, 2), (5, 2), (5, 5), (1, 5)];
1102 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1103 let mut poly = Polygon::from_pointset(&pointset);
1104 poly.sub_assign(Vector2::new(1, 2));
1105 assert_eq!(poly.origin, Point::new(0, 0));
1106}
1107
1108#[test]
1109fn test_polygon_partial_eq() {
1110 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1111 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1112 let poly1 = Polygon::from_pointset(&pointset);
1113 let poly2 = Polygon::from_pointset(&pointset);
1114 assert_eq!(poly1, poly2);
1115
1116 let coords2 = [(0, 0), (5, 0), (5, 3), (0, 3)];
1117 let pointset2: Vec<Point<i32, i32>> = coords2.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1118 let poly3 = Polygon::from_pointset(&pointset2);
1119 assert_ne!(poly1, poly3);
1120}
1121
1122#[test]
1123fn test_polygon_from_origin_and_vectors() {
1124 let origin = Point::new(0, 0);
1125 let vecs = vec![Vector2::new(4, 0), Vector2::new(0, 3), Vector2::new(-4, 0)];
1126 let poly = Polygon::from_origin_and_vectors(origin, vecs);
1127 assert_eq!(poly.origin, Point::new(0, 0));
1128 assert_eq!(poly.vecs.len(), 3);
1129}
1130
1131#[test]
1132fn test_polygon_default() {
1133 let poly: Polygon<i32> = Polygon::default();
1134 assert_eq!(poly.origin, Point::new(0, 0));
1135}
1136
1137#[test]
1138fn test_polygon_is_monotone_custom() {
1139 let coords = [(0, 0), (1, 0), (2, 1), (1, 2), (0, 2)];
1141 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1142 assert!(polygon_is_monotone(&pointset, |pt| (pt.xcoord, pt.ycoord)));
1144}
1145
1146#[test]
1147fn test_create_mono_polygon_custom() {
1148 let coords = [(0, 0), (2, 1), (1, 2), (3, 2)];
1150 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1151 let result = create_mono_polygon(&pointset, |pt| (pt.xcoord, pt.ycoord));
1152 assert!(!result.is_empty());
1153}
1154
1155#[test]
1156fn test_polygon_empty_vecs_is_rectilinear() {
1157 let origin = Point::new(0, 0);
1159 let poly = Polygon::from_origin_and_vectors(origin, vec![]);
1160 assert!(poly.is_rectilinear());
1161}
1162
1163#[test]
1164fn test_polygon_signed_area_x2_triangle() {
1165 let coords = [(0, 0), (3, 0), (0, 4)];
1167 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1168 let poly = Polygon::from_pointset(&pointset);
1169 assert_eq!(poly.signed_area_x2(), 12);
1172}
1173
1174#[test]
1175fn test_polygon_signed_area_x2_single_vec() {
1176 let origin = Point::new(0, 0);
1178 let vecs = vec![Vector2::new(4, 0)];
1179 let poly = Polygon::from_origin_and_vectors(origin, vecs);
1180 assert_eq!(poly.signed_area_x2(), 0);
1181}
1182
1183#[test]
1184fn test_polygon_area_multi_vertex() {
1185 let coords = [(0, 0), (4, 0), (5, 3), (2, 5), (-1, 2)];
1187 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1188 let poly = Polygon::from_pointset(&points);
1189 assert_ne!(poly.area(), 0);
1191}