use std::ops::{Add, AddAssign, BitAnd, BitAndAssign, Sub, SubAssign};
use super::{Affine, Point, Size, Vector};
#[derive(Clone, Copy, Debug, Default, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rect {
pub min: Point,
pub max: Point,
}
impl Rect {
pub const ZERO: Self = Self::new(Point::ZERO, Point::ZERO);
pub const fn new(min: Point, max: Point) -> Self {
Self { min, max }
}
pub fn min_size(min: Point, size: Size) -> Self {
Self {
min,
max: min + size,
}
}
pub fn max_size(max: Point, size: Size) -> Self {
Self {
min: max - size,
max,
}
}
pub fn center_size(center: Point, size: Size) -> Self {
Self {
min: center - size / 2.0,
max: center + size / 2.0,
}
}
pub fn round(self) -> Self {
Self {
min: self.min.round(),
max: self.max.round(),
}
}
pub fn clamp(self, other: impl Into<Self>) -> Self {
let other = other.into();
Self {
min: self.min.clamp(other.min, other.max),
max: self.max.clamp(other.min, other.max),
}
}
pub fn offset(self) -> Vector {
self.min.to_vector()
}
pub fn size(self) -> Size {
Size::from(self.max - self.min)
}
pub fn width(self) -> f32 {
self.max.x - self.min.x
}
pub fn height(self) -> f32 {
self.max.y - self.min.y
}
pub fn area(self) -> f32 {
self.width() * self.height()
}
pub fn top_left(self) -> Point {
self.min
}
pub fn top_center(self) -> Point {
Point::new(self.center().x, self.min.y)
}
pub fn top_right(self) -> Point {
Point::new(self.max.x, self.min.y)
}
pub fn center_left(self) -> Point {
Point::new(self.min.x, self.center().y)
}
pub fn center(self) -> Point {
self.min + self.size() / 2.0
}
pub fn center_right(self) -> Point {
Point::new(self.max.x, self.center().y)
}
pub fn bottom_left(self) -> Point {
Point::new(self.min.x, self.max.y)
}
pub fn bottom_center(self) -> Point {
Point::new(self.center().x, self.max.y)
}
pub fn bottom_right(self) -> Point {
self.max
}
pub fn top(self) -> f32 {
self.min.y
}
pub fn left(self) -> f32 {
self.min.x
}
pub fn right(self) -> f32 {
self.max.x
}
pub fn bottom(self) -> f32 {
self.max.y
}
pub fn is_finite(self) -> bool {
self.min.is_finite() && self.max.is_finite()
}
pub fn is_infinite(self) -> bool {
self.min.is_infinite() || self.max.is_infinite()
}
pub fn shrink(self, padding: f32) -> Self {
Self {
min: self.min + Vector::new(padding, padding),
max: self.max - Vector::new(padding, padding),
}
}
pub fn expand(self, padding: f32) -> Self {
self.shrink(-padding)
}
pub fn contains(self, point: Point) -> bool {
let x = point.x >= self.min.x && point.x <= self.max.x;
let y = point.y >= self.min.y && point.y <= self.max.y;
x && y
}
pub fn contain(self, point: Point) -> Point {
let x = point.x.max(self.min.x).min(self.max.x);
let y = point.y.max(self.min.y).min(self.max.y);
Point::new(x, y)
}
pub fn include(self, point: Point) -> Self {
let min_x = f32::min(self.min.x, point.x);
let min_y = f32::min(self.min.y, point.y);
let max_x = f32::max(self.max.x, point.x);
let max_y = f32::max(self.max.y, point.y);
Self {
min: Point::new(min_x, min_y),
max: Point::new(max_x, max_y),
}
}
pub fn try_intersection(self, other: Self) -> Option<Self> {
let min_x = f32::max(self.min.x, other.min.x);
let min_y = f32::max(self.min.y, other.min.y);
let max_x = f32::min(self.max.x, other.max.x);
let max_y = f32::min(self.max.y, other.max.y);
if min_x <= max_x && min_y <= max_y {
Some(Self {
min: Point::new(min_x, min_y),
max: Point::new(max_x, max_y),
})
} else {
None
}
}
pub fn intersection(self, other: Self) -> Self {
self.try_intersection(other).unwrap_or(Self::ZERO)
}
pub fn intersects(self, other: Self) -> bool {
self.try_intersection(other).is_some()
}
pub fn union(self, other: Self) -> Self {
let min_x = f32::min(self.min.x, other.min.x);
let min_y = f32::min(self.min.y, other.min.y);
let max_x = f32::max(self.max.x, other.max.x);
let max_y = f32::max(self.max.y, other.max.y);
Self {
min: Point::new(min_x, min_y),
max: Point::new(max_x, max_y),
}
}
pub fn transform(self, transform: Affine) -> Self {
let tl = transform * self.top_left();
let tr = transform * self.top_right();
let bl = transform * self.bottom_left();
let br = transform * self.bottom_right();
let min_x = f32::min(f32::min(tl.x, tr.x), f32::min(bl.x, br.x));
let min_y = f32::min(f32::min(tl.y, tr.y), f32::min(bl.y, br.y));
let max_x = f32::max(f32::max(tl.x, tr.x), f32::max(bl.x, br.x));
let max_y = f32::max(f32::max(tl.y, tr.y), f32::max(bl.y, br.y));
Self {
min: Point::new(min_x, min_y),
max: Point::new(max_x, max_y),
}
}
}
impl From<Size> for Rect {
fn from(size: Size) -> Self {
Self::new(Point::ZERO, size.into())
}
}
impl From<[f32; 4]> for Rect {
fn from([min_x, min_y, max_x, max_y]: [f32; 4]) -> Self {
Self {
min: Point::new(min_x, min_y),
max: Point::new(max_x, max_y),
}
}
}
impl From<Rect> for [f32; 4] {
fn from(rect: Rect) -> Self {
[rect.min.x, rect.min.y, rect.max.x, rect.max.y]
}
}
impl Add<Vector> for Rect {
type Output = Self;
fn add(self, rhs: Vector) -> Self::Output {
Self {
min: self.min + rhs,
max: self.max + rhs,
}
}
}
impl Add<Size> for Rect {
type Output = Self;
fn add(self, rhs: Size) -> Self::Output {
Self {
min: self.min,
max: self.max + rhs,
}
}
}
impl Sub<Vector> for Rect {
type Output = Self;
fn sub(self, rhs: Vector) -> Self::Output {
Self {
min: self.min - rhs,
max: self.max - rhs,
}
}
}
impl Sub<Size> for Rect {
type Output = Self;
fn sub(self, rhs: Size) -> Self::Output {
Self {
min: self.min,
max: self.max - rhs,
}
}
}
impl AddAssign<Vector> for Rect {
fn add_assign(&mut self, rhs: Vector) {
self.min += rhs;
self.max += rhs;
}
}
impl AddAssign<Size> for Rect {
fn add_assign(&mut self, rhs: Size) {
self.max += rhs;
}
}
impl SubAssign<Vector> for Rect {
fn sub_assign(&mut self, rhs: Vector) {
self.min -= rhs;
self.max -= rhs;
}
}
impl SubAssign<Size> for Rect {
fn sub_assign(&mut self, rhs: Size) {
self.max -= rhs;
}
}
impl BitAnd for Rect {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
self.intersection(rhs)
}
}
impl BitAndAssign for Rect {
fn bitand_assign(&mut self, rhs: Self) {
*self = self.intersection(rhs);
}
}