use std::cmp::{max, min}; #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub struct Size { pub width: usize, pub height: usize, } impl specs::Component for Size { type Storage = specs::VecStorage; } impl From<[usize; 2]> for Size { fn from([width, height]: [usize; 2]) -> Size { Size { width, height } } } #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub struct Coord { pub x: usize, pub y: usize, } impl specs::Component for Coord { type Storage = specs::VecStorage; } impl From<[usize; 2]> for Coord { fn from([x, y]: [usize; 2]) -> Coord { Coord { x, y } } } #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub struct Rect { pub origin: Coord, pub size: Size, } impl Rect { pub fn new(origin: impl Into, size: impl Into) -> Rect { let origin = origin.into(); let size = size.into(); Rect { origin, size } } pub fn from_points(p1: impl Into, p2: impl Into) -> Rect { let p1 = p1.into(); let p2 = p2.into(); let origin = Coord { x: min(p1.x, p2.x), y: min(p1.y, p2.y), }; let size = Size { width: max(max(p1.x, p2.x) - origin.x, 1), height: max(max(p1.y, p2.y) - origin.y, 1), }; Rect { origin, size } } pub fn area(&self) -> usize { self.size.width * self.size.height } pub fn width(&self) -> usize { self.size.width } pub fn height(&self) -> usize { self.size.height } pub fn x(&self) -> usize { self.origin.x } pub fn y(&self) -> usize { self.origin.y } pub fn contains(&self, pt: impl Into) -> bool { let pt = pt.into(); pt.x >= self.origin.x && pt.y >= self.origin.y && pt.x < self.origin.x + self.size.width && pt.y < self.origin.y + self.size.height } pub fn overlaps(&self, other: Rect) -> bool { if self.x() > other.x() + other.width() || other.x() > self.x() + self.width() { return false; } if self.y() > other.y() + other.height() || other.y() > self.y() + self.height() { return false; } true } pub fn center(&self) -> Coord { Coord { x: self.x() + (self.width() / 2), y: self.y() + (self.height() / 2), } } }