rust_faces/
rect.rs

1use std::fmt::Display;
2
3/// Rectangle.
4#[derive(Debug, Clone, Copy)]
5pub struct Rect {
6    /// X coordinate of the top-left corner.
7    pub x: f32,
8    /// Y coordinate of the top-left corner.
9    pub y: f32,
10    /// Width of the rectangle.
11    pub width: f32,
12    /// Height of the rectangle.
13    pub height: f32,
14}
15
16/// Rectangle position used for chaining constructors.
17pub struct RectPosition {
18    pub x: f32,
19    pub y: f32,
20}
21
22impl RectPosition {
23    /// Makes a rectangle with the given size.
24    pub fn with_size(&self, width: f32, height: f32) -> Rect {
25        Rect {
26            x: self.x,
27            y: self.y,
28            width,
29            height,
30        }
31    }
32
33    /// Makes a rectangle with the given end point.
34    pub fn ending_at(&self, x: f32, y: f32) -> Rect {
35        Rect {
36            x: self.x,
37            y: self.y,
38            width: x - self.x,
39            height: y - self.y,
40        }
41    }
42}
43
44impl Rect {
45    /// Starts a rectangle with the given position.
46    pub fn at(x: f32, y: f32) -> RectPosition {
47        RectPosition { x, y }
48    }
49
50    /// Right end of the rectangle.
51    pub fn right(&self) -> f32 {
52        self.x + self.width
53    }
54
55    /// Bottom end of the rectangle.
56    pub fn bottom(&self) -> f32 {
57        self.y + self.height
58    }
59
60    /// Unites two rectangles.
61    ///
62    /// # Arguments
63    ///
64    /// * `other` - Other rectangle to unite with.
65    ///
66    /// # Returns
67    ///
68    /// * `Rect` - United rectangle.
69    pub fn union(&self, other: &Rect) -> Rect {
70        let left = self.x.min(other.x);
71        let right = self.right().max(other.right());
72        let top = self.y.min(other.y);
73        let bottom = self.bottom().max(other.bottom());
74
75        Rect {
76            x: left,
77            y: top,
78            width: right - left,
79            height: bottom - top,
80        }
81    }
82
83    /// Intersects two rectangles.
84    ///
85    /// # Arguments
86    ///
87    /// * `other` - Other rectangle to intersect with.
88    ///
89    /// # Returns
90    ///
91    /// * `Rect` - Intersected rectangle.
92    pub fn intersection(&self, other: &Rect) -> Rect {
93        let left = self.x.max(other.x);
94        let right = self.right().min(other.right());
95        let top = self.y.max(other.y);
96        let bottom = self.bottom().min(other.bottom());
97
98        Rect {
99            x: left,
100            y: top,
101            width: right - left,
102            height: bottom - top,
103        }
104    }
105
106    /// Clamps the rectangle to the given rect.
107    /// If the rectangle is larger than the given size, it will be shrunk.
108    ///
109    /// # Arguments
110    ///
111    /// * `width` - Width to clamp to.
112    /// * `height` - Height to clamp to.
113    pub fn clamp(&self, width: f32, height: f32) -> Rect {
114        let left = self.x.max(0.0);
115        let right = self.right().min(width);
116        let top = self.y.max(0.0);
117        let bottom = self.bottom().min(height);
118
119        Rect {
120            x: left,
121            y: top,
122            width: right - left,
123            height: bottom - top,
124        }
125    }
126
127    /// Calculates the intersection over union of two rectangles.
128    ///
129    /// # Arguments
130    ///
131    /// * `other` - Other rectangle to calculate the intersection over union with.
132    ///
133    /// # Returns
134    ///
135    /// * `f32` - Intersection over union.
136    pub fn iou(&self, other: &Rect) -> f32 {
137        let left = self.x.max(other.x);
138        let right = (self.right()).min(other.right());
139        let top = self.y.max(other.y);
140        let bottom = (self.bottom()).min(other.bottom());
141
142        let intersection = (right - left).max(0.0) * (bottom - top).max(0.0);
143        let area_self = self.width * self.height;
144        let area_other = other.width * other.height;
145
146        intersection / (area_self + area_other - intersection)
147    }
148
149    /// Calculates the intersection over union of two rectangles.
150    ///
151    /// # Arguments
152    ///
153    /// * `other` - Other rectangle to calculate the intersection over union with.
154    ///
155    /// # Returns
156    ///
157    /// * `f32` - Intersection over union.
158    pub fn iou_min(&self, other: &Rect) -> f32 {
159        let left = self.x.max(other.x);
160        let right = (self.right()).min(other.right());
161        let top = self.y.max(other.y);
162        let bottom = (self.bottom()).min(other.bottom());
163
164        let intersection = (right - left).max(0.0) * (bottom - top).max(0.0);
165        let area_self = self.width * self.height;
166        let area_other = other.width * other.height;
167
168        intersection / area_self.min(area_other)
169    }
170
171    /// Scales the rectangle.
172    pub fn scale(&self, x_scale: f32, y_scale: f32) -> Rect {
173        Rect {
174            x: self.x * x_scale,
175            y: self.y * y_scale,
176            width: self.width * x_scale,
177            height: self.height * y_scale,
178        }
179    }
180
181    /// Gets the rectangle as a tuple of (x, y, width, height).
182    pub fn to_xywh(&self) -> (f32, f32, f32, f32) {
183        (self.x, self.y, self.width, self.height)
184    }
185}
186
187impl Display for Rect {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        write!(
190            f,
191            "{{x: {}, y: {}, width: {}, height: {}}}",
192            self.x, self.y, self.width, self.height
193        )
194    }
195}