Skip to main content

stipple_geometry/
size.rs

1use crate::Insets;
2
3/// A 2D extent (width × height) in logical pixels.
4///
5/// Components are expected to be non-negative; helpers that could produce a
6/// negative extent clamp to zero.
7#[derive(Clone, Copy, Debug, Default, PartialEq)]
8pub struct Size {
9    pub width: f64,
10    pub height: f64,
11}
12
13impl Size {
14    pub const ZERO: Self = Self {
15        width: 0.0,
16        height: 0.0,
17    };
18
19    #[inline]
20    pub const fn new(width: f64, height: f64) -> Self {
21        Self { width, height }
22    }
23
24    #[inline]
25    pub fn is_empty(self) -> bool {
26        self.width <= 0.0 || self.height <= 0.0
27    }
28
29    #[inline]
30    pub fn area(self) -> f64 {
31        self.width * self.height
32    }
33
34    /// Shrinks the size by `insets` on all sides, clamping to zero.
35    #[inline]
36    pub fn deflate(self, insets: Insets) -> Size {
37        Size::new(
38            (self.width - insets.left - insets.right).max(0.0),
39            (self.height - insets.top - insets.bottom).max(0.0),
40        )
41    }
42
43    /// Grows the size by `insets` on all sides.
44    #[inline]
45    pub fn inflate(self, insets: Insets) -> Size {
46        Size::new(
47            self.width + insets.left + insets.right,
48            self.height + insets.top + insets.bottom,
49        )
50    }
51
52    /// Component-wise clamp into `[min, max]`.
53    #[inline]
54    pub fn clamp(self, min: Size, max: Size) -> Size {
55        Size::new(
56            self.width.clamp(min.width, max.width),
57            self.height.clamp(min.height, max.height),
58        )
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn deflate_clamps_to_zero() {
68        let s = Size::new(10.0, 4.0);
69        assert_eq!(s.deflate(Insets::uniform(3.0)), Size::new(4.0, 0.0));
70    }
71}