1use core::cmp::{max, min};
2
3use ironrdp_pdu::geometry::{InclusiveRectangle, Rectangle as _};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Region {
10 pub extents: InclusiveRectangle,
11 pub rectangles: Vec<InclusiveRectangle>,
12}
13
14impl Region {
15 pub fn new() -> Self {
16 Self {
17 extents: InclusiveRectangle::empty(),
18 rectangles: Vec::new(),
19 }
20 }
21
22 pub fn union_rectangle(&mut self, rectangle: InclusiveRectangle) {
23 if self.rectangles.is_empty() {
24 *self = Self::from(rectangle);
25 } else {
26 let mut dst = Vec::with_capacity(self.rectangles.len() + 1);
27
28 handle_rectangle_higher_relative_to_extents(&rectangle, &self.extents, &mut dst);
29
30 let bands = split_bands(self.rectangles.as_slice());
32 let mut bands = bands.as_slice();
33 while let Some((band, bands_new)) = bands.split_first() {
34 bands = bands_new;
35
36 let top_inter_band = if band[0].bottom <= rectangle.top
37 || rectangle.bottom <= band[0].top
38 || rectangle_in_band(band, &rectangle)
39 {
40 dst.extend_from_slice(band);
42
43 rectangle.top
44 } else {
45 handle_rectangle_that_overlaps_band(&rectangle, band, &mut dst);
46
47 band[0].bottom
48 };
49
50 if !bands.is_empty() {
51 let next_band = bands[0];
52 handle_rectangle_between_bands(&rectangle, band, next_band, &mut dst, top_inter_band);
53 }
54 }
55
56 handle_rectangle_lower_relative_to_extents(&rectangle, &self.extents, &mut dst);
57
58 self.rectangles = dst;
59 self.extents = self.extents.union(&rectangle);
60
61 self.simplify();
62 }
63 }
64
65 #[must_use]
66 pub fn intersect_rectangle(&self, rectangle: &InclusiveRectangle) -> Self {
67 match self.rectangles.len() {
68 0 => Self::new(),
69 1 => self.extents.intersect(rectangle).map(Self::from).unwrap_or_default(),
70 _ => {
71 let rectangles = self
72 .rectangles
73 .iter()
74 .take_while(|r| r.top <= rectangle.bottom)
75 .filter_map(|r| r.intersect(rectangle))
76 .collect::<Vec<_>>();
77 let extents = InclusiveRectangle::union_all(rectangles.as_slice());
78
79 let mut region = Self { rectangles, extents };
80 region.simplify();
81
82 region
83 }
84 }
85 }
86
87 fn simplify(&mut self) {
88 if self.rectangles.len() < 2 {
101 return;
102 }
103
104 let mut current_band_start = 0;
105 while current_band_start < self.rectangles.len()
106 && current_band_start + get_current_band(&self.rectangles[current_band_start..]).len()
107 < self.rectangles.len()
108 {
109 let current_band = get_current_band(&self.rectangles[current_band_start..]);
110 let next_band = get_current_band(&self.rectangles[current_band_start + current_band.len()..]);
111
112 if current_band[0].bottom == next_band[0].top && bands_internals_equal(current_band, next_band) {
113 let first_band_len = current_band.len();
114 let second_band_len = next_band.len();
115 let second_band_bottom = next_band[0].bottom;
116 self.rectangles
117 .drain(current_band_start + first_band_len..current_band_start + first_band_len + second_band_len);
118 self.rectangles
119 .iter_mut()
120 .skip(current_band_start)
121 .take(first_band_len)
122 .for_each(|r| r.bottom = second_band_bottom);
123 } else {
124 current_band_start += current_band.len();
125 }
126 }
127 }
128}
129
130impl Default for Region {
131 fn default() -> Self {
132 Self::new()
133 }
134}
135
136impl From<InclusiveRectangle> for Region {
137 fn from(r: InclusiveRectangle) -> Self {
138 Self {
139 extents: r.clone(),
140 rectangles: vec![r],
141 }
142 }
143}
144
145fn handle_rectangle_higher_relative_to_extents(
146 rectangle: &InclusiveRectangle,
147 extents: &InclusiveRectangle,
148 dst: &mut Vec<InclusiveRectangle>,
149) {
150 if rectangle.top < extents.top {
151 dst.push(InclusiveRectangle {
152 top: rectangle.top,
153 bottom: min(extents.top, rectangle.bottom),
154 left: rectangle.left,
155 right: rectangle.right,
156 });
157 }
158}
159
160fn handle_rectangle_lower_relative_to_extents(
161 rectangle: &InclusiveRectangle,
162 extents: &InclusiveRectangle,
163 dst: &mut Vec<InclusiveRectangle>,
164) {
165 if extents.bottom < rectangle.bottom {
166 dst.push(InclusiveRectangle {
167 top: max(extents.bottom, rectangle.top),
168 bottom: rectangle.bottom,
169 left: rectangle.left,
170 right: rectangle.right,
171 });
172 }
173}
174
175fn handle_rectangle_that_overlaps_band(
176 rectangle: &InclusiveRectangle,
177 band: &[InclusiveRectangle],
178 dst: &mut Vec<InclusiveRectangle>,
179) {
180 let band_top = band[0].top;
204 let band_bottom = band[0].bottom;
205
206 if band_top < rectangle.top {
207 copy_band(band, dst, band_top, rectangle.top);
209 }
210
211 copy_band_with_union(
213 band,
214 dst,
215 max(rectangle.top, band_top),
216 min(rectangle.bottom, band_bottom),
217 rectangle,
218 );
219
220 if rectangle.bottom < band_bottom {
222 copy_band(band, dst, rectangle.bottom, band_bottom);
223 }
224}
225
226fn handle_rectangle_between_bands(
227 rectangle: &InclusiveRectangle,
228 band: &[InclusiveRectangle],
229 next_band: &[InclusiveRectangle],
230 dst: &mut Vec<InclusiveRectangle>,
231 top_inter_band: u16,
232) {
233 let band_bottom = band[0].bottom;
250
251 let next_band_top = next_band[0].top;
252 if next_band_top != band_bottom && band_bottom < rectangle.bottom && rectangle.top < next_band_top {
253 dst.push(InclusiveRectangle {
254 top: top_inter_band,
255 bottom: min(next_band_top, rectangle.bottom),
256 left: rectangle.left,
257 right: rectangle.right,
258 });
259 }
260}
261
262fn rectangle_in_band(band: &[InclusiveRectangle], rectangle: &InclusiveRectangle) -> bool {
263 if rectangle.top < band[0].top || band[0].bottom < rectangle.bottom {
265 return false;
266 }
267
268 for source_rectangle in band {
269 if source_rectangle.left <= rectangle.left {
270 if rectangle.right <= source_rectangle.right {
271 return true;
272 }
273 } else {
274 return false;
278 }
279 }
280
281 false
282}
283
284fn copy_band_with_union(
285 mut band: &[InclusiveRectangle],
286 dst: &mut Vec<InclusiveRectangle>,
287 band_top: u16,
288 band_bottom: u16,
289 union_rectangle: &InclusiveRectangle,
290) {
291 let items_before_union_rectangle = band
316 .iter()
317 .map(|r| InclusiveRectangle {
318 top: band_top,
319 bottom: band_bottom,
320 left: r.left,
321 right: r.right,
322 })
323 .take_while(|r| r.right < union_rectangle.left);
324 let items_before_union_rectangle_len = items_before_union_rectangle.clone().map(|_| 1).sum::<usize>();
325 dst.extend(items_before_union_rectangle);
326 band = &band[items_before_union_rectangle_len..];
327
328 let left = min(
330 band.first().map(|r| r.left).unwrap_or(union_rectangle.left),
331 union_rectangle.left,
332 );
333 let mut right = union_rectangle.right;
334 while !band.is_empty() {
335 if band[0].right >= union_rectangle.right {
336 if band[0].left < union_rectangle.right {
337 right = band[0].right;
338 band = &band[1..];
339 }
340 break;
341 }
342 band = &band[1..];
343 }
344 dst.push(InclusiveRectangle {
345 top: band_top,
346 bottom: band_bottom,
347 left,
348 right,
349 });
350
351 copy_band(band, dst, band_top, band_bottom);
353}
354
355fn copy_band(band: &[InclusiveRectangle], dst: &mut Vec<InclusiveRectangle>, band_top: u16, band_bottom: u16) {
356 dst.extend(band.iter().map(|r| InclusiveRectangle {
357 top: band_top,
358 bottom: band_bottom,
359 left: r.left,
360 right: r.right,
361 }));
362}
363
364fn split_bands(mut rectangles: &[InclusiveRectangle]) -> Vec<&[InclusiveRectangle]> {
365 let mut bands = Vec::new();
366 while !rectangles.is_empty() {
367 let band = get_current_band(rectangles);
368 rectangles = &rectangles[band.len()..];
369 bands.push(band);
370 }
371
372 bands
373}
374
375fn get_current_band(rectangles: &[InclusiveRectangle]) -> &[InclusiveRectangle] {
376 let band_top = rectangles[0].top;
377
378 for i in 1..rectangles.len() {
379 if rectangles[i].top != band_top {
380 return &rectangles[..i];
381 }
382 }
383
384 rectangles
385}
386
387fn bands_internals_equal(first_band: &[InclusiveRectangle], second_band: &[InclusiveRectangle]) -> bool {
388 if first_band.len() != second_band.len() {
389 return false;
390 }
391
392 for (first_band_rect, second_band_rect) in first_band.iter().zip(second_band.iter()) {
393 if first_band_rect.left != second_band_rect.left || first_band_rect.right != second_band_rect.right {
394 return false;
395 }
396 }
397
398 true
399}
400
401#[cfg(test)]
402mod tests {
403 use std::sync::LazyLock;
404
405 use super::*;
406
407 static REGION_FOR_RECTANGLES_INTERSECTION: LazyLock<Region> = LazyLock::new(|| Region {
408 extents: InclusiveRectangle {
409 left: 1,
410 top: 1,
411 right: 11,
412 bottom: 9,
413 },
414 rectangles: vec![
415 InclusiveRectangle {
416 left: 1,
417 top: 1,
418 right: 5,
419 bottom: 3,
420 },
421 InclusiveRectangle {
422 left: 7,
423 top: 1,
424 right: 8,
425 bottom: 3,
426 },
427 InclusiveRectangle {
428 left: 9,
429 top: 1,
430 right: 11,
431 bottom: 3,
432 },
433 InclusiveRectangle {
434 left: 7,
435 top: 3,
436 right: 11,
437 bottom: 4,
438 },
439 InclusiveRectangle {
440 left: 3,
441 top: 4,
442 right: 6,
443 bottom: 6,
444 },
445 InclusiveRectangle {
446 left: 7,
447 top: 4,
448 right: 11,
449 bottom: 6,
450 },
451 InclusiveRectangle {
452 left: 1,
453 top: 6,
454 right: 3,
455 bottom: 8,
456 },
457 InclusiveRectangle {
458 left: 4,
459 top: 6,
460 right: 5,
461 bottom: 8,
462 },
463 InclusiveRectangle {
464 left: 6,
465 top: 6,
466 right: 10,
467 bottom: 8,
468 },
469 InclusiveRectangle {
470 left: 4,
471 top: 8,
472 right: 5,
473 bottom: 9,
474 },
475 InclusiveRectangle {
476 left: 6,
477 top: 8,
478 right: 10,
479 bottom: 9,
480 },
481 ],
482 });
483
484 #[test]
485 fn union_rectangle_sets_extents_and_single_rectangle_for_empty_region() {
486 let mut region = Region::new();
487
488 let input_rectangle = InclusiveRectangle {
489 left: 5,
490 top: 1,
491 right: 9,
492 bottom: 2,
493 };
494
495 let expected_region = Region {
496 extents: input_rectangle.clone(),
497 rectangles: vec![input_rectangle.clone()],
498 };
499
500 region.union_rectangle(input_rectangle);
501 assert_eq!(expected_region, region);
502 }
503
504 #[test]
505 fn union_rectangle_places_new_rectangle_higher_relative_to_band() {
506 let existing_band_rectangle = InclusiveRectangle {
507 left: 2,
508 top: 3,
509 right: 7,
510 bottom: 7,
511 };
512 let mut region = Region {
513 extents: existing_band_rectangle.clone(),
514 rectangles: vec![existing_band_rectangle.clone()],
515 };
516
517 let input_rectangle = InclusiveRectangle {
518 left: 5,
519 top: 1,
520 right: 9,
521 bottom: 2,
522 };
523
524 let expected_region = Region {
525 extents: InclusiveRectangle {
526 left: 2,
527 top: 1,
528 right: 9,
529 bottom: 7,
530 },
531 rectangles: vec![input_rectangle.clone(), existing_band_rectangle],
532 };
533
534 region.union_rectangle(input_rectangle);
535 assert_eq!(expected_region, region);
536 }
537
538 #[test]
539 fn union_rectangle_places_new_rectangle_lower_relative_to_band() {
540 let existing_band_rectangle = InclusiveRectangle {
541 left: 2,
542 top: 3,
543 right: 7,
544 bottom: 7,
545 };
546 let mut region = Region {
547 extents: existing_band_rectangle.clone(),
548 rectangles: vec![existing_band_rectangle.clone()],
549 };
550
551 let input_rectangle = InclusiveRectangle {
552 left: 1,
553 top: 8,
554 right: 4,
555 bottom: 10,
556 };
557
558 let expected_region = Region {
559 extents: InclusiveRectangle {
560 left: 1,
561 top: 3,
562 right: 7,
563 bottom: 10,
564 },
565 rectangles: vec![existing_band_rectangle, input_rectangle.clone()],
566 };
567
568 region.union_rectangle(input_rectangle);
569 assert_eq!(expected_region, region);
570 }
571
572 #[test]
573 fn union_rectangle_does_not_add_new_rectangle_which_is_inside_a_band() {
574 let existing_band_rectangle = InclusiveRectangle {
575 left: 2,
576 top: 3,
577 right: 7,
578 bottom: 7,
579 };
580 let mut region = Region {
581 extents: existing_band_rectangle.clone(),
582 rectangles: vec![existing_band_rectangle.clone()],
583 };
584
585 let input_rectangle = InclusiveRectangle {
586 left: 5,
587 top: 4,
588 right: 6,
589 bottom: 5,
590 };
591
592 let expected_region = Region {
593 extents: existing_band_rectangle.clone(),
594 rectangles: vec![existing_band_rectangle],
595 };
596
597 region.union_rectangle(input_rectangle);
598 assert_eq!(expected_region, region);
599 }
600
601 #[test]
602 fn union_rectangle_cuts_new_rectangle_top_part_which_crosses_band_on_top() {
603 let existing_band_rectangle = InclusiveRectangle {
604 left: 2,
605 top: 3,
606 right: 7,
607 bottom: 7,
608 };
609 let mut region = Region {
610 extents: existing_band_rectangle.clone(),
611 rectangles: vec![existing_band_rectangle],
612 };
613
614 let input_rectangle = InclusiveRectangle {
615 left: 1,
616 top: 2,
617 right: 4,
618 bottom: 4,
619 };
620
621 let expected_region = Region {
622 extents: InclusiveRectangle {
623 left: 1,
624 top: 2,
625 right: 7,
626 bottom: 7,
627 },
628 rectangles: vec![
629 InclusiveRectangle {
630 left: 1,
631 top: 2,
632 right: 4,
633 bottom: 3,
634 },
635 InclusiveRectangle {
636 left: 1,
637 top: 3,
638 right: 7,
639 bottom: 4,
640 },
641 InclusiveRectangle {
642 left: 2,
643 top: 4,
644 right: 7,
645 bottom: 7,
646 },
647 ],
648 };
649
650 region.union_rectangle(input_rectangle);
651 assert_eq!(expected_region, region);
652 }
653
654 #[test]
655 fn union_rectangle_cuts_new_rectangle_lower_part_which_crosses_band_on_bottom() {
656 let existing_band_rectangle = InclusiveRectangle {
657 left: 2,
658 top: 3,
659 right: 7,
660 bottom: 7,
661 };
662 let mut region = Region {
663 extents: existing_band_rectangle.clone(),
664 rectangles: vec![existing_band_rectangle],
665 };
666
667 let input_rectangle = InclusiveRectangle {
668 left: 5,
669 top: 6,
670 right: 9,
671 bottom: 8,
672 };
673
674 let expected_region = Region {
675 extents: InclusiveRectangle {
676 left: 2,
677 top: 3,
678 right: 9,
679 bottom: 8,
680 },
681 rectangles: vec![
682 InclusiveRectangle {
683 left: 2,
684 top: 3,
685 right: 7,
686 bottom: 6,
687 },
688 InclusiveRectangle {
689 left: 2,
690 top: 6,
691 right: 9,
692 bottom: 7,
693 },
694 InclusiveRectangle {
695 left: 5,
696 top: 7,
697 right: 9,
698 bottom: 8,
699 },
700 ],
701 };
702
703 region.union_rectangle(input_rectangle);
704 assert_eq!(expected_region, region);
705 }
706
707 #[test]
708 fn union_rectangle_cuts_new_rectangle_higher_and_lower_part_which_crosses_band_on_top_and_bottom() {
709 let existing_band_rectangle = InclusiveRectangle {
710 left: 2,
711 top: 3,
712 right: 7,
713 bottom: 7,
714 };
715 let mut region = Region {
716 extents: existing_band_rectangle.clone(),
717 rectangles: vec![existing_band_rectangle],
718 };
719
720 let input_rectangle = InclusiveRectangle {
721 left: 3,
722 top: 1,
723 right: 5,
724 bottom: 11,
725 };
726
727 let expected_region = Region {
728 extents: InclusiveRectangle {
729 left: 2,
730 top: 1,
731 right: 7,
732 bottom: 11,
733 },
734 rectangles: vec![
735 InclusiveRectangle {
736 left: 3,
737 top: 1,
738 right: 5,
739 bottom: 3,
740 },
741 InclusiveRectangle {
742 left: 2,
743 top: 3,
744 right: 7,
745 bottom: 7,
746 },
747 InclusiveRectangle {
748 left: 3,
749 top: 7,
750 right: 5,
751 bottom: 11,
752 },
753 ],
754 };
755
756 region.union_rectangle(input_rectangle);
757 assert_eq!(expected_region, region);
758 }
759
760 #[test]
761 fn union_rectangle_inserts_new_rectangle_in_band_of_3_rectangles_without_merging_with_rectangles() {
762 let mut region = Region {
763 extents: InclusiveRectangle {
764 left: 2,
765 top: 3,
766 right: 15,
767 bottom: 7,
768 },
769 rectangles: vec![
770 InclusiveRectangle {
771 left: 2,
772 top: 3,
773 right: 7,
774 bottom: 7,
775 },
776 InclusiveRectangle {
777 left: 8,
778 top: 3,
779 right: 9,
780 bottom: 7,
781 },
782 InclusiveRectangle {
783 left: 12,
784 top: 3,
785 right: 15,
786 bottom: 7,
787 },
788 ],
789 };
790
791 let input_rectangle = InclusiveRectangle {
792 left: 10,
793 top: 3,
794 right: 11,
795 bottom: 7,
796 };
797 let expected_region = Region {
798 extents: InclusiveRectangle {
799 left: 2,
800 top: 3,
801 right: 15,
802 bottom: 7,
803 },
804 rectangles: vec![
805 InclusiveRectangle {
806 left: 2,
807 top: 3,
808 right: 7,
809 bottom: 7,
810 },
811 InclusiveRectangle {
812 left: 8,
813 top: 3,
814 right: 9,
815 bottom: 7,
816 },
817 InclusiveRectangle {
818 left: 10,
819 top: 3,
820 right: 11,
821 bottom: 7,
822 },
823 InclusiveRectangle {
824 left: 12,
825 top: 3,
826 right: 15,
827 bottom: 7,
828 },
829 ],
830 };
831
832 region.union_rectangle(input_rectangle);
833 assert_eq!(expected_region, region);
834 }
835
836 #[test]
837 fn union_rectangle_inserts_new_rectangle_in_band_of_3_rectangles_with_merging_with_side_rectangles() {
838 let mut region = Region {
839 extents: InclusiveRectangle {
840 left: 2,
841 top: 3,
842 right: 15,
843 bottom: 7,
844 },
845 rectangles: vec![
846 InclusiveRectangle {
847 left: 2,
848 top: 3,
849 right: 7,
850 bottom: 7,
851 },
852 InclusiveRectangle {
853 left: 8,
854 top: 3,
855 right: 10,
856 bottom: 7,
857 },
858 InclusiveRectangle {
859 left: 13,
860 top: 3,
861 right: 15,
862 bottom: 7,
863 },
864 ],
865 };
866
867 let input_rectangle = InclusiveRectangle {
868 left: 9,
869 top: 3,
870 right: 14,
871 bottom: 7,
872 };
873 let expected_region = Region {
874 extents: InclusiveRectangle {
875 left: 2,
876 top: 3,
877 right: 15,
878 bottom: 7,
879 },
880 rectangles: vec![
881 InclusiveRectangle {
882 left: 2,
883 top: 3,
884 right: 7,
885 bottom: 7,
886 },
887 InclusiveRectangle {
888 left: 8,
889 top: 3,
890 right: 15,
891 bottom: 7,
892 },
893 ],
894 };
895
896 region.union_rectangle(input_rectangle);
897 assert_eq!(expected_region, region);
898 }
899
900 #[test]
901 fn union_rectangle_inserts_new_rectangle_in_band_of_3_rectangles_with_merging_with_side_rectangles_on_board() {
902 let mut region = Region {
903 extents: InclusiveRectangle {
904 left: 2,
905 top: 3,
906 right: 15,
907 bottom: 7,
908 },
909 rectangles: vec![
910 InclusiveRectangle {
911 left: 2,
912 top: 3,
913 right: 7,
914 bottom: 7,
915 },
916 InclusiveRectangle {
917 left: 8,
918 top: 3,
919 right: 10,
920 bottom: 7,
921 },
922 InclusiveRectangle {
923 left: 13,
924 top: 3,
925 right: 15,
926 bottom: 7,
927 },
928 ],
929 };
930
931 let input_rectangle = InclusiveRectangle {
932 left: 10,
933 top: 3,
934 right: 13,
935 bottom: 7,
936 };
937 let expected_region = Region {
938 extents: InclusiveRectangle {
939 left: 2,
940 top: 3,
941 right: 15,
942 bottom: 7,
943 },
944 rectangles: vec![
945 InclusiveRectangle {
946 left: 2,
947 top: 3,
948 right: 7,
949 bottom: 7,
950 },
951 InclusiveRectangle {
952 left: 8,
953 top: 3,
954 right: 13,
955 bottom: 7,
956 },
957 InclusiveRectangle {
958 left: 13,
959 top: 3,
960 right: 15,
961 bottom: 7,
962 },
963 ],
964 };
965
966 region.union_rectangle(input_rectangle);
967 assert_eq!(expected_region, region);
968 }
969
970 #[test]
971 fn union_rectangle_inserts_new_rectangle_between_two_bands() {
972 let mut region = Region {
973 extents: InclusiveRectangle {
974 left: 1,
975 top: 3,
976 right: 7,
977 bottom: 10,
978 },
979 rectangles: vec![
980 InclusiveRectangle {
981 left: 2,
982 top: 3,
983 right: 7,
984 bottom: 7,
985 },
986 InclusiveRectangle {
987 left: 1,
988 top: 8,
989 right: 4,
990 bottom: 10,
991 },
992 ],
993 };
994
995 let input_rectangle = InclusiveRectangle {
996 left: 3,
997 top: 4,
998 right: 4,
999 bottom: 9,
1000 };
1001 let expected_region = Region {
1002 extents: InclusiveRectangle {
1003 left: 1,
1004 top: 3,
1005 right: 7,
1006 bottom: 10,
1007 },
1008 rectangles: vec![
1009 InclusiveRectangle {
1010 left: 2,
1011 top: 3,
1012 right: 7,
1013 bottom: 7,
1014 },
1015 InclusiveRectangle {
1016 left: 3,
1017 top: 7,
1018 right: 4,
1019 bottom: 8,
1020 },
1021 InclusiveRectangle {
1022 left: 1,
1023 top: 8,
1024 right: 4,
1025 bottom: 10,
1026 },
1027 ],
1028 };
1029
1030 region.union_rectangle(input_rectangle);
1031 assert_eq!(expected_region, region);
1032 }
1033
1034 #[test]
1035 fn simplify_does_not_change_two_different_bands_with_multiple_rectangles() {
1036 let mut region = Region {
1037 extents: InclusiveRectangle {
1038 left: 1,
1039 top: 1,
1040 right: 7,
1041 bottom: 3,
1042 },
1043 rectangles: vec![
1044 InclusiveRectangle {
1045 left: 1,
1046 top: 1,
1047 right: 2,
1048 bottom: 2,
1049 },
1050 InclusiveRectangle {
1051 left: 3,
1052 top: 1,
1053 right: 4,
1054 bottom: 2,
1055 },
1056 InclusiveRectangle {
1057 left: 5,
1058 top: 1,
1059 right: 6,
1060 bottom: 2,
1061 },
1062 InclusiveRectangle {
1063 left: 1,
1064 top: 2,
1065 right: 2,
1066 bottom: 3,
1067 },
1068 InclusiveRectangle {
1069 left: 3,
1070 top: 2,
1071 right: 4,
1072 bottom: 3,
1073 },
1074 InclusiveRectangle {
1075 left: 5,
1076 top: 2,
1077 right: 7,
1078 bottom: 3,
1079 },
1080 ],
1081 };
1082 let expected_region = region.clone();
1083
1084 region.simplify();
1085 assert_eq!(expected_region, region);
1086 }
1087
1088 #[test]
1089 fn simplify_does_not_change_two_different_bands_with_one_rectangle() {
1090 let mut region = Region {
1091 extents: InclusiveRectangle {
1092 left: 2,
1093 top: 1,
1094 right: 7,
1095 bottom: 11,
1096 },
1097 rectangles: vec![
1098 InclusiveRectangle {
1099 left: 3,
1100 top: 1,
1101 right: 5,
1102 bottom: 3,
1103 },
1104 InclusiveRectangle {
1105 left: 2,
1106 top: 3,
1107 right: 7,
1108 bottom: 7,
1109 },
1110 ],
1111 };
1112 let expected_region = region.clone();
1113
1114 region.simplify();
1115 assert_eq!(expected_region, region);
1116 }
1117
1118 #[test]
1119 fn simplify_does_not_change_three_different_bands_with_one_rectangle() {
1120 let mut region = Region {
1121 extents: InclusiveRectangle {
1122 left: 2,
1123 top: 1,
1124 right: 7,
1125 bottom: 11,
1126 },
1127 rectangles: vec![
1128 InclusiveRectangle {
1129 left: 3,
1130 top: 1,
1131 right: 5,
1132 bottom: 3,
1133 },
1134 InclusiveRectangle {
1135 left: 2,
1136 top: 3,
1137 right: 7,
1138 bottom: 7,
1139 },
1140 InclusiveRectangle {
1141 left: 3,
1142 top: 7,
1143 right: 5,
1144 bottom: 11,
1145 },
1146 ],
1147 };
1148 let expected_region = region.clone();
1149
1150 region.simplify();
1151 assert_eq!(expected_region, region);
1152 }
1153
1154 #[test]
1155 fn simplify_merges_bands_with_identical_internal_rectangles() {
1156 let mut region = Region {
1157 extents: InclusiveRectangle {
1158 left: 1,
1159 top: 1,
1160 right: 7,
1161 bottom: 3,
1162 },
1163 rectangles: vec![
1164 InclusiveRectangle {
1165 left: 1,
1166 top: 1,
1167 right: 2,
1168 bottom: 2,
1169 },
1170 InclusiveRectangle {
1171 left: 3,
1172 top: 1,
1173 right: 4,
1174 bottom: 2,
1175 },
1176 InclusiveRectangle {
1177 left: 5,
1178 top: 1,
1179 right: 6,
1180 bottom: 2,
1181 },
1182 InclusiveRectangle {
1183 left: 1,
1184 top: 2,
1185 right: 2,
1186 bottom: 3,
1187 },
1188 InclusiveRectangle {
1189 left: 3,
1190 top: 2,
1191 right: 4,
1192 bottom: 3,
1193 },
1194 InclusiveRectangle {
1195 left: 5,
1196 top: 2,
1197 right: 6,
1198 bottom: 3,
1199 },
1200 ],
1201 };
1202 let expected_region = Region {
1203 extents: InclusiveRectangle {
1204 left: 1,
1205 top: 1,
1206 right: 7,
1207 bottom: 3,
1208 },
1209 rectangles: vec![
1210 InclusiveRectangle {
1211 left: 1,
1212 top: 1,
1213 right: 2,
1214 bottom: 3,
1215 },
1216 InclusiveRectangle {
1217 left: 3,
1218 top: 1,
1219 right: 4,
1220 bottom: 3,
1221 },
1222 InclusiveRectangle {
1223 left: 5,
1224 top: 1,
1225 right: 6,
1226 bottom: 3,
1227 },
1228 ],
1229 };
1230
1231 region.simplify();
1232 assert_eq!(expected_region, region);
1233 }
1234
1235 #[test]
1236 fn simplify_merges_three_bands_with_identical_internal_rectangles() {
1237 let mut region = Region {
1238 extents: InclusiveRectangle {
1239 left: 1,
1240 top: 1,
1241 right: 7,
1242 bottom: 3,
1243 },
1244 rectangles: vec![
1245 InclusiveRectangle {
1246 left: 1,
1247 top: 1,
1248 right: 2,
1249 bottom: 2,
1250 },
1251 InclusiveRectangle {
1252 left: 3,
1253 top: 1,
1254 right: 4,
1255 bottom: 2,
1256 },
1257 InclusiveRectangle {
1258 left: 5,
1259 top: 1,
1260 right: 6,
1261 bottom: 2,
1262 },
1263 InclusiveRectangle {
1264 left: 1,
1265 top: 2,
1266 right: 2,
1267 bottom: 3,
1268 },
1269 InclusiveRectangle {
1270 left: 3,
1271 top: 2,
1272 right: 4,
1273 bottom: 3,
1274 },
1275 InclusiveRectangle {
1276 left: 5,
1277 top: 2,
1278 right: 6,
1279 bottom: 3,
1280 },
1281 InclusiveRectangle {
1282 left: 1,
1283 top: 3,
1284 right: 2,
1285 bottom: 4,
1286 },
1287 InclusiveRectangle {
1288 left: 3,
1289 top: 3,
1290 right: 4,
1291 bottom: 4,
1292 },
1293 InclusiveRectangle {
1294 left: 5,
1295 top: 3,
1296 right: 6,
1297 bottom: 4,
1298 },
1299 ],
1300 };
1301 let expected_region = Region {
1302 extents: InclusiveRectangle {
1303 left: 1,
1304 top: 1,
1305 right: 7,
1306 bottom: 3,
1307 },
1308 rectangles: vec![
1309 InclusiveRectangle {
1310 left: 1,
1311 top: 1,
1312 right: 2,
1313 bottom: 4,
1314 },
1315 InclusiveRectangle {
1316 left: 3,
1317 top: 1,
1318 right: 4,
1319 bottom: 4,
1320 },
1321 InclusiveRectangle {
1322 left: 5,
1323 top: 1,
1324 right: 6,
1325 bottom: 4,
1326 },
1327 ],
1328 };
1329
1330 region.simplify();
1331 assert_eq!(expected_region, region);
1332 }
1333
1334 #[test]
1335 fn simplify_merges_two_pairs_of_bands_with_identical_internal_rectangles() {
1336 let mut region = Region {
1337 extents: InclusiveRectangle {
1338 left: 1,
1339 top: 1,
1340 right: 7,
1341 bottom: 5,
1342 },
1343 rectangles: vec![
1344 InclusiveRectangle {
1345 left: 1,
1346 top: 1,
1347 right: 2,
1348 bottom: 2,
1349 },
1350 InclusiveRectangle {
1351 left: 3,
1352 top: 1,
1353 right: 4,
1354 bottom: 2,
1355 },
1356 InclusiveRectangle {
1357 left: 5,
1358 top: 1,
1359 right: 6,
1360 bottom: 2,
1361 },
1362 InclusiveRectangle {
1363 left: 1,
1364 top: 2,
1365 right: 2,
1366 bottom: 3,
1367 },
1368 InclusiveRectangle {
1369 left: 3,
1370 top: 2,
1371 right: 4,
1372 bottom: 3,
1373 },
1374 InclusiveRectangle {
1375 left: 5,
1376 top: 2,
1377 right: 6,
1378 bottom: 3,
1379 },
1380 InclusiveRectangle {
1381 left: 2,
1382 top: 3,
1383 right: 3,
1384 bottom: 4,
1385 },
1386 InclusiveRectangle {
1387 left: 4,
1388 top: 3,
1389 right: 5,
1390 bottom: 4,
1391 },
1392 InclusiveRectangle {
1393 left: 6,
1394 top: 3,
1395 right: 7,
1396 bottom: 4,
1397 },
1398 InclusiveRectangle {
1399 left: 2,
1400 top: 4,
1401 right: 3,
1402 bottom: 5,
1403 },
1404 InclusiveRectangle {
1405 left: 4,
1406 top: 4,
1407 right: 5,
1408 bottom: 5,
1409 },
1410 InclusiveRectangle {
1411 left: 6,
1412 top: 4,
1413 right: 7,
1414 bottom: 5,
1415 },
1416 ],
1417 };
1418 let expected_region = Region {
1419 extents: InclusiveRectangle {
1420 left: 1,
1421 top: 1,
1422 right: 7,
1423 bottom: 5,
1424 },
1425 rectangles: vec![
1426 InclusiveRectangle {
1427 left: 1,
1428 top: 1,
1429 right: 2,
1430 bottom: 3,
1431 },
1432 InclusiveRectangle {
1433 left: 3,
1434 top: 1,
1435 right: 4,
1436 bottom: 3,
1437 },
1438 InclusiveRectangle {
1439 left: 5,
1440 top: 1,
1441 right: 6,
1442 bottom: 3,
1443 },
1444 InclusiveRectangle {
1445 left: 2,
1446 top: 3,
1447 right: 3,
1448 bottom: 5,
1449 },
1450 InclusiveRectangle {
1451 left: 4,
1452 top: 3,
1453 right: 5,
1454 bottom: 5,
1455 },
1456 InclusiveRectangle {
1457 left: 6,
1458 top: 3,
1459 right: 7,
1460 bottom: 5,
1461 },
1462 ],
1463 };
1464
1465 region.simplify();
1466 assert_eq!(expected_region, region);
1467 }
1468
1469 #[test]
1470 fn intersect_rectangle_returns_empty_region_for_not_intersecting_rectangle() {
1471 let region = &*REGION_FOR_RECTANGLES_INTERSECTION;
1472 let expected_region = Region {
1473 extents: InclusiveRectangle {
1474 left: 0,
1475 top: 0,
1476 right: 0,
1477 bottom: 0,
1478 },
1479 rectangles: Vec::new(),
1480 };
1481 let input_rectangle = InclusiveRectangle {
1482 left: 1,
1483 top: 4,
1484 right: 2,
1485 bottom: 5,
1486 };
1487
1488 let actual_region = region.intersect_rectangle(&input_rectangle);
1489 assert_eq!(expected_region, actual_region);
1490 }
1491
1492 #[test]
1493 fn intersect_rectangle_returns_empty_region_for_empty_intersection_region() {
1494 let expected_region: Region = Region {
1495 extents: InclusiveRectangle {
1496 left: 0,
1497 top: 0,
1498 right: 0,
1499 bottom: 0,
1500 },
1501 rectangles: Vec::new(),
1502 };
1503 let input_rectangle = InclusiveRectangle {
1504 left: 5,
1505 top: 2,
1506 right: 6,
1507 bottom: 3,
1508 };
1509
1510 let actual_region = expected_region.intersect_rectangle(&input_rectangle);
1511 assert_eq!(expected_region, actual_region);
1512 }
1513
1514 #[test]
1515 fn intersect_rectangle_returns_part_of_rectangle_that_overlaps_for_region_with_one_rectangle() {
1516 let region = Region {
1517 extents: InclusiveRectangle {
1518 left: 1,
1519 top: 1,
1520 right: 5,
1521 bottom: 3,
1522 },
1523 rectangles: vec![InclusiveRectangle {
1524 left: 1,
1525 top: 1,
1526 right: 5,
1527 bottom: 3,
1528 }],
1529 };
1530 let expected_region = Region {
1531 extents: InclusiveRectangle {
1532 left: 2,
1533 top: 2,
1534 right: 3,
1535 bottom: 3,
1536 },
1537 rectangles: vec![InclusiveRectangle {
1538 left: 2,
1539 top: 2,
1540 right: 3,
1541 bottom: 3,
1542 }],
1543 };
1544 let input_rectangle = InclusiveRectangle {
1545 left: 2,
1546 top: 2,
1547 right: 3,
1548 bottom: 3,
1549 };
1550
1551 let actual_region = region.intersect_rectangle(&input_rectangle);
1552 assert_eq!(expected_region, actual_region);
1553 }
1554
1555 #[test]
1556 fn intersect_rectangle_returns_region_with_parts_of_rectangles_that_intersect_input_rectangle() {
1557 let region = &*REGION_FOR_RECTANGLES_INTERSECTION;
1558 let expected_region = Region {
1559 extents: InclusiveRectangle {
1560 left: 3,
1561 top: 2,
1562 right: 8,
1563 bottom: 5,
1564 },
1565 rectangles: vec![
1566 InclusiveRectangle {
1567 left: 3,
1568 top: 2,
1569 right: 5,
1570 bottom: 3,
1571 },
1572 InclusiveRectangle {
1573 left: 7,
1574 top: 2,
1575 right: 8,
1576 bottom: 3,
1577 },
1578 InclusiveRectangle {
1579 left: 7,
1580 top: 3,
1581 right: 8,
1582 bottom: 4,
1583 },
1584 InclusiveRectangle {
1585 left: 3,
1586 top: 4,
1587 right: 6,
1588 bottom: 5,
1589 },
1590 InclusiveRectangle {
1591 left: 7,
1592 top: 4,
1593 right: 8,
1594 bottom: 5,
1595 },
1596 ],
1597 };
1598 let input_rectangle = InclusiveRectangle {
1599 left: 3,
1600 top: 2,
1601 right: 8,
1602 bottom: 5,
1603 };
1604
1605 let actual_region = region.intersect_rectangle(&input_rectangle);
1606 assert_eq!(expected_region, actual_region);
1607 }
1608
1609 #[test]
1610 fn intersect_rectangle_returns_region_with_exact_sizes_of_rectangle_that_overlaps_it() {
1611 let region = &*REGION_FOR_RECTANGLES_INTERSECTION;
1612 let expected_region = Region {
1613 extents: InclusiveRectangle {
1614 left: 2,
1615 top: 2,
1616 right: 4,
1617 bottom: 3,
1618 },
1619 rectangles: vec![InclusiveRectangle {
1620 left: 2,
1621 top: 2,
1622 right: 4,
1623 bottom: 3,
1624 }],
1625 };
1626 let input_rectangle: InclusiveRectangle = InclusiveRectangle {
1627 left: 2,
1628 top: 2,
1629 right: 4,
1630 bottom: 3,
1631 };
1632
1633 let actual_region = region.intersect_rectangle(&input_rectangle);
1634 assert_eq!(expected_region, actual_region);
1635 }
1636}