From 4bf7a0c9b2ba7fd4adaeb39217cdc325a52b88fd Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 3 Mar 2024 22:04:27 +0100 Subject: [PATCH] Add Rect --- showbits-common/src/lib.rs | 3 +- showbits-common/src/rect.rs | 118 ++++++++++++++++++++++++++++++++++++ showbits-common/src/vec2.rs | 55 +++++++++++++++-- 3 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 showbits-common/src/rect.rs diff --git a/showbits-common/src/lib.rs b/showbits-common/src/lib.rs index b5eac6e..91a1efd 100644 --- a/showbits-common/src/lib.rs +++ b/showbits-common/src/lib.rs @@ -1,4 +1,5 @@ -pub use crate::{buffer::Buffer, vec2::Vec2}; +pub use crate::{buffer::Buffer, rect::Rect, vec2::Vec2}; mod buffer; +mod rect; mod vec2; diff --git a/showbits-common/src/rect.rs b/showbits-common/src/rect.rs new file mode 100644 index 0000000..ca61d36 --- /dev/null +++ b/showbits-common/src/rect.rs @@ -0,0 +1,118 @@ +use std::ops::{Add, Sub}; + +use crate::Vec2; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Rect { + north: i32, + south: i32, + west: i32, + east: i32, +} + +impl Rect { + /// Whenever a `Rect` is constructed, this function must be used. This + /// ensures invariants are always checked. + fn new(north: i32, south: i32, west: i32, east: i32) -> Self { + let result = Self { + north, + south, + west, + east, + }; + + let size = result.size(); + assert!(size.x >= 0); + assert!(size.y >= 0); + + result + } + + /// Construct a `Rect` that is a bounding box around two points. + /// + /// It is not possible to construct a `Rect` with a width or height of 0 + /// through this method. Use one of the other constructor functions instead. + pub fn from_points(a: Vec2, b: Vec2) -> Self { + Self::new(a.y.min(b.y), a.y.max(b.y), a.x.min(b.x), a.x.max(b.x)) + } + + /// Construct a `Rect` from its north-west and south-east corners. + pub fn from_nw_se(nw: Vec2, se: Vec2) -> Self { + Self::new(nw.y, se.y, nw.x, se.x) + } + + /// Construct a `Rect` from its north-east and south-west corners. + pub fn from_ne_sw(ne: Vec2, sw: Vec2) -> Self { + Self::new(ne.y, sw.y, sw.x, ne.x) + } + + /// Construct a `Rect` from its north-west corner and size. + pub fn from_nw(nw: Vec2, size: Vec2) -> Self { + let se = nw + (size - 1); + Self::from_nw_se(nw, se) + } + + /// Construct a `Rect` from its north-east corner and size. + pub fn from_corner_ne(ne: Vec2, size: Vec2) -> Self { + let sw = ne + (size - 1).neg_x(); + Self::from_ne_sw(ne, sw) + } + + /// Construct a `Rect` from its south-west corner and size. + pub fn from_corner_sw(sw: Vec2, size: Vec2) -> Self { + let ne = sw + (size - 1).neg_y(); + Self::from_ne_sw(ne, sw) + } + + /// Construct a `Rect` from its south-east corner and size. + pub fn from_corner_se(se: Vec2, size: Vec2) -> Self { + let nw = se - (size - 1); + Self::from_nw_se(nw, se) + } + + pub fn corner_nw(&self) -> Vec2 { + Vec2::new(self.west, self.north) + } + + pub fn corner_ne(&self) -> Vec2 { + Vec2::new(self.east, self.north) + } + + pub fn corner_sw(&self) -> Vec2 { + Vec2::new(self.west, self.south) + } + + pub fn corner_se(&self) -> Vec2 { + Vec2::new(self.east, self.south) + } + + pub fn size(&self) -> Vec2 { + Vec2::new(self.east - self.west + 1, self.south - self.north + 1) + } +} + +impl Add for Rect { + type Output = Self; + + fn add(self, rhs: Vec2) -> Self::Output { + Self::new( + self.north + rhs.y, + self.south + rhs.y, + self.west + rhs.x, + self.east + rhs.x, + ) + } +} + +impl Sub for Rect { + type Output = Self; + + fn sub(self, rhs: Vec2) -> Self::Output { + Self::new( + self.north - rhs.y, + self.south - rhs.y, + self.west - rhs.x, + self.east - rhs.x, + ) + } +} diff --git a/showbits-common/src/vec2.rs b/showbits-common/src/vec2.rs index 1660e6d..8a73dee 100644 --- a/showbits-common/src/vec2.rs +++ b/showbits-common/src/vec2.rs @@ -20,9 +20,39 @@ impl Vec2 { Self { x, y } } + /// The vector pointing from `self` to `other`. + /// + /// ``` + /// # use showbits_common::Vec2; + /// let a = Vec2::new(1, 3); + /// let b = Vec2::new(3, 7); + /// assert_eq!(a.to(b), b - a); + /// ``` pub fn to(self, other: Self) -> Self { other - self } + + /// Negate the `x` component of the vector. + /// + /// ``` + /// # use showbits_common::Vec2; + /// let v = Vec2::new(3, 4); + /// assert_eq!(v.neg_x(), v * Vec2::new(-1, 1)); + /// ``` + pub fn neg_x(self) -> Self { + Self { x: -self.x, ..self } + } + + /// Negate the `y` component of the vector. + /// + /// ``` + /// # use showbits_common::Vec2; + /// let v = Vec2::new(3, 4); + /// assert_eq!(v.neg_y(), v * Vec2::new(1, -1)); + /// ``` + pub fn neg_y(self) -> Self { + Self { y: -self.y, ..self } + } } impl fmt::Debug for Vec2 { @@ -53,6 +83,14 @@ impl Add for Vec2 { } } +impl Add for Vec2 { + type Output = Self; + + fn add(self, rhs: i32) -> Self::Output { + self + Self::new(rhs, rhs) + } +} + impl Sub for Vec2 { type Output = Self; @@ -64,14 +102,11 @@ impl Sub for Vec2 { } } -impl Mul for Vec2 { +impl Sub for Vec2 { type Output = Self; - fn mul(self, rhs: i32) -> Self::Output { - Self { - x: self.x * rhs, - y: self.y * rhs, - } + fn sub(self, rhs: i32) -> Self::Output { + self - Self::new(rhs, rhs) } } @@ -85,3 +120,11 @@ impl Mul for Vec2 { } } } + +impl Mul for Vec2 { + type Output = Self; + + fn mul(self, rhs: i32) -> Self::Output { + self * Self::new(rhs, rhs) + } +}