use crate::{Abs, Pair, Scalar, Vector2, ZeroOneTwo};
pub trait Rectangle: Copy {
type Scalar: Scalar;
type Vector: Vector2<Scalar = Self::Scalar>;
fn new(top_left: Self::Vector, size: Self::Vector) -> Self;
fn top_left(self) -> Self::Vector;
fn size(self) -> Self::Vector;
fn square(top_left: Self::Vector, side_length: Self::Scalar) -> Self {
Self::new(top_left, Self::Vector::square(side_length))
}
fn centered(center: Self::Vector, size: Self::Vector) -> Self {
Self::new(center.sub(size.div(Self::Scalar::TWO)), size)
}
fn square_centered(center: Self::Vector, side_length: Self::Scalar) -> Self {
Self::centered(center, Self::Vector::square(side_length))
}
fn map_into<R>(self) -> R
where
R: Rectangle,
R::Scalar: From<Self::Scalar>,
{
R::new(
R::Vector::new(R::Scalar::from(self.left()), R::Scalar::from(self.top())),
R::Vector::new(
R::Scalar::from(self.width()),
R::Scalar::from(self.height()),
),
)
}
fn map_rect(self) -> [Self::Scalar; 4] {
self.map_into()
}
fn map_with<R, F>(self, mut f: F) -> R
where
R: Rectangle,
F: FnMut(Self::Scalar) -> <<R as Rectangle>::Vector as Vector2>::Scalar,
{
R::new(
R::Vector::new(f(self.left()), f(self.top())),
R::Vector::new(f(self.width()), f(self.height())),
)
}
fn abs_size(self) -> Self::Vector {
Self::Vector::new(self.size().x().abs(), self.size().y().abs())
}
fn top_right(self) -> Self::Vector {
Self::Vector::new(self.top_left().x() + self.size().x(), self.top_left().y())
}
fn bottom_left(self) -> Self::Vector {
Self::Vector::new(self.top_left().x(), self.top_left().y() + self.size().y())
}
fn bottom_right(self) -> Self::Vector {
self.top_left().add(self.size())
}
fn abs_top_left(self) -> Self::Vector {
let tl = self.top_left();
let size = self.size();
Self::Vector::new(
tl.x().minn(tl.x() + size.x()),
tl.y().minn(tl.y() + size.y()),
)
}
fn abs_top_right(self) -> Self::Vector {
Self::Vector::new(
self.abs_top_left().x() + self.abs_size().x(),
self.abs_top_left().y(),
)
}
fn abs_bottom_left(self) -> Self::Vector {
Self::Vector::new(
self.abs_top_left().x(),
self.abs_top_left().y() + self.abs_size().y(),
)
}
fn abs_bottom_right(self) -> Self::Vector {
self.abs_top_left().add(self.abs_size())
}
fn top(self) -> Self::Scalar {
self.top_left().y()
}
fn bottom(self) -> Self::Scalar {
self.top_left().y() + self.size().y()
}
fn left(self) -> Self::Scalar {
self.top_left().x()
}
fn right(self) -> Self::Scalar {
self.top_left().x() + self.size().x()
}
fn abs_top(self) -> Self::Scalar {
self.abs_top_left().y()
}
fn abs_bottom(self) -> Self::Scalar {
self.abs_top_left().y() + self.abs_size().y()
}
fn abs_left(self) -> Self::Scalar {
self.abs_top_left().x()
}
fn abs_right(self) -> Self::Scalar {
self.abs_top_left().x() + self.abs_size().x()
}
fn width(self) -> Self::Scalar {
self.size().x()
}
fn height(self) -> Self::Scalar {
self.size().y()
}
fn abs_width(self) -> Self::Scalar {
self.abs_size().x()
}
fn abs_height(self) -> Self::Scalar {
self.abs_size().y()
}
fn center(self) -> Self::Vector {
self.top_left().add(self.size().div(Self::Scalar::TWO))
}
fn with_top_left(self, top_left: Self::Vector) -> Self {
Self::new(top_left, self.size())
}
fn with_center(self, center: Self::Vector) -> Self {
Self::centered(center, self.size())
}
fn with_size(self, size: Self::Vector) -> Self {
Self::new(self.top_left(), size)
}
fn perimeter(self) -> Self::Scalar {
self.width() * Self::Scalar::TWO + self.height() * Self::Scalar::TWO
}
fn area(self) -> Self::Scalar {
self.width() * self.height()
}
fn translated(self, offset: Self::Vector) -> Self {
self.with_top_left(self.top_left().add(offset))
}
fn scaled(self, scale: Self::Scalar) -> Self {
self.with_size(self.size().mul(scale))
}
fn scaled2(self, scale: Self::Vector) -> Self {
self.with_size(self.size().mul2(scale))
}
fn corners(self) -> [Self::Vector; 4] {
[
self.top_left(),
self.top_right(),
self.bottom_right(),
self.bottom_left(),
]
}
fn contains(self, point: Self::Vector) -> bool {
let in_x_bounds = self.abs_left() <= point.x() && point.x() <= self.abs_right();
let in_y_bounds = || self.abs_top() <= point.y() && point.y() <= self.abs_bottom();
in_x_bounds && in_y_bounds()
}
fn contains_all<I>(self, points: I) -> bool
where
I: IntoIterator<Item = Self::Vector>,
{
points.into_iter().all(|point| self.contains(point))
}
fn contains_any<I>(self, points: I) -> bool
where
I: IntoIterator<Item = Self::Vector>,
{
points.into_iter().any(|point| self.contains(point))
}
fn bounding<I>(points: I) -> Option<Self>
where
I: IntoIterator<Item = Self::Vector>,
{
let mut points = points.into_iter();
if let Some(first) = points.next() {
let mut tl = first;
let mut br = first;
for point in points {
tl = Self::Vector::new(tl.x().minn(point.x()), tl.y().minn(point.y()));
br = Self::Vector::new(br.x().maxx(point.x()), br.y().maxx(point.y()));
}
Some(Self::new(tl, br.sub(tl)))
} else {
None
}
}
fn inner_margin(self, margin: Self::Scalar) -> Self {
self.inner_margins([margin; 4])
}
fn inner_margins(self, [left, right, top, bottom]: [Self::Scalar; 4]) -> Self {
Self::new(
self.abs_top_left().add(Self::Vector::new(left, top)),
self.abs_size()
.sub(Self::Vector::new(left + right, top + bottom)),
)
}
fn outer_margin(self, margin: Self::Scalar) -> Self {
self.outer_margins([margin; 4])
}
fn outer_margins(self, [left, right, top, bottom]: [Self::Scalar; 4]) -> Self {
Self::new(
self.abs_top_left().sub(Self::Vector::new(left, top)),
self.abs_size()
.add(Self::Vector::new(left + right, top + bottom)),
)
}
}
impl<P> Rectangle for P
where
P: Pair + Copy,
P::Item: Vector2,
{
type Scalar = <P::Item as Vector2>::Scalar;
type Vector = P::Item;
fn new(top_left: Self::Vector, size: Self::Vector) -> Self {
Self::from_items(top_left, size)
}
fn top_left(self) -> Self::Vector {
self.to_pair().0
}
fn size(self) -> Self::Vector {
self.to_pair().1
}
}