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 mut min_x = self.origin.xcoord;
296 let mut min_y = self.origin.ycoord;
297 let mut max_x = self.origin.xcoord;
298 let mut max_y = self.origin.ycoord;
299
300 for vec in &self.vecs {
301 let x = self.origin.xcoord + vec.x_;
302 let y = self.origin.ycoord + vec.y_;
303 if x < min_x {
304 min_x = x;
305 }
306 if y < min_y {
307 min_y = y;
308 }
309 if x > max_x {
310 max_x = x;
311 }
312 if y > max_y {
313 max_y = y;
314 }
315 }
316
317 (Point::new(min_x, min_y), Point::new(max_x, max_y))
318 }
319
320 pub fn is_rectilinear(&self) -> bool {
348 if self.vecs.is_empty() {
349 return true;
350 }
351
352 if self.vecs[0].x_ != T::zero() && self.vecs[0].y_ != T::zero() {
354 return false;
355 }
356
357 for i in 0..self.vecs.len() - 1 {
359 let v1 = self.vecs[i];
360 let v2 = self.vecs[i + 1];
361 if v1.x_ != v2.x_ && v1.y_ != v2.y_ {
362 return false;
363 }
364 }
365
366 let last_vec = self.vecs.last().unwrap();
368 last_vec.x_ == T::zero() || last_vec.y_ == T::zero()
369 }
370
371 pub fn is_anticlockwise(&self) -> bool
378 where
379 T: PartialOrd,
380 {
381 let n = self.vecs.len() + 1;
382 if n < 3 {
383 panic!("Polygon must have at least 3 points");
384 }
385
386 let get_pt = |i: usize| -> Vector2<T, T> {
387 if i == 0 {
388 Vector2::new(T::zero(), T::zero())
389 } else {
390 self.vecs[i - 1]
391 }
392 };
393
394 let (min_index, _) = (0..n)
396 .map(|i| (i, get_pt(i)))
397 .min_by(|(_, a), (_, b)| {
398 a.x_.partial_cmp(&b.x_)
399 .unwrap_or(Ordering::Equal)
400 .then(a.y_.partial_cmp(&b.y_).unwrap_or(Ordering::Equal))
401 })
402 .unwrap();
403
404 let prev_point = get_pt((min_index + n - 1) % n);
406 let current_point = get_pt(min_index);
407 let next_point = get_pt((min_index + 1) % n);
408
409 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
411 }
412
413 pub fn is_convex(&self) -> bool
453 where
454 T: PartialOrd,
455 {
456 let n = self.vecs.len();
457 if n < 2 {
458 return false;
459 }
460 if n == 2 {
461 return true;
462 }
463
464 let cross_product_sign =
468 self.vecs[n - 2].y_ * self.vecs[0].x_ - self.vecs[n - 2].x_ * self.vecs[0].y_;
469
470 for i in 0..n - 1 {
471 let v0 = if i == 0 {
472 Vector2::new(T::zero(), T::zero())
473 } else {
474 self.vecs[i - 1]
475 };
476 let v1 = self.vecs[i];
477 let v2 = self.vecs[i + 1];
478
479 let current_cross =
480 (v1.x_ - v0.x_) * (v2.y_ - v1.y_) - (v1.y_ - v0.y_) * (v2.x_ - v1.x_);
481
482 if (cross_product_sign > T::zero()) != (current_cross > T::zero()) {
483 return false;
484 }
485 }
486
487 true
488 }
489}
490
491pub fn create_mono_polygon<T, F>(pointset: &[Point<T, T>], func: F) -> Vec<Point<T, T>>
502where
503 T: Clone + Num + Ord + Copy + PartialOrd,
504 F: Fn(&Point<T, T>) -> (T, T),
505{
506 let max_pt = pointset
507 .iter()
508 .max_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
509 .unwrap();
510 let min_pt = pointset
511 .iter()
512 .min_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
513 .unwrap();
514 let diff = *max_pt - *min_pt;
515
516 let (mut lst1, mut lst2): (Vec<Point<T, T>>, Vec<Point<T, T>>) = pointset
517 .iter()
518 .partition(|&a| diff.cross(&(*a - *min_pt)) <= T::zero());
519
520 lst1.sort_by_key(|a| func(a));
521 lst2.sort_by_key(|a| func(a));
522 lst2.reverse();
523 lst1.append(&mut lst2);
524 lst1
525}
526
527#[inline]
556pub fn create_xmono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
557where
558 T: Clone + Num + Ord + Copy + PartialOrd,
559{
560 create_mono_polygon(pointset, |a| (a.xcoord, a.ycoord))
561}
562
563#[inline]
592pub fn create_ymono_polygon<T>(pointset: &[Point<T, T>]) -> Vec<Point<T, T>>
593where
594 T: Clone + Num + Ord + Copy + PartialOrd,
595{
596 create_mono_polygon(pointset, |a| (a.ycoord, a.xcoord))
597}
598
599pub fn polygon_is_monotone<T, F>(lst: &[Point<T, T>], dir: F) -> bool
606where
607 T: Clone + Num + Ord + Copy + PartialOrd,
608 F: Fn(&Point<T, T>) -> (T, T),
609{
610 if lst.len() <= 3 {
611 return true;
612 }
613
614 let (min_index, _) = lst
615 .iter()
616 .enumerate()
617 .min_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
618 .unwrap();
619
620 let (max_index, _) = lst
621 .iter()
622 .enumerate()
623 .max_by(|(_, a), (_, b)| dir(a).partial_cmp(&dir(b)).unwrap())
624 .unwrap();
625
626 let n = lst.len();
627
628 let mut i = min_index;
630 while i != max_index {
631 let next_i = (i + 1) % n;
632 if dir(&lst[i]).0 > dir(&lst[next_i]).0 {
633 return false;
634 }
635 i = next_i;
636 }
637
638 let mut i = max_index;
640 while i != min_index {
641 let next_i = (i + 1) % n;
642 if dir(&lst[i]).0 < dir(&lst[next_i]).0 {
643 return false;
644 }
645 i = next_i;
646 }
647
648 true
649}
650
651pub fn polygon_is_xmonotone<T>(lst: &[Point<T, T>]) -> bool
653where
654 T: Clone + Num + Ord + Copy + PartialOrd,
655{
656 polygon_is_monotone(lst, |pt| (pt.xcoord, pt.ycoord))
657}
658
659pub fn polygon_is_ymonotone<T>(lst: &[Point<T, T>]) -> bool
661where
662 T: Clone + Num + Ord + Copy + PartialOrd,
663{
664 polygon_is_monotone(lst, |pt| (pt.ycoord, pt.xcoord))
665}
666
667pub fn point_in_polygon<T>(pointset: &[Point<T, T>], ptq: &Point<T, T>) -> bool
673where
674 T: Clone + Num + Ord + Copy + PartialOrd,
675{
676 let n = pointset.len();
677 if n == 0 {
678 return false;
679 }
680
681 let mut pt0 = &pointset[n - 1];
682 let mut res = false;
683
684 for pt1 in pointset.iter() {
685 if (pt1.ycoord <= ptq.ycoord && ptq.ycoord < pt0.ycoord)
686 || (pt0.ycoord <= ptq.ycoord && ptq.ycoord < pt1.ycoord)
687 {
688 let det = (*ptq - *pt0).cross(&(*pt1 - *pt0));
689 if pt1.ycoord > pt0.ycoord {
690 if det < T::zero() {
691 res = !res;
692 }
693 } else if det > T::zero() {
694 res = !res;
695 }
696 }
697 pt0 = pt1;
698 }
699
700 res
701}
702
703pub fn polygon_is_anticlockwise<T>(pointset: &[Point<T, T>]) -> bool
708where
709 T: Clone + Num + Ord + Copy + PartialOrd,
710{
711 if pointset.len() < 3 {
712 panic!("Polygon must have at least 3 points");
713 }
714
715 let (min_index, _) = pointset
717 .iter()
718 .enumerate()
719 .min_by(|(_, a), (_, b)| {
720 a.xcoord
721 .partial_cmp(&b.xcoord)
722 .unwrap_or(Ordering::Equal)
723 .then(a.ycoord.partial_cmp(&b.ycoord).unwrap_or(Ordering::Equal))
724 })
725 .unwrap();
726
727 let n = pointset.len();
729 let prev_point = pointset[(min_index + n - 1) % n];
730 let current_point = pointset[min_index];
731 let next_point = pointset[(min_index + 1) % n];
732
733 (current_point - prev_point).cross(&(next_point - current_point)) > T::zero()
735}
736
737impl<T: PartialEq> PartialEq for Polygon<T> {
739 fn eq(&self, other: &Self) -> bool {
741 self.origin == other.origin && self.vecs == other.vecs
742 }
743}
744
745impl<T: AddAssign + Clone + Num> AddAssign<Vector2<T, T>> for Polygon<T> {
747 fn add_assign(&mut self, rhs: Vector2<T, T>) {
749 self.origin += rhs;
750 }
751}
752
753impl<T: SubAssign + Clone + Num> SubAssign<Vector2<T, T>> for Polygon<T> {
754 fn sub_assign(&mut self, rhs: Vector2<T, T>) {
756 self.origin -= rhs;
757 }
758}
759
760#[cfg(test)]
761mod tests {
762 use super::*;
763 use crate::point::Point;
764 use crate::vector2::Vector2;
765
766 #[test]
767 fn test_polygon() {
768 let coords = [
769 (-2, 2),
770 (0, -1),
771 (-5, 1),
772 (-2, 4),
773 (0, -4),
774 (-4, 3),
775 (-6, -2),
776 (5, 1),
777 (2, 2),
778 (3, -3),
779 (-3, -3),
780 (3, 3),
781 (-3, -4),
782 (1, 4),
783 ];
784
785 let mut pointset = Vec::new();
786 for (x_coord, y_coord) in coords.iter() {
787 pointset.push(Point::new(*x_coord, *y_coord));
788 }
789
790 let poly_points = create_xmono_polygon(&pointset);
791 assert!(polygon_is_anticlockwise(&poly_points));
792
793 let poly = Polygon::from_pointset(&poly_points);
794 let mut poly2 = Polygon::from_pointset(&poly_points);
795 poly2.add_assign(Vector2::new(4, 5));
796 poly2.sub_assign(Vector2::new(4, 5));
797 assert_eq!(poly2, poly);
798 }
799
800 #[test]
801 fn test_ymono_polygon() {
802 let coords = [
803 (-2, 2),
804 (0, -1),
805 (-5, 1),
806 (-2, 4),
807 (0, -4),
808 (-4, 3),
809 (-6, -2),
810 (5, 1),
811 (2, 2),
812 (3, -3),
813 (-3, -3),
814 (3, 3),
815 (-3, -4),
816 (1, 4),
817 ];
818
819 let mut pointset = Vec::new();
820 for (x_coord, y_coord) in coords.iter() {
821 pointset.push(Point::new(*x_coord, *y_coord));
822 }
823
824 let poly_points = create_ymono_polygon(&pointset);
825 assert!(polygon_is_ymonotone(&poly_points));
826 assert!(!polygon_is_xmonotone(&poly_points));
827 assert!(polygon_is_anticlockwise(&poly_points));
828
829 let poly = Polygon::from_pointset(&poly_points);
830 assert_eq!(poly.signed_area_x2(), 102);
831 assert!(poly.is_anticlockwise());
832 }
833
834 #[test]
835 fn test_xmono_polygon() {
836 let coords = [
837 (-2, 2),
838 (0, -1),
839 (-5, 1),
840 (-2, 4),
841 (0, -4),
842 (-4, 3),
843 (-6, -2),
844 (5, 1),
845 (2, 2),
846 (3, -3),
847 (-3, -3),
848 (3, 3),
849 (-3, -4),
850 (1, 4),
851 ];
852
853 let mut pointset = Vec::new();
854 for (x_coord, y_coord) in coords.iter() {
855 pointset.push(Point::new(*x_coord, *y_coord));
856 }
857
858 let poly_points = create_xmono_polygon(&pointset);
859 assert!(polygon_is_xmonotone(&poly_points));
860 assert!(!polygon_is_ymonotone(&poly_points));
861 assert!(polygon_is_anticlockwise(&poly_points));
862
863 let poly = Polygon::from_pointset(&poly_points);
864 assert_eq!(poly.signed_area_x2(), 111);
865 assert!(poly.is_anticlockwise());
866 }
867
868 #[test]
869 fn test_is_rectilinear() {
870 let rectilinear_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
872 let rectilinear_points: Vec<Point<i32, i32>> = rectilinear_coords
873 .iter()
874 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
875 .collect();
876 let rectilinear_polygon = Polygon::from_pointset(&rectilinear_points);
877 assert!(rectilinear_polygon.is_rectilinear());
878
879 let non_rectilinear_coords = [(0, 0), (1, 1), (2, 0)];
881 let non_rectilinear_points: Vec<Point<i32, i32>> = non_rectilinear_coords
882 .iter()
883 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
884 .collect();
885 let non_rectilinear_polygon = Polygon::from_pointset(&non_rectilinear_points);
886 assert!(!non_rectilinear_polygon.is_rectilinear());
887 }
888
889 #[test]
890 fn test_is_convex() {
891 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
893 let convex_points: Vec<Point<i32, i32>> = convex_coords
894 .iter()
895 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
896 .collect();
897 let convex_polygon = Polygon::from_pointset(&convex_points);
898 assert!(convex_polygon.is_convex());
899
900 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
902 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
903 .iter()
904 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
905 .collect();
906 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
907 assert!(!non_convex_polygon.is_convex());
908
909 let triangle_coords = [(0, 0), (2, 0), (1, 2)];
911 let triangle_points: Vec<Point<i32, i32>> = triangle_coords
912 .iter()
913 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
914 .collect();
915 let triangle = Polygon::from_pointset(&triangle_points);
916 assert!(triangle.is_convex());
917 }
918
919 #[test]
920 fn test_is_anticlockwise() {
921 let clockwise_coords = [(0, 0), (0, 1), (1, 1), (1, 0)];
923 let clockwise_points: Vec<Point<i32, i32>> = clockwise_coords
924 .iter()
925 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
926 .collect();
927 let clockwise_polygon = Polygon::from_pointset(&clockwise_points);
928 assert!(!clockwise_polygon.is_anticlockwise());
929
930 let counter_clockwise_coords = [(0, 0), (1, 0), (1, 1), (0, 1)];
932 let counter_clockwise_points: Vec<Point<i32, i32>> = counter_clockwise_coords
933 .iter()
934 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
935 .collect();
936 let counter_clockwise_polygon = Polygon::from_pointset(&counter_clockwise_points);
937 assert!(counter_clockwise_polygon.is_anticlockwise());
938 }
939
940 #[test]
941 fn test_is_convex_clockwise() {
942 let convex_coords = [(0, 0), (0, 2), (2, 2), (2, 0)];
944 let convex_points: Vec<Point<i32, i32>> = convex_coords
945 .iter()
946 .map(|(x, y)| Point::new(*x, *y))
947 .collect();
948 let convex_polygon = Polygon::from_pointset(&convex_points);
949 assert!(convex_polygon.is_convex());
950
951 let non_convex_coords = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0)];
953 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
954 .iter()
955 .map(|(x, y)| Point::new(*x, *y))
956 .collect();
957 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
958 assert!(!non_convex_polygon.is_convex());
959 }
960
961 #[test]
962 fn test_point_in_polygon_missed_branches() {
963 let coords = [(0, 0), (10, 0), (10, 10), (0, 10)];
964 let pointset: Vec<Point<i32, i32>> = coords
965 .iter()
966 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
967 .collect();
968
969 assert!(!point_in_polygon(&pointset, &Point::new(5, 10)));
971
972 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
974
975 assert!(point_in_polygon(&pointset, &Point::new(5, 0)));
977 }
978
979 #[test]
980 #[should_panic(expected = "Polygon must have at least 3 points")]
981 fn test_polygon_is_anticlockwise_less_than_3_points() {
982 let coords = [(0, 0), (0, 1)];
983 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
984 polygon_is_anticlockwise(&points);
985 }
986
987 #[test]
988 #[should_panic(expected = "Polygon must have at least 3 points")]
989 fn test_is_anticlockwise_less_than_3_points() {
990 let coords = [(0, 0), (0, 1)];
991 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
992 let polygon = Polygon::from_pointset(&points);
993 polygon.is_anticlockwise();
994 }
995
996 #[test]
997 fn test_is_convex_more() {
998 let non_convex_coords = [(0, 0), (2, 0), (1, 1), (2, 2), (0, 2)];
1000 let non_convex_points: Vec<Point<i32, i32>> = non_convex_coords
1001 .iter()
1002 .map(|(x, y)| Point::new(*x, *y))
1003 .collect();
1004 let non_convex_polygon = Polygon::from_pointset(&non_convex_points);
1005 assert!(!non_convex_polygon.is_convex());
1006
1007 let convex_coords = [(0, 0), (2, 0), (2, 2), (0, 2)];
1009 let convex_points: Vec<Point<i32, i32>> = convex_coords
1010 .iter()
1011 .map(|(x, y)| Point::new(*x, *y))
1012 .collect();
1013 let convex_polygon = Polygon::from_pointset(&convex_points);
1014 assert!(convex_polygon.is_convex());
1015 }
1016
1017 #[test]
1018 fn test_point_in_polygon_more() {
1019 let coords = [(0, 0), (10, 5), (0, 10)];
1021 let pointset: Vec<Point<i32, i32>> = coords
1022 .iter()
1023 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
1024 .collect();
1025
1026 assert!(point_in_polygon(&pointset, &Point::new(1, 5)));
1028
1029 let coords_cw = [(0, 0), (0, 10), (10, 5)];
1031 let pointset_cw: Vec<Point<i32, i32>> = coords_cw
1032 .iter()
1033 .map(|(x_coord, y_coord)| Point::new(*x_coord, *y_coord))
1034 .collect();
1035 assert!(point_in_polygon(&pointset_cw, &Point::new(1, 5)));
1036 }
1037
1038 #[test]
1039 fn test_is_rectilinear_non_rectilinear_last_edge() {
1040 let coords = [(0, 0), (4, 0), (4, 4), (1, 3)];
1042 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1043 let poly = Polygon::from_pointset(&points);
1044 assert!(!poly.is_rectilinear());
1045 }
1046
1047 #[test]
1048 fn test_is_convex_less_than_two_vecs() {
1049 let origin = Point::new(0, 0);
1051 let vecs = vec![Vector2::new(4, 0)];
1052 let poly = Polygon::from_origin_and_vectors(origin, vecs);
1053 assert!(!poly.is_convex());
1054 }
1055
1056 #[test]
1057 fn test_bounding_box_branches() {
1058 let coords = [(3, 5), (8, 2), (10, 7), (6, 9), (1, 4)];
1060 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1061 let poly = Polygon::from_pointset(&points);
1062 let (min_pt, max_pt) = poly.bounding_box();
1063 assert_eq!(min_pt, Point::new(1, 2));
1064 assert_eq!(max_pt, Point::new(10, 9));
1065 }
1066}
1067
1068#[test]
1069fn test_polygon_signed_area_x2() {
1070 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1072 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1073 let poly = Polygon::from_pointset(&pointset);
1074 assert_eq!(poly.signed_area_x2(), 24); }
1076
1077#[test]
1078fn test_polygon_vertices() {
1079 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1080 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1081 let poly = Polygon::from_pointset(&pointset);
1082 let vertices = poly.vertices();
1083 assert_eq!(vertices.len(), 4);
1084}
1085
1086#[test]
1087fn test_polygon_bounding_box() {
1088 let coords = [(1, 1), (5, 1), (5, 4), (1, 4)];
1089 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1090 let poly = Polygon::from_pointset(&pointset);
1091 let (min, max) = poly.bounding_box();
1092 assert_eq!(min, Point::new(1, 1));
1093 assert_eq!(max, Point::new(5, 4));
1094}
1095
1096#[test]
1097fn test_polygon_add_assign() {
1098 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1099 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1100 let mut poly = Polygon::from_pointset(&pointset);
1101 poly.add_assign(Vector2::new(1, 2));
1102 assert_eq!(poly.origin, Point::new(1, 2));
1103}
1104
1105#[test]
1106fn test_polygon_sub_assign() {
1107 let coords = [(1, 2), (5, 2), (5, 5), (1, 5)];
1108 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1109 let mut poly = Polygon::from_pointset(&pointset);
1110 poly.sub_assign(Vector2::new(1, 2));
1111 assert_eq!(poly.origin, Point::new(0, 0));
1112}
1113
1114#[test]
1115fn test_polygon_partial_eq() {
1116 let coords = [(0, 0), (4, 0), (4, 3), (0, 3)];
1117 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1118 let poly1 = Polygon::from_pointset(&pointset);
1119 let poly2 = Polygon::from_pointset(&pointset);
1120 assert_eq!(poly1, poly2);
1121
1122 let coords2 = [(0, 0), (5, 0), (5, 3), (0, 3)];
1123 let pointset2: Vec<Point<i32, i32>> = coords2.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1124 let poly3 = Polygon::from_pointset(&pointset2);
1125 assert_ne!(poly1, poly3);
1126}
1127
1128#[test]
1129fn test_polygon_from_origin_and_vectors() {
1130 let origin = Point::new(0, 0);
1131 let vecs = vec![Vector2::new(4, 0), Vector2::new(0, 3), Vector2::new(-4, 0)];
1132 let poly = Polygon::from_origin_and_vectors(origin, vecs);
1133 assert_eq!(poly.origin, Point::new(0, 0));
1134 assert_eq!(poly.vecs.len(), 3);
1135}
1136
1137#[test]
1138fn test_polygon_default() {
1139 let poly: Polygon<i32> = Polygon::default();
1140 assert_eq!(poly.origin, Point::new(0, 0));
1141}
1142
1143#[test]
1144fn test_polygon_is_monotone_custom() {
1145 let coords = [(0, 0), (1, 0), (2, 1), (1, 2), (0, 2)];
1147 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1148 assert!(polygon_is_monotone(&pointset, |pt| (pt.xcoord, pt.ycoord)));
1150}
1151
1152#[test]
1153fn test_create_mono_polygon_custom() {
1154 let coords = [(0, 0), (2, 1), (1, 2), (3, 2)];
1156 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1157 let result = create_mono_polygon(&pointset, |pt| (pt.xcoord, pt.ycoord));
1158 assert!(!result.is_empty());
1159}
1160
1161#[test]
1162fn test_polygon_empty_vecs_is_rectilinear() {
1163 let origin = Point::new(0, 0);
1165 let poly = Polygon::from_origin_and_vectors(origin, vec![]);
1166 assert!(poly.is_rectilinear());
1167}
1168
1169#[test]
1170fn test_polygon_signed_area_x2_triangle() {
1171 let coords = [(0, 0), (3, 0), (0, 4)];
1173 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1174 let poly = Polygon::from_pointset(&pointset);
1175 assert_eq!(poly.signed_area_x2(), 12);
1178}
1179
1180#[test]
1181fn test_polygon_signed_area_x2_single_vec() {
1182 let origin = Point::new(0, 0);
1184 let vecs = vec![Vector2::new(4, 0)];
1185 let poly = Polygon::from_origin_and_vectors(origin, vecs);
1186 assert_eq!(poly.signed_area_x2(), 0);
1187}
1188
1189#[test]
1190fn test_polygon_area_multi_vertex() {
1191 let coords = [(0, 0), (4, 0), (5, 3), (2, 5), (-1, 2)];
1193 let points: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
1194 let poly = Polygon::from_pointset(&points);
1195 assert_ne!(poly.area(), 0);
1197}