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
125 where
126 T: std::ops::Sub<Output = T> + std::ops::AddAssign + std::ops::Mul<Output = T> + Copy,
127 {
128 let n = self.vecs.len();
129 if n < 2 {
130 return T::zero();
131 }
132
133 let vec0 = self.vecs[0];
134 let vec1 = self.vecs[1];
135 let itr = self.vecs.iter().skip(2);
136
137 let mut res = vec0.x_ * vec1.y_ - self.vecs[n - 1].x_ * self.vecs[n - 2].y_;
138
139 let mut vec0 = vec0;
140 let mut vec1 = vec1;
141
142 for vec2 in itr {
143 res += vec1.x_ * (vec2.y_ - vec0.y_);
144 vec0 = vec1;
145 vec1 = *vec2;
146 }
147
148 res
149 }
150
151 pub fn vertices(&self) -> Vec<Point<T, T>> {
175 let mut result = Vec::with_capacity(self.vecs.len() + 1);
176 result.push(self.origin);
177
178 for vec in &self.vecs {
179 result.push(self.origin + *vec);
180 }
181
182 result
183 }
184
185 pub fn add_assign(&mut self, rhs: Vector2<T, T>)
187 where
188 T: AddAssign,
189 {
190 self.origin += rhs;
191 }
192
193 pub fn sub_assign(&mut self, rhs: Vector2<T, T>)
195 where
196 T: SubAssign,
197 {
198 self.origin -= rhs;
199 }
200
201 pub fn signed_area_x2(&self) -> T {
227 let vecs = &self.vecs;
228 let n = vecs.len();
229 if n < 2 {
230 return T::zero();
231 }
232
233 let mut itr = vecs.iter();
234 let vec0 = itr.next().unwrap();
235 let vec1 = itr.next().unwrap();
236 let mut res = vec0.x_ * vec1.y_ - vecs[n - 1].x_ * vecs[n - 2].y_;
237
238 let mut vec0 = vec0;
239 let mut vec1 = vec1;
240
241 for vec2 in itr {
242 res += vec1.x_ * (vec2.y_ - vec0.y_);
243 vec0 = vec1;
244 vec1 = vec2;
245 }
246
247 res
248 }
249
250 pub fn get_vertices(&self) -> Vec<Point<T, T>> {
252 let mut result = Vec::with_capacity(self.vecs.len() + 1);
253 result.push(self.origin);
254
255 for vec in &self.vecs {
256 result.push(self.origin + *vec);
257 }
258
259 result
260 }
261
262 pub fn bounding_box(&self) -> (Point<T, T>, Point<T, T>)
286 where
287 T: Ord + Copy,
288 {
289 let vertices = self.vertices();
290 let mut min_x = vertices[0].xcoord;
291 let mut min_y = vertices[0].ycoord;
292 let mut max_x = vertices[0].xcoord;
293 let mut max_y = vertices[0].ycoord;
294
295 for pt in &vertices {
296 if pt.xcoord < min_x {
297 min_x = pt.xcoord;
298 }
299 if pt.ycoord < min_y {
300 min_y = pt.ycoord;
301 }
302 if pt.xcoord > max_x {
303 max_x = pt.xcoord;
304 }
305 if pt.ycoord > max_y {
306 max_y = pt.ycoord;
307 }
308 }
309
310 (Point::new(min_x, min_y), Point::new(max_x, max_y))
311 }
312
313 pub fn is_rectilinear(&self) -> bool {
341 if self.vecs.is_empty() {
342 return true;
343 }
344
345 if self.vecs[0].x_ != T::zero() && self.vecs[0].y_ != T::zero() {
347 return false;
348 }
349
350 for i in 0..self.vecs.len() - 1 {
352 let v1 = self.vecs[i];
353 let v2 = self.vecs[i + 1];
354 if v1.x_ != v2.x_ && v1.y_ != v2.y_ {
355 return false;
356 }
357 }
358
359 let last_vec = self.vecs.last().unwrap();
361 last_vec.x_ == T::zero() || last_vec.y_ == T::zero()
362 }
363
364 pub fn is_anticlockwise(&self) -> bool
366 where
367 T: PartialOrd,
368 {
369 let mut pointset = Vec::with_capacity(self.vecs.len() + 1);
370 pointset.push(Vector2::new(T::zero(), T::zero()));
371 pointset.extend(self.vecs.iter().cloned());
372
373 if pointset.len() < 3 {
374 panic!("Polygon must have at least 3 points");
375 }
376
377 let (min_index, _) = pointset
379 .iter()
380 .enumerate()
381 .min_by(|(_, a), (_, b)| {
382 a.x_.partial_cmp(&b.x_)
383 .unwrap_or(Ordering::Equal)
384 .then(a.y_.partial_cmp(&b.y_).unwrap_or(Ordering::Equal))
385 })
386 .unwrap();
387
388 let n = pointset.len();
390 let prev_point = pointset[(min_index + n - 1) % n];
391 let current_point = pointset[min_index];
392 let next_point = pointset[(min_index + 1) % n];
393
394 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
396 }
397
398 pub fn is_convex(&self) -> bool
436 where
437 T: PartialOrd,
438 {
439 let n = self.vecs.len();
440 if n < 2 {
441 return false;
442 }
443 if n == 2 {
444 return true;
445 }
446
447 let cross_product_sign =
451 self.vecs[n - 2].y_ * self.vecs[0].x_ - self.vecs[n - 2].x_ * self.vecs[0].y_;
452
453 for i in 0..n - 1 {
454 let v0 = if i == 0 {
455 Vector2::new(T::zero(), T::zero())
456 } else {
457 self.vecs[i - 1]
458 };
459 let v1 = self.vecs[i];
460 let v2 = self.vecs[i + 1];
461
462 let current_cross =
463 (v1.x_ - v0.x_) * (v2.y_ - v1.y_) - (v1.y_ - v0.y_) * (v2.x_ - v1.x_);
464
465 if (cross_product_sign > T::zero()) != (current_cross > T::zero()) {
466 return false;
467 }
468 }
469
470 true
471 }
472}
473
474pub fn create_mono_polygon<T, F>(pointset: &[Point<T, T>], func: F) -> Vec<Point<T, T>>
481where
482 T: Clone + Num + Ord + Copy + PartialOrd,
483 F: Fn(&Point<T, T>) -> (T, T),
484{
485 let max_pt = pointset
486 .iter()
487 .max_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
488 .unwrap();
489 let min_pt = pointset
490 .iter()
491 .min_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
492 .unwrap();
493 let diff = *max_pt - *min_pt;
494
495 let (mut lst1, mut lst2): (Vec<Point<T, T>>, Vec<Point<T, T>>) = pointset
496 .iter()
497 .partition(|&a| diff.cross(&(*a - *min_pt)) <= T::zero());
498
499 lst1.sort_by_key(|a| func(a));
500 lst2.sort_by_key(|a| func(a));
501 lst2.reverse();
502 lst1.append(&mut lst2);
503 lst1
504}
505
506#[inline]
535pub fn create_xmono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
536where
537 T: Clone + Num + Ord + Copy + PartialOrd,
538{
539 create_mono_polygon(pointset, |a| (a.xcoord, a.ycoord))
540}
541
542#[inline]
571pub fn create_ymono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
572where
573 T: Clone + Num + Ord + Copy + PartialOrd,
574{
575 create_mono_polygon(pointset, |a| (a.ycoord, a.xcoord))
576}
577
578pub fn polygon_is_monotone<T, F>(lst: &[Point<T, T>], dir: F) -> bool
580where
581 T: Clone + Num + Ord + Copy + PartialOrd,
582 F: Fn(&Point<T, T>) -> (T, T),
583{
584 if lst.len() <= 3 {
585 return true;
586 }
587
588 let (min_index, _) = lst
589 .iter()
590 .enumerate()
591 .min_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
592 .unwrap();
593
594 let (max_index, _) = lst
595 .iter()
596 .enumerate()
597 .max_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
598 .unwrap();
599
600 let n = lst.len();
601
602 let mut i = min_index;
604 while i != max_index {
605 let next_i = (i + 1) % n;
606 if dir(&lst[i]).0 > dir(&lst[next_i]).0 {
607 return false;
608 }
609 i = next_i;
610 }
611
612 let mut i = max_index;
614 while i != min_index {
615 let next_i = (i + 1) % n;
616 if dir(&lst[i]).0 < dir(&lst[next_i]).0 {
617 return false;
618 }
619 i = next_i;
620 }
621
622 true
623}
624
625pub fn polygon_is_xmonotone<T>(lst: &[Point<T, T>]) -> bool
627where
628 T: Clone + Num + Ord + Copy + PartialOrd,
629{
630 polygon_is_monotone(lst, |pt| (pt.xcoord, pt.ycoord))
631}
632
633pub fn polygon_is_ymonotone<T>(lst: &[Point<T, T>]) -> bool
635where
636 T: Clone + Num + Ord + Copy + PartialOrd,
637{
638 polygon_is_monotone(lst, |pt| (pt.ycoord, pt.xcoord))
639}
640
641pub fn point_in_polygon<T>(pointset: &[Point<T, T>], ptq: &Point<T, T>) -> bool
643where
644 T: Clone + Num + Ord + Copy + PartialOrd,
645{
646 let n = pointset.len();
647 if n == 0 {
648 return false;
649 }
650
651 let mut pt0 = &pointset[n - 1];
652 let mut res = false;
653
654 for pt1 in pointset.iter() {
655 if (pt1.ycoord <= ptq.ycoord && ptq.ycoord < pt0.ycoord)
656 || (pt0.ycoord <= ptq.ycoord && ptq.ycoord < pt1.ycoord)
657 {
658 let det = (*ptq - *pt0).cross(&(*pt1 - *pt0));
659 if pt1.ycoord > pt0.ycoord {
660 if det < T::zero() {
661 res = !res;
662 }
663 } else if det > T::zero() {
664 res = !res;
665 }
666 }
667 pt0 = pt1;
668 }
669
670 res
671}
672
673pub fn polygon_is_anticlockwise<T>(pointset: &[Point<T, T>]) -> bool
675where
676 T: Clone + Num + Ord + Copy + PartialOrd,
677{
678 if pointset.len() < 3 {
679 panic!("Polygon must have at least 3 points");
680 }
681
682 let (min_index, _) = pointset
684 .iter()
685 .enumerate()
686 .min_by(|(_, a), (_, b)| {
687 a.xcoord
688 .partial_cmp(&b.xcoord)
689 .unwrap_or(Ordering::Equal)
690 .then(a.ycoord.partial_cmp(&b.ycoord).unwrap_or(Ordering::Equal))
691 })
692 .unwrap();
693
694 let n = pointset.len();
696 let prev_point = pointset[(min_index + n - 1) % n];
697 let current_point = pointset[min_index];
698 let next_point = pointset[(min_index + 1) % n];
699
700 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
702}
703
704impl<T: PartialEq> PartialEq for Polygon<T> {
706 fn eq(&self, other: &Self) -> bool {
707 self.origin == other.origin && self.vecs == other.vecs
708 }
709}
710
711impl<T: AddAssign + Clone + Num> AddAssign<Vector2<T, T>> for Polygon<T> {
713 fn add_assign(&mut self, rhs: Vector2<T, T>) {
714 self.origin += rhs;
715 }
716}
717
718impl<T: SubAssign + Clone + Num> SubAssign<Vector2<T, T>> for Polygon<T> {
719 fn sub_assign(&mut self, rhs: Vector2<T, T>) {
720 self.origin -= rhs;
721 }
722}
723
724#[cfg(test)]
725mod tests {
726 use super::*;
727 use crate::point::Point;
728 use crate::vector2::Vector2;
729
730 #[test]
731 fn test_polygon() {
732 let coords = [
733 (-2, 2),
734 (0, -1),
735 (-5, 1),
736 (-2, 4),
737 (0, -4),
738 (-4, 3),
739 (-6, -2),
740 (5, 1),
741 (2, 2),
742 (3, -3),
743 (-3, -3),
744 (3, 3),
745 (-3, -4),
746 (1, 4),
747 ];
748
749 let mut pointset = Vec::new();
750 for (x_coord, y_coord) in coords.iter() {
751 pointset.push(Point::new(*x_coord, *y_coord));
752 }
753
754 let poly_points = create_xmono_polygon(&pointset);
755 assert!(polygon_is_anticlockwise(&poly_points));
756
757 let poly = Polygon::from_pointset(&poly_points);
758 let mut poly2 = Polygon::from_pointset(&poly_points);
759 poly2.add_assign(Vector2::new(4, 5));
760 poly2.sub_assign(Vector2::new(4, 5));
761 assert_eq!(poly2, poly);
762 }
763
764 #[test]
765 fn test_ymono_polygon() {
766 let coords = [
767 (-2, 2),
768 (0, -1),
769 (-5, 1),
770 (-2, 4),
771 (0, -4),
772 (-4, 3),
773 (-6, -2),
774 (5, 1),
775 (2, 2),
776 (3, -3),
777 (-3, -3),
778 (3, 3),
779 (-3, -4),
780 (1, 4),
781 ];
782
783 let mut pointset = Vec::new();
784 for (x_coord, y_coord) in coords.iter() {
785 pointset.push(Point::new(*x_coord, *y_coord));
786 }
787
788 let poly_points = create_ymono_polygon(&pointset);
789 assert!(polygon_is_ymonotone(&poly_points));
790 assert!(!polygon_is_xmonotone(&poly_points));
791 assert!(polygon_is_anticlockwise(&poly_points));
792
793 let poly = Polygon::from_pointset(&poly_points);
794 assert_eq!(poly.signed_area_x2(), 102);
795 assert!(poly.is_anticlockwise());
796 }
797
798 #[test]
799 fn test_xmono_polygon() {
800 let coords = [
801 (-2, 2),
802 (0, -1),
803 (-5, 1),
804 (-2, 4),
805 (0, -4),
806 (-4, 3),
807 (-6, -2),
808 (5, 1),
809 (2, 2),
810 (3, -3),
811 (-3, -3),
812 (3, 3),
813 (-3, -4),
814 (1, 4),
815 ];
816
817 let mut pointset = Vec::new();
818 for (x_coord, y_coord) in coords.iter() {
819 pointset.push(Point::new(*x_coord, *y_coord));
820 }
821
822 let poly_points = create_xmono_polygon(&pointset);
823 assert!(polygon_is_xmonotone(&poly_points));
824 assert!(!polygon_is_ymonotone(&poly_points));
825 assert!(polygon_is_anticlockwise(&poly_points));
826
827 let poly = Polygon::from_pointset(&poly_points);
828 assert_eq!(poly.signed_area_x2(), 111);
829 assert!(poly.is_anticlockwise());
830 }
831
832 #[test]
833 fn test_is_rectilinear() {
834 let rectilinear_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
836 let rectilinear_points: Vec<Point<i32, i32>> = rectilinear_coords
837 .iter()
838 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
839 .collect();
840 let rectilinear_polygon = Polygon::from_pointset(&rectilinear_points);
841 assert!(rectilinear_polygon.is_rectilinear());
842
843 let non_rectilinear_coords = [(0, 0), (1, 1), (2, 0)];
845 let non_rectilinear_points: Vec<Point<i32, i32>> = non_rectilinear_coords
846 .iter()
847 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
848 .collect();
849 let non_rectilinear_polygon = Polygon::from_pointset(&non_rectilinear_points);
850 assert!(!non_rectilinear_polygon.is_rectilinear());
851 }
852
853 #[test]
854 fn test_is_convex() {
855 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
857 let convex_points: Vec<Point<i32, i32>> = convex_coords
858 .iter()
859 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
860 .collect();
861 let convex_polygon = Polygon::from_pointset(&convex_points);
862 assert!(convex_polygon.is_convex());
863
864 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
866 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
867 .iter()
868 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
869 .collect();
870 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
871 assert!(!non_convex_polygon.is_convex());
872
873 let triangle_coords = [(0, 0), (2, 0), (1, 2)];
875 let triangle_points: Vec<Point<i32, i32>> = triangle_coords
876 .iter()
877 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
878 .collect();
879 let triangle = Polygon::from_pointset(&triangle_points);
880 assert!(triangle.is_convex());
881 }
882
883 #[test]
884 fn test_is_anticlockwise() {
885 let clockwise_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
887 let clockwise_points: Vec<Point<i32, i32>> = clockwise_coords
888 .iter()
889 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
890 .collect();
891 let clockwise_polygon = Polygon::from_pointset(&clockwise_points);
892 assert!(!clockwise_polygon.is_anticlockwise());
893
894 let counter_clockwise_coords = [(0, 0), (1, 0), (1, 1), (0, 1)];
896 let counter_clockwise_points: Vec<Point<i32, i32>> = counter_clockwise_coords
897 .iter()
898 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
899 .collect();
900 let counter_clockwise_polygon = Polygon::from_pointset(&counter_clockwise_points);
901 assert!(counter_clockwise_polygon.is_anticlockwise());
902 }
903
904 #[test]
905 fn test_is_convex_clockwise() {
906 let convex_coords = [(0, 0), (0, 2), (2, 2), (2, 0)];
908 let convex_points: Vec<Point<i32, i32>> = convex_coords
909 .iter()
910 .map(|(x, y)| Point::new(*x, *y))
911 .collect();
912 let convex_polygon = Polygon::from_pointset(&convex_points);
913 assert!(convex_polygon.is_convex());
914
915 let non_convex_coords = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0)];
917 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
918 .iter()
919 .map(|(x, y)| Point::new(*x, *y))
920 .collect();
921 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
922 assert!(!non_convex_polygon.is_convex());
923 }
924
925 #[test]
926 fn test_point_in_polygon_missed_branches() {
927 let coords = [(0, 0), (10, 0), (10, 10), (0, 10)];
928 let pointset: Vec<Point<i32, i32>> = coords
929 .iter()
930 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
931 .collect();
932
933 assert!(!point_in_polygon(&pointset, &Point::new(5, 10)));
935
936 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
938
939 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
941 }
942
943 #[test]
944 #[should_panic(expected = "Polygon must have at least 3 points")]
945 fn test_polygon_is_anticlockwise_less_than_3_points() {
946 let coords = [(0, 0), (0, 1)];
947 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
948 polygon_is_anticlockwise(&points);
949 }
950
951 #[test]
952 #[should_panic(expected = "Polygon must have at least 3 points")]
953 fn test_is_anticlockwise_less_than_3_points() {
954 let coords = [(0, 0), (0, 1)];
955 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
956 let polygon = Polygon::from_pointset(&points);
957 polygon.is_anticlockwise();
958 }
959
960 #[test]
961 fn test_is_convex_more() {
962 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
964 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
965 .iter()
966 .map(|(x, y)| Point::new(*x, *y))
967 .collect();
968 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
969 assert!(!non_convex_polygon.is_convex());
970
971 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
973 let convex_points: Vec<Point<i32, i32>> = convex_coords
974 .iter()
975 .map(|(x, y)| Point::new(*x, *y))
976 .collect();
977 let convex_polygon = Polygon::from_pointset(&convex_points);
978 assert!(convex_polygon.is_convex());
979 }
980
981 #[test]
982 fn test_point_in_polygon_more() {
983 let coords = [(0, 0), (10, 5), (0, 10)];
985 let pointset: Vec<Point<i32, i32>> = coords
986 .iter()
987 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
988 .collect();
989
990 assert!(point_in_polygon(&pointset, &Point::new(1, 5)));
992
993 let coords_cw = [(0, 0), (0, 10), (10, 5)];
995 let pointset_cw: Vec<Point<i32, i32>> = coords_cw
996 .iter()
997 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
998 .collect();
999 assert!(point_in_polygon(&pointset_cw, &Point::new(1, 5)));
1000 }
1001}
1002
1003#[test]
1004fn test_polygon_signed_area_x2() {
1005 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1007 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1008 let poly = Polygon::from_pointset(&pointset);
1009 assert_eq!(poly.signed_area_x2(), 24); }
1011
1012#[test]
1013fn test_polygon_vertices() {
1014 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1015 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1016 let poly = Polygon::from_pointset(&pointset);
1017 let vertices = poly.vertices();
1018 assert_eq!(vertices.len(), 4);
1019}
1020
1021#[test]
1022fn test_polygon_bounding_box() {
1023 let coords = [(1, 1), (5, 1), (5, 4), (1, 4)];
1024 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1025 let poly = Polygon::from_pointset(&pointset);
1026 let (min, max) = poly.bounding_box();
1027 assert_eq!(min, Point::new(1, 1));
1028 assert_eq!(max, Point::new(5, 4));
1029}
1030
1031#[test]
1032fn test_polygon_add_assign() {
1033 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1034 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1035 let mut poly = Polygon::from_pointset(&pointset);
1036 poly.add_assign(Vector2::new(1, 2));
1037 assert_eq!(poly.origin, Point::new(1, 2));
1038}
1039
1040#[test]
1041fn test_polygon_sub_assign() {
1042 let coords = [(1, 2), (5, 2), (5, 5), (1, 5)];
1043 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1044 let mut poly = Polygon::from_pointset(&pointset);
1045 poly.sub_assign(Vector2::new(1, 2));
1046 assert_eq!(poly.origin, Point::new(0, 0));
1047}
1048
1049#[test]
1050fn test_polygon_partial_eq() {
1051 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1052 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1053 let poly1 = Polygon::from_pointset(&pointset);
1054 let poly2 = Polygon::from_pointset(&pointset);
1055 assert_eq!(poly1, poly2);
1056
1057 let coords2 = [(0, 0), (5, 0), (5, 3), (0, 3)];
1058 let pointset2: Vec<Point<i32, i32>> = coords2.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1059 let poly3 = Polygon::from_pointset(&pointset2);
1060 assert_ne!(poly1, poly3);
1061}
1062
1063#[test]
1064fn test_polygon_from_origin_and_vectors() {
1065 let origin = Point::new(0, 0);
1066 let vecs = vec![Vector2::new(4, 0), Vector2::new(0, 3), Vector2::new(-4, 0)];
1067 let poly = Polygon::from_origin_and_vectors(origin, vecs);
1068 assert_eq!(poly.origin, Point::new(0, 0));
1069 assert_eq!(poly.vecs.len(), 3);
1070}
1071
1072#[test]
1073fn test_polygon_default() {
1074 let poly: Polygon<i32> = Polygon::default();
1075 assert_eq!(poly.origin, Point::new(0, 0));
1076}
1077
1078#[test]
1079fn test_polygon_is_monotone_custom() {
1080 let coords = [(0, 0), (1, 0), (2, 1), (1, 2), (0, 2)];
1082 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1083 assert!(polygon_is_monotone(&pointset, |pt| (pt.xcoord, pt.ycoord)));
1085}
1086
1087#[test]
1088fn test_create_mono_polygon_custom() {
1089 let coords = [(0, 0), (2, 1), (1, 2), (3, 2)];
1091 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1092 let result = create_mono_polygon(&pointset, |pt| (pt.xcoord, pt.ycoord));
1093 assert!(!result.is_empty());
1094}
1095
1096#[test]
1097fn test_polygon_empty_vecs_is_rectilinear() {
1098 let origin = Point::new(0, 0);
1100 let poly = Polygon::from_origin_and_vectors(origin, vec![]);
1101 assert!(poly.is_rectilinear());
1102}
1103
1104#[test]
1105fn test_polygon_signed_area_x2_triangle() {
1106 let coords = [(0, 0), (3, 0), (0, 4)];
1108 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1109 let poly = Polygon::from_pointset(&pointset);
1110 assert_eq!(poly.signed_area_x2(), 12);
1113}