Skip to main content

standard_plugin/
geometry.rs

1//! Surface sizes and rectangles.
2
3/// The size a surface currently has. `cols`/`rows` are cells; `px_w`/`px_h`
4/// the pixel size of the graphics model (zero while the viewer has no pixel
5/// geometry); `cell_px_w`/`cell_px_h` the pixel size of one cell.
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
7pub struct Geometry {
8    pub cols: u32,
9    pub rows: u32,
10    pub px_w: u32,
11    pub px_h: u32,
12    pub cell_px_w: u32,
13    pub cell_px_h: u32,
14}
15
16impl Geometry {
17    /// `cols` by `rows` cells of `cell_px` pixels (`(0, 0)`: no pixels).
18    pub const fn cells(cols: u32, rows: u32, cell_px: (u32, u32)) -> Self {
19        Self {
20            cols,
21            rows,
22            px_w: cols * cell_px.0,
23            px_h: rows * cell_px.1,
24            cell_px_w: cell_px.0,
25            cell_px_h: cell_px.1,
26        }
27    }
28
29    pub const fn is_empty(&self) -> bool {
30        self.cols == 0 || self.rows == 0
31    }
32}
33
34/// A rectangle in cells (cell model) or pixels (graphics model).
35#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
36pub struct Rect {
37    pub x: u32,
38    pub y: u32,
39    pub w: u32,
40    pub h: u32,
41}
42
43impl Rect {
44    pub const fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
45        Self { x, y, w, h }
46    }
47
48    pub const fn is_empty(&self) -> bool {
49        self.w == 0 || self.h == 0
50    }
51
52    pub const fn right(&self) -> u32 {
53        self.x.saturating_add(self.w)
54    }
55
56    pub const fn bottom(&self) -> u32 {
57        self.y.saturating_add(self.h)
58    }
59
60    pub const fn area(&self) -> u64 {
61        self.w as u64 * self.h as u64
62    }
63
64    /// The part inside a `width` by `height` surface, or `None`.
65    pub fn clamp(self, width: u32, height: u32) -> Option<Self> {
66        let right = self.right().min(width);
67        let bottom = self.bottom().min(height);
68        (self.x < right && self.y < bottom).then(|| Self {
69            x: self.x,
70            y: self.y,
71            w: right - self.x,
72            h: bottom - self.y,
73        })
74    }
75
76    pub fn contains_rect(&self, other: &Self) -> bool {
77        other.x >= self.x
78            && other.y >= self.y
79            && other.right() <= self.right()
80            && other.bottom() <= self.bottom()
81    }
82
83    /// The smallest rectangle covering both.
84    pub fn union(&self, other: &Self) -> Self {
85        let x = self.x.min(other.x);
86        let y = self.y.min(other.y);
87        Self {
88            x,
89            y,
90            w: self.right().max(other.right()) - x,
91            h: self.bottom().max(other.bottom()) - y,
92        }
93    }
94}