use std::ops::{Add, Div, Mul, Range, Sub};
use crate::{CompArithm, Padding, RangeExt, Two, Vec2, Zero};
pub trait RectExt: Sized {
type Val: Copy
+ Add<Output = Self::Val>
+ Sub<Output = Self::Val>
+ PartialOrd;
fn from_pos_size(
pos: impl Into<Vec2<Self::Val>>,
size: impl Into<Vec2<Self::Val>>,
) -> Self;
fn width(&self) -> Self::Val;
fn height(&self) -> Self::Val;
fn x(&self) -> Self::Val;
fn y(&self) -> Self::Val;
fn set_width(&mut self, w: Self::Val);
fn set_height(&mut self, h: Self::Val);
fn set_x(&mut self, x: Self::Val);
fn set_y(&mut self, y: Self::Val);
fn from_ranges(
lr: impl Into<Range<Self::Val>>,
tb: impl Into<Range<Self::Val>>,
) -> Self {
let lr = lr.into();
let tb = tb.into();
Self::from_pos_size((lr.start, tb.start), (lr.size(), tb.size()))
}
fn from_points(
a: impl Into<Vec2<Self::Val>>,
b: impl Into<Vec2<Self::Val>>,
) -> Self {
let a = a.into();
let b = b.into();
Self::from_ranges(
Vec2::new(a.x, b.x).sorted(),
Vec2::new(a.y, b.y).sorted(),
)
}
fn pos(&self) -> Vec2<Self::Val> {
Vec2::new(self.x(), self.y())
}
fn size(&self) -> Vec2<Self::Val> {
Vec2::new(self.width(), self.height())
}
fn left(&self) -> Self::Val {
self.x()
}
fn top(&self) -> Self::Val {
self.y()
}
fn right(&self) -> Self::Val {
self.x() + self.width()
}
fn bottom(&self) -> Self::Val {
self.y() + self.height()
}
fn top_left(&self) -> Vec2<Self::Val> {
self.pos()
}
fn top_right(&self) -> Vec2<Self::Val> {
Vec2::new(self.right(), self.top())
}
fn bot_right(&self) -> Vec2<Self::Val> {
self.pos() + self.size()
}
fn bot_left(&self) -> Vec2<Self::Val> {
Vec2::new(self.left(), self.bottom())
}
fn xrange(&self) -> Range<Self::Val> {
self.left()..self.right()
}
fn yrange(&self) -> Range<Self::Val> {
self.top()..self.bottom()
}
fn center(&self) -> Vec2<Self::Val>
where
Self::Val: Div<Output = Self::Val> + Two,
{
self.pos() + self.size() / Self::Val::TWO
}
fn pad_rect(&self, padding: impl Into<Padding<Self::Val>>) -> Self
where
Self::Val: PartialOrd + Zero,
{
let p = padding.into();
Self::from_pos_size(
self.pos() + p.offset(),
self.size().cjoin(p.size(), |s, p| {
if p >= s { Self::Val::ZERO } else { s - p }
}),
)
}
fn extend_rect(&self, margin: impl Into<Padding<Self::Val>>) -> Self {
let m = margin.into();
Self::from_pos_size(self.pos() - m.offset(), self.size() + m.size())
}
fn bound_join(&self, other: impl Into<Self>) -> Self {
let o = other.into();
Self::from_ranges(
self.xrange().join_gap(o.xrange()),
self.yrange().join_gap(o.yrange()),
)
}
fn intersect(&self, other: impl Into<Self>) -> Self {
let o = other.into();
Self::from_ranges(
self.xrange().intersect(o.xrange()),
self.yrange().intersect(o.yrange()),
)
}
fn move_to(&mut self, pos: impl Into<Vec2<Self::Val>>) -> &mut Self {
let pos = pos.into();
self.set_x(pos.x);
self.set_y(pos.y);
self
}
fn encloses(&self, other: &Self) -> bool {
self.xrange().encloses(other.xrange())
&& self.yrange().encloses(other.yrange())
}
fn contains(&self, point: impl Into<Vec2<Self::Val>>) -> bool {
let p = point.into();
self.xrange().contains(&p.x) && self.yrange().contains(&p.y)
}
fn intersects(&self, other: &Self) -> bool {
self.xrange().intersects(other.xrange())
&& self.yrange().intersects(other.yrange())
}
fn area(&self) -> Self::Val
where
Self::Val: Mul<Output = Self::Val>,
{
self.size().prod()
}
fn is_empty(&self) -> bool
where
Self::Val: PartialEq + Zero,
{
self.width() == Self::Val::ZERO || self.height() == Self::Val::ZERO
}
fn clamp(&self, pt: impl Into<Vec2<Self::Val>>) -> Vec2<Self::Val> {
let pt = pt.into();
let x = self.xrange().clamp(pt.x);
let y = self.yrange().clamp(pt.y);
Vec2::new(x, y)
}
fn set_pos(&mut self, pos: impl Into<Vec2<Self::Val>>) {
let s = pos.into();
self.set_x(s.x);
self.set_y(s.y);
}
fn set_size(&mut self, size: impl Into<Vec2<Self::Val>>) {
let s = size.into();
self.set_width(s.x);
self.set_height(s.y);
}
fn extend_bot(&mut self, amt: Self::Val) {
self.set_height(self.height() + amt);
}
fn extend_right(&mut self, amt: Self::Val) {
self.set_width(self.width() + amt);
}
fn extend_left(&mut self, amt: Self::Val) {
self.set_width(self.width() + amt);
self.set_x(self.x() - amt);
}
fn extend_top(&mut self, amt: Self::Val) {
self.set_height(self.height() + amt);
self.set_y(self.y() - amt);
}
}