use std::cmp::{max, min};
use crate::layout::{Direction, Margin};
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
pub struct Rect {
pub x: u16,
pub y: u16,
pub width: u16,
pub height: u16,
}
impl Rect {
pub fn new(x: u16, y: u16, width: u16, height: u16) -> Rect {
let max_area = u16::max_value();
let (clipped_width, clipped_height) =
if u32::from(width) * u32::from(height) > u32::from(max_area) {
let aspect_ratio = f64::from(width) / f64::from(height);
let max_area_f = f64::from(max_area);
let height_f = (max_area_f / aspect_ratio).sqrt();
let width_f = height_f * aspect_ratio;
(width_f as u16, height_f as u16)
} else {
(width, height)
};
Rect {
x,
y,
width: clipped_width,
height: clipped_height,
}
}
pub fn area(self) -> u16 {
self.width * self.height
}
pub fn left(self) -> u16 {
self.x
}
pub fn right(self) -> u16 {
self.x.saturating_add(self.width)
}
pub fn top(self) -> u16 {
self.y
}
pub fn bottom(self) -> u16 {
self.y.saturating_add(self.height)
}
pub fn inner(self, margin: &Margin) -> Rect {
if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical {
Rect::default()
} else {
Rect {
x: self.x + margin.horizontal,
y: self.y + margin.vertical,
width: self.width - 2 * margin.horizontal,
height: self.height - 2 * margin.vertical,
}
}
}
pub fn union(self, other: Rect) -> Rect {
let x1 = min(self.x, other.x);
let y1 = min(self.y, other.y);
let x2 = max(self.x + self.width, other.x + other.width);
let y2 = max(self.y + self.height, other.y + other.height);
Rect {
x: x1,
y: y1,
width: x2 - x1,
height: y2 - y1,
}
}
pub fn intersection(self, other: Rect) -> Rect {
let x1 = max(self.x, other.x);
let y1 = max(self.y, other.y);
let x2 = min(self.x + self.width, other.x + other.width);
let y2 = min(self.y + self.height, other.y + other.height);
Rect {
x: x1,
y: y1,
width: x2 - x1,
height: y2 - y1,
}
}
pub fn intersects(self, other: Rect) -> bool {
self.x < other.x + other.width
&& self.x + self.width > other.x
&& self.y < other.y + other.height
&& self.y + self.height > other.y
}
pub fn inhere(&self, x: u16, y: u16) -> bool {
x >= self.x && x < self.x + self.width && y >= self.y && y < self.y + self.height
}
#[inline(always)]
pub(crate) fn start(&self, direction: Direction) -> f64 {
match direction {
Direction::Horizontal => self.x as f64,
Direction::Vertical => self.y as f64,
}
}
#[inline(always)]
pub(crate) fn end(&self, direction: Direction) -> f64 {
match direction {
Direction::Horizontal => (self.x + self.width) as f64,
Direction::Vertical => (self.y + self.height) as f64,
}
}
#[inline(always)]
pub(crate) fn size(&self, direction: Direction) -> f64 {
match direction {
Direction::Horizontal => self.width as f64,
Direction::Vertical => self.height as f64,
}
}
#[inline(always)]
pub(crate) fn cross_start(&self, direction: Direction) -> f64 {
match direction {
Direction::Horizontal => self.y as f64,
Direction::Vertical => self.x as f64,
}
}
#[inline(always)]
pub(crate) fn cross_end(&self, direction: Direction) -> f64 {
match direction {
Direction::Horizontal => (self.y + self.height) as f64,
Direction::Vertical => (self.x + self.width) as f64,
}
}
#[inline(always)]
pub(crate) fn cross_size(&self, direction: Direction) -> f64 {
match direction {
Direction::Horizontal => self.height as f64,
Direction::Vertical => self.width as f64,
}
}
}