From 8547ad9c2f2867da9b0e655dd4ff0fe78f04ffba Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Sun, 24 Dec 2023 20:03:12 +1300 Subject: First commit --- src/rect.rs | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 src/rect.rs (limited to 'src/rect.rs') diff --git a/src/rect.rs b/src/rect.rs new file mode 100644 index 0000000..3f5e9e3 --- /dev/null +++ b/src/rect.rs @@ -0,0 +1,193 @@ +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); -- cgit v1.2.3-70-g09d2