1#![allow(clippy::type_complexity)]
2
3use num_traits::Num;
4use std::cmp::Ord;
5use std::cmp::Ordering;
6use std::ops::{AddAssign, SubAssign};
7
8use crate::point::Point;
9use crate::vector2::Vector2;
10
11#[derive(Eq, Clone, Debug, Default)]
46pub struct RPolygon<T> {
47 pub origin: Point<T, T>,
48 vecs: Vec<Vector2<T, T>>,
49}
50
51impl<T: Clone + Num + Copy + std::ops::AddAssign + Ord> RPolygon<T> {
52 pub fn new(coords: &[Point<T, T>]) -> Self {
66 let (&origin, coords) = coords.split_first().unwrap();
72 let vecs = coords.iter().map(|pt| *pt - origin).collect();
73 RPolygon { origin, vecs }
74 }
75
76 pub fn from_origin_and_vectors(origin: Point<T, T>, vecs: Vec<Vector2<T, T>>) -> Self {
83 RPolygon { origin, vecs }
84 }
85
86 pub fn from_pointset(pointset: &[Point<T, T>]) -> Self {
91 Self::new(pointset)
92 }
93
94 pub fn add_assign(&mut self, rhs: Vector2<T, T>)
96 where
97 T: AddAssign,
98 {
99 self.origin += rhs;
100 }
101
102 pub fn sub_assign(&mut self, rhs: Vector2<T, T>)
104 where
105 T: SubAssign,
106 {
107 self.origin -= rhs;
108 }
109
110 pub fn signed_area(&self) -> T {
116 let mut itr = self.vecs.iter();
119 let mut vec0 = itr.next().unwrap();
120 let mut res = vec0.x_ * vec0.y_;
121 for vec1 in itr {
122 res += vec1.x_ * (vec1.y_ - vec0.y_);
123 vec0 = vec1;
124 }
125 res
126 }
127
128 pub fn vertices(&self) -> Vec<Point<T, T>> {
130 let mut result = Vec::with_capacity(self.vecs.len() + 1);
131 result.push(self.origin);
132
133 for vec in &self.vecs {
134 result.push(self.origin + *vec);
135 }
136
137 result
138 }
139
140 pub fn bounding_box(&self) -> (Point<T, T>, Point<T, T>) {
142 let mut min_x = T::zero();
143 let mut min_y = T::zero();
144 let mut max_x = T::zero();
145 let mut max_y = T::zero();
146
147 for vec in &self.vecs {
148 if vec.x_ < min_x {
149 min_x = vec.x_;
150 }
151 if vec.y_ < min_y {
152 min_y = vec.y_;
153 }
154 if vec.x_ > max_x {
155 max_x = vec.x_;
156 }
157 if vec.y_ > max_y {
158 max_y = vec.y_;
159 }
160 }
161
162 (
163 Point::new(self.origin.xcoord + min_x, self.origin.ycoord + min_y),
164 Point::new(self.origin.xcoord + max_x, self.origin.ycoord + max_y),
165 )
166 }
167
168 pub fn is_rectilinear(&self) -> bool {
196 true
197 }
198
199 pub fn is_anticlockwise(&self) -> bool
201 where
202 T: PartialOrd,
203 {
204 let mut pointset = Vec::with_capacity(self.vecs.len() + 1);
205 pointset.push(Vector2::new(T::zero(), T::zero()));
206 pointset.extend(self.vecs.iter().cloned());
207
208 if pointset.len() < 2 {
209 panic!("Polygon must have at least 2 points");
210 }
211
212 let (min_index, _) = pointset
214 .iter()
215 .enumerate()
216 .min_by(|(_, a), (_, b)| {
217 a.x_.partial_cmp(&b.x_)
218 .unwrap_or(Ordering::Equal)
219 .then(a.y_.partial_cmp(&b.y_).unwrap_or(Ordering::Equal))
220 })
221 .unwrap();
222
223 let n = pointset.len();
225 let prev_point = pointset[(min_index + n - 1) % n];
226 let current_point = pointset[min_index];
227
228 prev_point.y_ > current_point.y_
229 }
230}
231
232impl<T: PartialEq> PartialEq for RPolygon<T> {
234 fn eq(&self, other: &Self) -> bool {
235 self.origin == other.origin && self.vecs == other.vecs
236 }
237}
238
239impl<T: Clone + Num + Ord + Copy> RPolygon<T> {
240 pub fn create_mono_rpolygon<F>(pointset: &[Point<T, T>], func: F) -> (Vec<Point<T, T>>, bool)
251 where
252 F: Fn(&Point<T, T>) -> (T, T),
253 {
254 let rightmost = pointset
256 .iter()
257 .max_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
258 .unwrap();
259 let leftmost = pointset
260 .iter()
261 .min_by(|a, b| func(a).partial_cmp(&func(b)).unwrap())
262 .unwrap();
263 let is_anticlockwise = func(rightmost).1 <= func(leftmost).1;
264 let (mut lst1, mut lst2): (Vec<Point<T, T>>, Vec<Point<T, T>>) = if is_anticlockwise {
265 pointset
266 .iter()
267 .partition(|pt| func(pt).1 <= func(leftmost).1)
268 } else {
269 pointset
270 .iter()
271 .partition(|pt| func(pt).1 >= func(leftmost).1)
272 };
273 lst1.sort_by_key(|a| func(a));
274 lst2.sort_by_key(|a| func(a));
275 lst2.reverse();
276 lst1.append(&mut lst2);
277 (lst1, is_anticlockwise) }
279
280 #[inline]
287 pub fn create_xmono_rpolygon(pointset: &[Point<T, T>]) -> (Vec<Point<T, T>>, bool) {
288 Self::create_mono_rpolygon(pointset, |a| (a.xcoord, a.ycoord))
289 }
290
291 #[inline]
299 pub fn create_ymono_rpolygon(pointset: &[Point<T, T>]) -> (Vec<Point<T, T>>, bool) {
300 Self::create_mono_rpolygon(pointset, |a| (a.ycoord, a.xcoord))
301 }
302
303 pub fn point_in_rpolygon(pointset: &[Point<T, T>], query_pt: &Point<T, T>) -> bool {
329 let mut result = false;
330 let n = pointset.len();
331 let mut pt0 = &pointset[n - 1];
332 for pt1 in pointset.iter() {
333 if ((pt1.ycoord <= query_pt.ycoord && query_pt.ycoord < pt0.ycoord)
334 || (pt0.ycoord <= query_pt.ycoord && query_pt.ycoord < pt1.ycoord))
335 && pt1.xcoord > query_pt.xcoord
336 {
337 result = !result;
338 }
339 pt0 = pt1;
340 }
341 result
342 }
343}
344
345pub fn rpolygon_is_monotone<T, F>(lst: &[Point<T, T>], dir: F) -> bool
347where
348 T: Clone + Num + Ord + Copy + PartialOrd,
349 F: Fn(&Point<T, T>) -> (T, T),
350{
351 if lst.len() <= 3 {
352 return true;
353 }
354
355 let (min_index, _) = lst
356 .iter()
357 .enumerate()
358 .min_by_key(|(_, pt)| dir(pt))
359 .unwrap();
360
361 let (max_index, _) = lst
362 .iter()
363 .enumerate()
364 .max_by_key(|(_, pt)| dir(pt))
365 .unwrap();
366
367 let n = lst.len();
368
369 let mut i = min_index;
371 while i != max_index {
372 let next_i = (i + 1) % n;
373 if dir(&lst[i]).0 > dir(&lst[next_i]).0 {
374 return false;
375 }
376 i = next_i;
377 }
378
379 let mut i = max_index;
381 while i != min_index {
382 let next_i = (i + 1) % n;
383 if dir(&lst[i]).0 < dir(&lst[next_i]).0 {
384 return false;
385 }
386 i = next_i;
387 }
388
389 true
390}
391
392pub fn rpolygon_is_xmonotone<T>(lst: &[Point<T, T>]) -> bool
394where
395 T: Clone + Num + Ord + Copy + PartialOrd,
396{
397 rpolygon_is_monotone(lst, |pt| (pt.xcoord, pt.ycoord))
398}
399
400pub fn rpolygon_is_ymonotone<T>(lst: &[Point<T, T>]) -> bool
402where
403 T: Clone + Num + Ord + Copy + PartialOrd,
404{
405 rpolygon_is_monotone(lst, |pt| (pt.ycoord, pt.xcoord))
406}
407
408pub fn rpolygon_is_convex<T>(lst: &[Point<T, T>]) -> bool
410where
411 T: Clone + Num + Ord + Copy + PartialOrd,
412{
413 rpolygon_is_xmonotone(lst) && rpolygon_is_ymonotone(lst)
414}
415
416pub fn rpolygon_is_anticlockwise<T>(pointset: &[Point<T, T>]) -> bool
418where
419 T: Clone + Num + Ord + Copy + PartialOrd,
420{
421 if pointset.len() < 2 {
422 panic!("Polygon must have at least 2 points");
423 }
424
425 let (min_index, min_point) = pointset
427 .iter()
428 .enumerate()
429 .min_by(|(_, a), (_, b)| {
430 a.xcoord
431 .partial_cmp(&b.xcoord)
432 .unwrap_or(Ordering::Equal)
433 .then(a.ycoord.partial_cmp(&b.ycoord).unwrap_or(Ordering::Equal))
434 })
435 .unwrap();
436
437 let n = pointset.len();
439 let prev_index = (min_index + n - 1) % n;
440
441 let prev_point = pointset[prev_index];
442 let current_point = *min_point;
443
444 prev_point.ycoord() > current_point.ycoord()
445}
446
447#[cfg(test)]
448mod test {
449 #![allow(non_upper_case_globals)]
450
451 use super::*;
452
453 #[test]
454 pub fn test_ymono_rpolygon() {
455 let coords = [
456 (-2, 2),
457 (0, -1),
458 (-5, 1),
459 (-2, 4),
460 (0, -4),
461 (-4, 3),
462 (-6, -2),
463 (5, 1),
464 (2, 2),
465 (3, -3),
466 (-3, -4),
467 (1, 4),
468 ];
469 let mut pointset = vec![];
470 for (x_coord, y_coord) in coords.iter() {
471 pointset.push(Point::<i32, i32>::new(*x_coord, *y_coord));
472 }
473 let (poly_points, is_cw) = RPolygon::<i32>::create_ymono_rpolygon(&pointset);
474 assert!(rpolygon_is_anticlockwise(&poly_points));
475 assert!(rpolygon_is_ymonotone(&poly_points));
476 assert!(!rpolygon_is_xmonotone(&poly_points));
477 for pt in poly_points.iter() {
478 print!("({}, {}) ", pt.xcoord, pt.ycoord);
479 }
480 let poly = RPolygon::<i32>::new(&poly_points);
481 assert!(!is_cw);
482 assert_eq!(poly.signed_area(), 45);
483 }
484
485 #[test]
486 pub fn test_xmono_rpolygon() {
487 let coords = [
488 (-2, 2),
489 (0, -1),
490 (-5, 1),
491 (-2, 4),
492 (0, -4),
493 (-4, 3),
494 (-6, -2),
495 (5, 1),
496 (2, 2),
497 (3, -3),
498 (-3, -4),
499 (1, 4),
500 ];
501 let mut pointset = vec![];
502 for (x_coord, y_coord) in coords.iter() {
503 pointset.push(Point::<i32, i32>::new(*x_coord, *y_coord));
504 }
505 let (poly_points, is_anticw) = RPolygon::<i32>::create_xmono_rpolygon(&pointset);
506 assert!(!rpolygon_is_anticlockwise(&poly_points));
507 assert!(rpolygon_is_xmonotone(&poly_points));
508 assert!(!rpolygon_is_ymonotone(&poly_points));
509 for pt in poly_points.iter() {
510 print!("({}, {}) ", pt.xcoord, pt.ycoord);
511 }
512 let poly = RPolygon::<i32>::new(&poly_points);
513 assert!(!is_anticw);
514 assert_eq!(poly.signed_area(), -53);
515 assert!(!poly.is_anticlockwise())
516 }
517
518 #[test]
519 pub fn test_point_in_rpolygon() {
520 let coords = [
521 (-2, 2),
522 (0, -1),
523 (-5, 1),
524 (-2, 4),
525 (0, -4),
526 (-4, 3),
527 (-6, -2),
528 (5, 1),
529 (2, 2),
530 (3, -3),
531 (-3, -4),
532 (1, 4),
533 ];
534 let mut pointset = vec![];
535 for (x_coord, y_coord) in coords.iter() {
536 pointset.push(Point::<i32, i32>::new(*x_coord, *y_coord));
537 }
538 let query_pt = Point::<i32, i32>::new(0, -3);
539 assert!(!RPolygon::<i32>::point_in_rpolygon(&pointset, &query_pt));
541 }
542
543 #[test]
544 fn test_signed_area_more_cases() {
545 let pt1 = Point::new(0, 0);
546 let pt2 = Point::new(1, 0);
547 let pt3 = Point::new(1, 1);
548 let pt4 = Point::new(0, 1);
549 let poly = RPolygon::new(&[pt1, pt2, pt3, pt4]);
550 assert_eq!(poly.signed_area(), 1);
551
552 let pt5 = Point::new(0, 0);
553 let pt6 = Point::new(0, 1);
554 let pt7 = Point::new(1, 1);
555 let pt8 = Point::new(1, 0);
556 let poly2 = RPolygon::new(&[pt5, pt6, pt7, pt8]);
557 assert_eq!(poly2.signed_area(), -1);
558 }
559
560 #[test]
561 fn test_point_in_rpolygon_more_cases() {
562 let pt1 = Point::new(0, 0);
563 let pt2 = Point::new(1, 0);
564 let pt3 = Point::new(1, 1);
565 let pt4 = Point::new(0, 1);
566 let pointset = &[pt1, pt2, pt3, pt4];
567
568 let query_pt1 = Point::new(0, 0);
569 assert!(RPolygon::<i32>::point_in_rpolygon(pointset, &query_pt1));
570
571 let query_pt2 = Point::new(1, 1);
572 assert!(!RPolygon::<i32>::point_in_rpolygon(pointset, &query_pt2));
573
574 let query_pt3 = Point::new(0, 1);
575 assert!(!RPolygon::<i32>::point_in_rpolygon(pointset, &query_pt3));
576
577 let query_pt4 = Point::new(1, 0);
578 assert!(!RPolygon::<i32>::point_in_rpolygon(pointset, &query_pt4));
579 }
580}
581
582#[test]
583fn test_rpolygon_is_xmonotone() {
584 let coords = [(0, 0), (1, 0), (2, 0), (2, 1), (1, 1), (0, 1)];
586 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
587 assert!(rpolygon_is_xmonotone(&pointset));
588
589 let coords2 = [(0, 0), (2, 0), (1, 1), (0, 2), (2, 2)];
591 let pointset2: Vec<Point<i32, i32>> = coords2.iter().map(|(x, y)| Point::new(*x, *y)).collect();
592 assert!(!rpolygon_is_xmonotone(&pointset2));
593}
594
595#[test]
596fn test_rpolygon_is_ymonotone() {
597 let coords = [(0, 0), (0, 1), (0, 2), (1, 2), (1, 1), (1, 0)];
599 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
600 assert!(rpolygon_is_ymonotone(&pointset));
601
602 let coords2 = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0)];
604 let pointset2: Vec<Point<i32, i32>> = coords2.iter().map(|(x, y)| Point::new(*x, *y)).collect();
605 assert!(!rpolygon_is_ymonotone(&pointset2));
606}
607
608#[test]
609fn test_rpolygon_is_convex() {
610 let coords = [(0, 0), (0, 2), (2, 2), (2, 0)];
612 let pointset: Vec<Point<i32, i32>> = coords.iter().map(|(x, y)| Point::new(*x, *y)).collect();
613 assert!(rpolygon_is_convex(&pointset));
614
615 let coords2 = [(0, 0), (0, 2), (1, 1), (2, 2), (2, 0)];
617 let pointset2: Vec<Point<i32, i32>> = coords2.iter().map(|(x, y)| Point::new(*x, *y)).collect();
618 assert!(!rpolygon_is_convex(&pointset2));
619}
620
621#[test]
622fn test_rpolygon_vertices() {
623 let pt1 = Point::new(0, 0);
624 let pt2 = Point::new(1, 0);
625 let pt3 = Point::new(1, 1);
626 let poly = RPolygon::new(&[pt1, pt2, pt3]);
627 let vertices = poly.vertices();
628 assert_eq!(vertices.len(), 3);
629 assert_eq!(vertices[0], pt1);
630 assert_eq!(vertices[1], pt2);
631 assert_eq!(vertices[2], pt3);
632}
633
634#[test]
635fn test_rpolygon_bounding_box() {
636 let pt1 = Point::new(0, 0);
637 let pt2 = Point::new(2, 0);
638 let pt3 = Point::new(2, 2);
639 let pt4 = Point::new(0, 2);
640 let poly = RPolygon::new(&[pt1, pt2, pt3, pt4]);
641 let (min, max) = poly.bounding_box();
642 assert_eq!(min, Point::new(0, 0));
643 assert_eq!(max, Point::new(2, 2));
644}
645
646#[test]
647fn test_rpolygon_add_assign() {
648 let pt1 = Point::new(0, 0);
649 let pt2 = Point::new(1, 0);
650 let pt3 = Point::new(1, 1);
651 let mut poly = RPolygon::new(&[pt1, pt2, pt3]);
652 poly.add_assign(Vector2::new(1, 1));
653 let vertices = poly.vertices();
654 assert_eq!(vertices[0], Point::new(1, 1));
655}
656
657#[test]
658fn test_rpolygon_sub_assign() {
659 let pt1 = Point::new(1, 1);
660 let pt2 = Point::new(2, 1);
661 let pt3 = Point::new(2, 2);
662 let mut poly = RPolygon::new(&[pt1, pt2, pt3]);
663 poly.sub_assign(Vector2::new(1, 1));
664 let vertices = poly.vertices();
665 assert_eq!(vertices[0], Point::new(0, 0));
666}
667
668#[test]
669fn test_rpolygon_is_rectilinear() {
670 let pt1 = Point::new(0, 0);
671 let pt2 = Point::new(1, 0);
672 let pt3 = Point::new(1, 1);
673 let pt4 = Point::new(0, 1);
674 let poly = RPolygon::new(&[pt1, pt2, pt3, pt4]);
675 assert!(poly.is_rectilinear());
676}
677
678#[test]
679fn test_rpolygon_from_origin_and_vectors() {
680 let origin = Point::new(0, 0);
681 let vecs = vec![Vector2::new(1, 0), Vector2::new(1, 1), Vector2::new(0, 1)];
682 let poly = RPolygon::from_origin_and_vectors(origin, vecs);
683 assert_eq!(poly.origin, Point::new(0, 0));
684 let vertices = poly.vertices();
685 assert_eq!(vertices.len(), 4);
686}
687
688#[test]
689fn test_rpolygon_from_pointset() {
690 let pointset = [Point::new(0, 0), Point::new(1, 0), Point::new(1, 1)];
691 let poly = RPolygon::from_pointset(&pointset);
692 assert_eq!(poly.origin, Point::new(0, 0));
693}
694
695#[test]
696fn test_rpolygon_partial_eq() {
697 let pt1 = Point::new(0, 0);
698 let pt2 = Point::new(1, 0);
699 let pt3 = Point::new(1, 1);
700 let poly1 = RPolygon::new(&[pt1, pt2, pt3]);
701 let poly2 = RPolygon::new(&[pt1, pt2, pt3]);
702 assert_eq!(poly1, poly2);
703
704 let poly3 = RPolygon::new(&[pt1, pt2, Point::new(0, 1)]);
705 assert_ne!(poly1, poly3);
706}
707
708#[test]
709fn test_rpolygon_is_anticlockwise_standalone() {
710 let pointset = [Point::new(0, 0), Point::new(1, 0), Point::new(1, 1)];
711 assert!(rpolygon_is_anticlockwise(&pointset));
712}
713
714#[test]
715fn test_rpolygon_default() {
716 let poly: RPolygon<i32> = RPolygon::default();
717 assert_eq!(poly.origin, Point::new(0, 0));
718}