1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use super::ICoord;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct IRect {
pub left: isize,
pub top: isize,
pub width: usize,
pub height: usize,
}
impl IRect {
pub fn new(left: isize, top: isize, width: usize, height: usize) -> Self {
Self {
left,
top,
width,
height,
}
}
pub fn centered(center: ICoord, width: usize, height: usize) -> Self {
let top = center.y - height as isize / 2;
let left = center.x - width as isize / 2;
Self::new(left, top, width, height)
}
pub fn contains(&self, pos: ICoord) -> bool {
self.top <= pos.y && self.bottom() >= pos.y && self.left <= pos.x && self.right() >= pos.x
}
pub fn area(&self) -> usize {
self.width * self.height
}
pub fn contained_coords(&self) -> RectIter {
RectIter::new(*self)
}
pub fn right(&self) -> isize {
self.left + self.width as isize - 1
}
pub fn bottom(&self) -> isize {
self.top + self.height as isize - 1
}
pub fn shifted(self, by: ICoord) -> IRect {
IRect {
top: self.top + by.y,
left: self.left + by.x,
..self
}
}
}
impl std::ops::Add<ICoord> for IRect {
type Output = IRect;
fn add(self, rhs: ICoord) -> Self::Output {
self.shifted(rhs)
}
}
pub struct RectIter {
rect: IRect,
cursor: ICoord,
exhausted: bool,
}
impl RectIter {
pub fn new(rect: IRect) -> Self {
Self {
rect,
cursor: ICoord::new(rect.left, rect.top),
exhausted: rect.width == 0 || rect.height == 0,
}
}
}
impl Iterator for RectIter {
type Item = ICoord;
fn next(&mut self) -> Option<Self::Item> {
if !self.exhausted {
let out = self.cursor;
self.cursor.x += 1;
if !self.rect.contains(self.cursor) {
self.cursor.x = self.rect.left;
self.cursor.y += 1;
if !self.rect.contains(self.cursor) {
self.exhausted = true;
}
}
Some(out)
} else {
None
}
}
}