#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Rect {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
impl Rect {
pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
Self {
x,
y,
width,
height,
}
}
pub fn contains(&self, x: f32, y: f32) -> bool {
x >= self.x && x < self.x + self.width && y >= self.y && y < self.y + self.height
}
pub fn intersect(self, other: Rect) -> Option<Rect> {
let x = self.x.max(other.x);
let y = self.y.max(other.y);
let right = (self.x + self.width).min(other.x + other.width);
let bottom = (self.y + self.height).min(other.y + other.height);
if right > x && bottom > y {
Some(Rect::new(x, y, right - x, bottom - y))
} else {
None
}
}
pub fn union(self, other: Rect) -> Rect {
let x = self.x.min(other.x);
let y = self.y.min(other.y);
let right = (self.x + self.width).max(other.x + other.width);
let bottom = (self.y + self.height).max(other.y + other.height);
Rect::new(x, y, right - x, bottom - y)
}
pub fn overlaps(self, other: Rect) -> bool {
self.x < other.x + other.width
&& self.x + self.width > other.x
&& self.y < other.y + other.height
&& self.y + self.height > other.y
}
}
impl Default for Rect {
fn default() -> Self {
Self::new(0.0, 0.0, 0.0, 0.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rect_new_stores_fields() {
let r = Rect::new(1.0, 2.0, 10.0, 20.0);
assert_eq!(r.x, 1.0);
assert_eq!(r.y, 2.0);
assert_eq!(r.width, 10.0);
assert_eq!(r.height, 20.0);
}
#[test]
fn rect_default_is_zero() {
let r = Rect::default();
assert_eq!(r.x, 0.0);
assert_eq!(r.y, 0.0);
assert_eq!(r.width, 0.0);
assert_eq!(r.height, 0.0);
}
#[test]
fn rect_intersect_overlapping() {
let a = Rect::new(0.0, 0.0, 10.0, 10.0);
let b = Rect::new(5.0, 5.0, 10.0, 10.0);
let result = a.intersect(b).unwrap();
assert_eq!(result.x, 5.0);
assert_eq!(result.y, 5.0);
assert_eq!(result.width, 5.0);
assert_eq!(result.height, 5.0);
}
#[test]
fn rect_intersect_non_overlapping() {
let a = Rect::new(0.0, 0.0, 5.0, 5.0);
let b = Rect::new(10.0, 10.0, 5.0, 5.0);
assert!(a.intersect(b).is_none());
}
}