use crate::{Pos, Size};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Region {
pub from: Pos,
pub to: Pos,
}
impl Region {
pub const ZERO: Self = Self::new(Pos::ZERO, Pos::ZERO);
pub const fn new(from: Pos, to: Pos) -> Self {
Self { from, to }
}
pub const fn intersects(&self, other: &Region) -> bool {
if other.to.x <= self.from.x || other.from.x >= self.to.x {
return false;
}
if other.from.y >= self.to.y || other.to.y <= self.from.y {
return false;
}
true
}
pub fn intersect_with(self, other: &Region) -> Self {
if !self.intersects(other) {
return Self::ZERO;
}
let from_x = self.from.x.max(other.from.x);
let from_y = self.from.y.max(other.from.y);
let to_x = self.to.x.min(other.to.x);
let to_y = self.to.y.min(other.to.y);
Region::new(Pos::new(from_x, from_y), Pos::new(to_x, to_y))
}
pub const fn contains(&self, pos: Pos) -> bool {
pos.x >= self.from.x && pos.x < self.to.x && pos.y >= self.from.y && pos.y < self.to.y
}
pub fn constrain(&mut self, other: &Region) {
self.from.x = self.from.x.max(other.from.x);
self.from.y = self.from.y.max(other.from.y);
self.to.x = self.to.x.min(other.to.x);
self.to.y = self.to.y.min(other.to.y);
}
}
impl From<(Pos, Size)> for Region {
fn from((from, size): (Pos, Size)) -> Self {
let to = Pos::new(from.x + size.width as i32, from.y + size.height as i32);
Self::new(from, to)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn region_inersect() {
let a = Region::new(Pos::ZERO, Pos::new(10, 10));
let b = Region::new(Pos::new(5, 5), Pos::new(8, 8));
assert!(a.intersects(&b));
assert!(b.intersects(&a));
}
#[test]
fn region_contains() {
let a = Region::new(Pos::ZERO, Pos::new(10, 10));
assert!(a.contains(Pos::ZERO));
assert!(a.contains(Pos::new(9, 9)));
assert!(!a.contains(Pos::new(10, 10)));
}
#[test]
fn constrain_region() {
let inner = Region::from((Pos::ZERO, Size::new(10, 10)));
let mut outer = Region::from((Pos::ZERO, Size::new(100, 100)));
outer.constrain(&inner);
let expected = inner;
assert_eq!(expected, outer);
}
}