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)]
22pub struct RPolygon<T> {
23 pub origin: Point<T, T>,
24 vecs: Vec<Vector2<T, T>>,
25}
26
27impl<T: Clone + Num + Copy + std::ops::AddAssign + Ord> RPolygon<T> {
28 pub fn new(coords: &[Point<T, T>]) -> Self {
42 let (&origin, coords) = coords.split_first().unwrap();
48 let vecs = coords.iter().map(|pt| *pt - origin).collect();
49 RPolygon { origin, vecs }
50 }
51
52 pub fn from_origin_and_vectors(origin: Point<T, T>, vecs: Vec<Vector2<T, T>>) -> Self {
59 RPolygon { origin, vecs }
60 }
61
62 pub fn from_pointset(pointset: &[Point<T, T>]) -> Self {
67 Self::new(pointset)
68 }
69
70 pub fn add_assign(&mut self, rhs: Vector2<T, T>)
72 where
73 T: AddAssign,
74 {
75 self.origin += rhs;
76 }
77
78 pub fn sub_assign(&mut self, rhs: Vector2<T, T>)
80 where
81 T: SubAssign,
82 {
83 self.origin -= rhs;
84 }
85
86 pub fn signed_area(&self) -> T {
92 let mut itr = self.vecs.iter();
95 let mut vec0 = itr.next().unwrap();
96 let mut res = vec0.x_ * vec0.y_;
97 for vec1 in itr {
98 res += vec1.x_ * (vec1.y_ - vec0.y_);
99 vec0 = vec1;
100 }
101 res
102 }
103
104 pub fn vertices(&self) -> Vec<Point<T, T>> {
106 let mut result = Vec::with_capacity(self.vecs.len() + 1);
107 result.push(self.origin);
108
109 for vec in &self.vecs {
110 result.push(self.origin + *vec);
111 }
112
113 result
114 }
115
116 pub fn bounding_box(&self) -> (Point<T, T>, Point<T, T>) {
118 let mut min_x = T::zero();
119 let mut min_y = T::zero();
120 let mut max_x = T::zero();
121 let mut max_y = T::zero();
122
123 for vec in &self.vecs {
124 if vec.x_ < min_x {
125 min_x = vec.x_;
126 }
127 if vec.y_ < min_y {
128 min_y = vec.y_;
129 }
130 if vec.x_ > max_x {
131 max_x = vec.x_;
132 }
133 if vec.y_ > max_y {
134 max_y = vec.y_;
135 }
136 }
137
138 (
139 Point::new(self.origin.xcoord + min_x, self.origin.ycoord + min_y),
140 Point::new(self.origin.xcoord + max_x, self.origin.ycoord + max_y),
141 )
142 }
143
144 pub fn is_rectilinear(&self) -> bool {
172 true
173 }
174
175 pub fn is_anticlockwise(&self) -> bool
177 where
178 T: PartialOrd,
179 {
180 let mut pointset = Vec::with_capacity(self.vecs.len() + 1);
181 pointset.push(Vector2::new(T::zero(), T::zero()));
182 pointset.extend(self.vecs.iter().cloned());
183
184 if pointset.len() < 2 {
185 panic!("Polygon must have at least 2 points");
186 }
187
188 let (min_index, _) = pointset
190 .iter()
191 .enumerate()
192 .min_by(|(_, a), (_, b)| {
193 a.x_.partial_cmp(&b.x_)
194 .unwrap_or(Ordering::Equal)
195 .then(a.y_.partial_cmp(&b.y_).unwrap_or(Ordering::Equal))
196 })
197 .unwrap();
198
199 let n = pointset.len();
201 let prev_point = pointset[(min_index + n - 1) % n];
202 let current_point = pointset[min_index];
203
204 prev_point.y_ > current_point.y_
205 }
206}
207
208impl<T: PartialEq> PartialEq for RPolygon<T> {
210 fn eq(&self, other: &Self) -> bool {
211 self.origin == other.origin && self.vecs == other.vecs
212 }
213}
214
215impl<T: Clone + Num + Ord + Copy> RPolygon<T> {
216 pub fn create_mono_rpolygon<F>(pointset: &[Point<T, T>], f: F) -> (Vec<Point<T, T>>, bool)
227 where
228 F: Fn(&Point<T, T>) -> (T, T),
229 {
230 let rightmost = pointset
232 .iter()
233 .max_by(|a, b| f(a).partial_cmp(&f(b)).unwrap())
234 .unwrap();
235 let leftmost = pointset
236 .iter()
237 .min_by(|a, b| f(a).partial_cmp(&f(b)).unwrap())
238 .unwrap();
239 let is_anticlockwise = f(rightmost).1 <= f(leftmost).1;
240 let (mut lst1, mut lst2): (Vec<Point<T, T>>, Vec<Point<T, T>>) = if is_anticlockwise {
241 pointset.iter().partition(|pt| (f(pt).1 <= f(leftmost).1))
242 } else {
243 pointset.iter().partition(|pt| (f(pt).1 >= f(leftmost).1))
244 };
245 lst1.sort_by_key(|a| f(a));
246 lst2.sort_by_key(|a| f(a));
247 lst2.reverse();
248 lst1.append(&mut lst2);
249 (lst1, is_anticlockwise) }
251
252 #[inline]
259 pub fn create_xmono_rpolygon(pointset: &[Point<T, T>]) -> (Vec<Point<T, T>>, bool) {
260 Self::create_mono_rpolygon(pointset, |a| (a.xcoord, a.ycoord))
261 }
262
263 #[inline]
271 pub fn create_ymono_rpolygon(pointset: &[Point<T, T>]) -> (Vec<Point<T, T>>, bool) {
272 Self::create_mono_rpolygon(pointset, |a| (a.ycoord, a.xcoord))
273 }
274
275 pub fn point_in_rpolygon(pointset: &[Point<T, T>], q: &Point<T, T>) -> bool {
301 let mut res = false;
302 let n = pointset.len();
303 let mut p0 = &pointset[n - 1];
304 for p1 in pointset.iter() {
305 if ((p1.ycoord <= q.ycoord && q.ycoord < p0.ycoord)
306 || (p0.ycoord <= q.ycoord && q.ycoord < p1.ycoord))
307 && p1.xcoord > q.xcoord
308 {
309 res = !res;
310 }
311 p0 = p1;
312 }
313 res
314 }
315}
316
317pub fn rpolygon_is_monotone<T, F>(lst: &[Point<T, T>], dir: F) -> bool
319where
320 T: Clone + Num + Ord + Copy + PartialOrd,
321 F: Fn(&Point<T, T>) -> (T, T),
322{
323 if lst.len() <= 3 {
324 return true;
325 }
326
327 let (min_index, _) = lst
328 .iter()
329 .enumerate()
330 .min_by_key(|(_, pt)| dir(pt))
331 .unwrap();
332
333 let (max_index, _) = lst
334 .iter()
335 .enumerate()
336 .max_by_key(|(_, pt)| dir(pt))
337 .unwrap();
338
339 let n = lst.len();
340
341 let mut i = min_index;
343 while i != max_index {
344 let next_i = (i + 1) % n;
345 if dir(&lst[i]).0 > dir(&lst[next_i]).0 {
346 return false;
347 }
348 i = next_i;
349 }
350
351 let mut i = max_index;
353 while i != min_index {
354 let next_i = (i + 1) % n;
355 if dir(&lst[i]).0 < dir(&lst[next_i]).0 {
356 return false;
357 }
358 i = next_i;
359 }
360
361 true
362}
363
364pub fn rpolygon_is_xmonotone<T>(lst: &[Point<T, T>]) -> bool
366where
367 T: Clone + Num + Ord + Copy + PartialOrd,
368{
369 rpolygon_is_monotone(lst, |pt| (pt.xcoord, pt.ycoord))
370}
371
372pub fn rpolygon_is_ymonotone<T>(lst: &[Point<T, T>]) -> bool
374where
375 T: Clone + Num + Ord + Copy + PartialOrd,
376{
377 rpolygon_is_monotone(lst, |pt| (pt.ycoord, pt.xcoord))
378}
379
380pub fn rpolygon_is_convex<T>(lst: &[Point<T, T>]) -> bool
382where
383 T: Clone + Num + Ord + Copy + PartialOrd,
384{
385 rpolygon_is_xmonotone(lst) && rpolygon_is_ymonotone(lst)
386}
387
388pub fn rpolygon_is_anticlockwise<T>(pointset: &[Point<T, T>]) -> bool
390where
391 T: Clone + Num + Ord + Copy + PartialOrd,
392{
393 if pointset.len() < 2 {
394 panic!("Polygon must have at least 2 points");
395 }
396
397 let (min_index, min_point) = pointset
399 .iter()
400 .enumerate()
401 .min_by(|(_, a), (_, b)| {
402 a.xcoord
403 .partial_cmp(&b.xcoord)
404 .unwrap_or(Ordering::Equal)
405 .then(a.ycoord.partial_cmp(&b.ycoord).unwrap_or(Ordering::Equal))
406 })
407 .unwrap();
408
409 let n = pointset.len();
411 let prev_index = (min_index + n - 1) % n;
412
413 let prev_point = pointset[prev_index];
414 let current_point = *min_point;
415
416 prev_point.ycoord() > current_point.ycoord()
417}
418
419#[cfg(test)]
420mod test {
421 #![allow(non_upper_case_globals)]
422
423 use super::*;
424
425 #[test]
426 pub fn test_ymono_rpolygon() {
427 let coords = [
428 (-2, 2),
429 (0, -1),
430 (-5, 1),
431 (-2, 4),
432 (0, -4),
433 (-4, 3),
434 (-6, -2),
435 (5, 1),
436 (2, 2),
437 (3, -3),
438 (-3, -4),
439 (1, 4),
440 ];
441 let mut pointset = vec![];
442 for (x, y) in coords.iter() {
443 pointset.push(Point::<i32, i32>::new(*x, *y));
444 }
445 let (pointset, is_cw) = RPolygon::<i32>::create_ymono_rpolygon(&pointset);
446 assert!(rpolygon_is_anticlockwise(&pointset));
447 assert!(rpolygon_is_ymonotone(&pointset));
448 assert!(!rpolygon_is_xmonotone(&pointset));
449 for p in pointset.iter() {
450 print!("({}, {}) ", p.xcoord, p.ycoord);
451 }
452 let poly = RPolygon::<i32>::new(&pointset);
453 assert!(!is_cw);
454 assert_eq!(poly.signed_area(), 45);
455 }
456
457 #[test]
458 pub fn test_xmono_rpolygon() {
459 let coords = [
460 (-2, 2),
461 (0, -1),
462 (-5, 1),
463 (-2, 4),
464 (0, -4),
465 (-4, 3),
466 (-6, -2),
467 (5, 1),
468 (2, 2),
469 (3, -3),
470 (-3, -4),
471 (1, 4),
472 ];
473 let mut pointset = vec![];
474 for (x, y) in coords.iter() {
475 pointset.push(Point::<i32, i32>::new(*x, *y));
476 }
477 let (pointset, is_anticw) = RPolygon::<i32>::create_xmono_rpolygon(&pointset);
478 assert!(!rpolygon_is_anticlockwise(&pointset));
479 assert!(rpolygon_is_xmonotone(&pointset));
480 assert!(!rpolygon_is_ymonotone(&pointset));
481 for p in pointset.iter() {
482 print!("({}, {}) ", p.xcoord, p.ycoord);
483 }
484 let poly = RPolygon::<i32>::new(&pointset);
485 assert!(!is_anticw);
486 assert_eq!(poly.signed_area(), -53);
487 assert!(!poly.is_anticlockwise())
488 }
489
490 #[test]
491 pub fn test_point_in_rpolygon() {
492 let coords = [
493 (-2, 2),
494 (0, -1),
495 (-5, 1),
496 (-2, 4),
497 (0, -4),
498 (-4, 3),
499 (-6, -2),
500 (5, 1),
501 (2, 2),
502 (3, -3),
503 (-3, -4),
504 (1, 4),
505 ];
506 let mut pointset = vec![];
507 for (x, y) in coords.iter() {
508 pointset.push(Point::<i32, i32>::new(*x, *y));
509 }
510 let q = Point::<i32, i32>::new(0, -3);
511 assert!(!RPolygon::<i32>::point_in_rpolygon(&pointset, &q));
513 }
514
515 #[test]
516 fn test_signed_area_more_cases() {
517 let p1 = Point::new(0, 0);
518 let p2 = Point::new(1, 0);
519 let p3 = Point::new(1, 1);
520 let p4 = Point::new(0, 1);
521 let poly = RPolygon::new(&[p1, p2, p3, p4]);
522 assert_eq!(poly.signed_area(), 1);
523
524 let p5 = Point::new(0, 0);
525 let p6 = Point::new(0, 1);
526 let p7 = Point::new(1, 1);
527 let p8 = Point::new(1, 0);
528 let poly2 = RPolygon::new(&[p5, p6, p7, p8]);
529 assert_eq!(poly2.signed_area(), -1);
530 }
531
532 #[test]
533 fn test_point_in_rpolygon_more_cases() {
534 let p1 = Point::new(0, 0);
535 let p2 = Point::new(1, 0);
536 let p3 = Point::new(1, 1);
537 let p4 = Point::new(0, 1);
538 let pointset = &[p1, p2, p3, p4];
539
540 let q1 = Point::new(0, 0);
541 assert!(RPolygon::<i32>::point_in_rpolygon(pointset, &q1));
542
543 let q2 = Point::new(1, 1);
544 assert!(!RPolygon::<i32>::point_in_rpolygon(pointset, &q2));
545
546 let q3 = Point::new(0, 1);
547 assert!(!RPolygon::<i32>::point_in_rpolygon(pointset, &q3));
548
549 let q4 = Point::new(1, 0);
550 assert!(!RPolygon::<i32>::point_in_rpolygon(pointset, &q4));
551 }
552}