This commit is contained in:
Joscha 2024-03-03 22:04:27 +01:00
parent 52c5778a19
commit 4bf7a0c9b2
3 changed files with 169 additions and 7 deletions

118
showbits-common/src/rect.rs Normal file
View file

@ -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<Vec2> 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<Vec2> 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,
)
}
}