Skip to main content

ansiq_core/
geometry.rs

1use crate::Padding;
2
3#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
4pub struct Rect {
5    pub x: u16,
6    pub y: u16,
7    pub width: u16,
8    pub height: u16,
9}
10
11impl Rect {
12    pub const fn new(x: u16, y: u16, width: u16, height: u16) -> Self {
13        Self {
14            x,
15            y,
16            width,
17            height,
18        }
19    }
20
21    pub const fn right(self) -> u16 {
22        self.x.saturating_add(self.width)
23    }
24
25    pub const fn bottom(self) -> u16 {
26        self.y.saturating_add(self.height)
27    }
28
29    pub const fn is_empty(self) -> bool {
30        self.width == 0 || self.height == 0
31    }
32
33    pub const fn intersects(self, other: Self) -> bool {
34        self.x < other.right()
35            && other.x < self.right()
36            && self.y < other.bottom()
37            && other.y < self.bottom()
38    }
39
40    pub fn intersection(self, other: Self) -> Option<Self> {
41        if !self.intersects(other) {
42            return None;
43        }
44
45        let x = self.x.max(other.x);
46        let y = self.y.max(other.y);
47        let right = self.right().min(other.right());
48        let bottom = self.bottom().min(other.bottom());
49
50        Some(Self::new(
51            x,
52            y,
53            right.saturating_sub(x),
54            bottom.saturating_sub(y),
55        ))
56    }
57
58    pub const fn contains(self, other: Self) -> bool {
59        self.x <= other.x
60            && self.y <= other.y
61            && self.right() >= other.right()
62            && self.bottom() >= other.bottom()
63    }
64
65    pub const fn can_merge_rect(self, other: Self) -> bool {
66        self.intersects(other)
67            || (self.x == other.x
68                && self.width == other.width
69                && (self.bottom() == other.y || other.bottom() == self.y))
70            || (self.y == other.y
71                && self.height == other.height
72                && (self.right() == other.x || other.right() == self.x))
73    }
74
75    pub fn union(self, other: Self) -> Self {
76        let x = self.x.min(other.x);
77        let y = self.y.min(other.y);
78        let right = self.right().max(other.right());
79        let bottom = self.bottom().max(other.bottom());
80        Self::new(x, y, right.saturating_sub(x), bottom.saturating_sub(y))
81    }
82
83    pub fn shrink(self, amount: u16) -> Self {
84        let next_x = self.x.saturating_add(amount.min(self.width));
85        let next_y = self.y.saturating_add(amount.min(self.height));
86
87        if self.width <= amount.saturating_mul(2) || self.height <= amount.saturating_mul(2) {
88            return Self::new(next_x, next_y, 0, 0);
89        }
90
91        Self::new(
92            self.x.saturating_add(amount),
93            self.y.saturating_add(amount),
94            self.width.saturating_sub(amount.saturating_mul(2)),
95            self.height.saturating_sub(amount.saturating_mul(2)),
96        )
97    }
98
99    pub fn inset(self, padding: Padding) -> Self {
100        let x = self.x.saturating_add(padding.left.min(self.width));
101        let y = self.y.saturating_add(padding.top.min(self.height));
102        let horizontal = padding.left.saturating_add(padding.right);
103        let vertical = padding.top.saturating_add(padding.bottom);
104
105        Self::new(
106            x,
107            y,
108            self.width.saturating_sub(horizontal),
109            self.height.saturating_sub(vertical),
110        )
111    }
112}