use crate::*; use std::fmt; use std::ops::{Add, Sub, AddAssign, SubAssign}; #[derive(Clone, Copy, PartialEq)] pub struct Rect { pub origin: Point, pub dimensions: Dimensions, } pub trait HasRect: HasPosition + HasDimensions { fn rect(&self) -> Rect; } impl Rect { pub const ZERO: Rect = Rect::construct(Point::::ZERO, Dimensions::::ZERO); pub const fn new(origin_x: O, origin_y: O, width: D, height: D) -> Self { let origin = Point::new(origin_x, origin_y); let dimensions = Dimensions::new(width, height); Self { origin, dimensions } } pub const fn construct(origin: Point, dimensions: Dimensions) -> Self { Self { origin, dimensions } } } impl HasDimensions for Rect { fn dimensions(&self) -> Dimensions { self.dimensions } } impl HasPosition for Rect { fn position(&self) -> Point { self.origin } } impl + HasPosition> HasRect for T { fn rect(&self) -> Rect { Rect::construct(self.position(), self.dimensions()) } } impl Add> for Rect { type Output = Rect; fn add(self, point: Point) -> Self::Output { Rect::construct(self.origin + point, self.dimensions) } } impl Sub> for Rect { type Output = Rect; fn sub(self, point: Point) -> Self::Output { Rect::construct(self.origin - point, self.dimensions) } } impl AddAssign> for Rect { fn add_assign(&mut self, point: Point) { self.origin += point } } impl SubAssign> for Rect { fn sub_assign(&mut self, point: Point) { self.origin -= point } } impl fmt::Debug for Rect { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Rect {{ x:{:?} y:{:?} w:{:?} h:{:?} }}", self.origin.x, self.origin.y, self.dimensions.width, self.dimensions.height, ) } } // ----------------------------------------------------------------------------- // Macro-generated code // PartialOrd versions of std::cmp::min/max fn min(a: T, b: T) -> T { match a < b { true => a, false => b } } fn max(a: T, b: T) -> T { match a > b { true => a, false => b } } macro_rules! impl_for_types { ($O:ty, $D:ty) => { impl Rect<$O, $D> { pub const fn from_dimensions(dimensions: Dimensions<$D>) -> Self { Self { origin: Point::<$O>::ZERO, dimensions, } } pub fn from_points(point1: Point<$O>, point2: Point<$O>) -> Self { let (left, right) = match point1.x < point2.x { true => (point1.x, point2.x), false => (point2.x, point1.x), }; let (top, bottom) = match point1.y < point2.y { true => (point1.y, point2.y), false => (point2.y, point1.y), }; let width = (right - left) as $D; let height = (bottom - top) as $D; Self { origin: Point::new(left, top), dimensions: Dimensions::new(width, height), } } /// Returns Rect(0,0,0,0) where no intersection exists. pub fn intersect(&self, other: Rect<$O, $D>) -> Self { let left = max(self.origin.x, other.origin.x); let top = max(self.origin.y, other.origin.y); let right_self = self.origin.x + (self.width() as $O); let right_other = other.origin.x + (other.width() as $O); let bottom_self = self.origin.y + (self.height() as $O); let bottom_other = other.origin.y + (other.height() as $O); let right = min(right_self, right_other); let bottom = min(bottom_self, bottom_other); if right <= left || bottom <= top { Rect::<$O, $D>::ZERO } else { let width = (right - left) as $D; let height = (bottom - top) as $D; Rect::construct(Point::new(left, top), Dimensions::new(width, height)) } } pub fn contains_point(&self, point: Point<$O>) -> bool { let left = self.origin.x; let top = self.origin.y; let right = left + (self.width() as $O); let bottom = top + (self.height() as $O); point.x >= left && point.x < right && point.y >= top && point.y < bottom } pub fn include_point(&mut self, _point: Point<$O>) { todo!() } /// Return the inclusive left x-coordinate. pub fn left(&self) -> $O { self.origin.x } /// Return the inclusive top y-coordinate. pub fn top(&self) -> $O { self.origin.y } /// Return the exclusive right x-coordinate. pub fn right(&self) -> $O { self.left() + self.width() as $O } /// Return the exclusive bottom y-coordinate. pub fn bottom(&self) -> $O { self.top() + self.height() as $O } } impl From> for Rect<$O, $D> { fn from(dimensions: Dimensions<$D>) -> Rect<$O, $D> { Rect::<$O, $D>::from_dimensions(dimensions) } } }; } impl_for_types!(u8, u8); impl_for_types!(u16, u16); impl_for_types!(u32, u32); impl_for_types!(u64, u64); impl_for_types!(u128, u128); impl_for_types!(usize, usize); impl_for_types!(i8, u8); impl_for_types!(i16, u16); impl_for_types!(i32, u32); impl_for_types!(i64, u64); impl_for_types!(i128, u128); impl_for_types!(isize, usize); impl_for_types!(f32, f32); impl_for_types!(f64, f64);