use crate::range::Range;
use crate::vec2::vec2;
use crate::*;
use core::convert::TryInto;
#[inline(always)]
#[must_use]
pub fn rect<T>(xstart: T, xend: T, ystart: T, yend: T) -> Rect<T> {
Rect::new(xstart, xend, ystart, yend)
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(C)]
#[must_use]
pub struct Rect<T> {
pub x: Range<T>,
pub y: Range<T>,
}
impl<S> Rect<S> {
#[inline(always)]
pub fn inner_into<A>(self) -> Rect<A> where S:Into<A> {
let x = self.x.inner_into();
let y = self.y.inner_into();
Rect { x, y }
}
#[inline(always)]
#[must_use]
pub fn inner_try_into<A>(self) -> Result<Rect<A>, S::Error> where S:TryInto<A> {
let x = self.x.inner_try_into();
let y = self.y.inner_try_into();
match (x, y) {
(Ok(x), Ok(y)) => Ok(Rect { x, y }),
(Ok(_), Err(e)) => Err(e),
(Err(e), Ok(_)) => Err(e),
(Err(e1), Err(_)) => Err(e1),
}
}
}
impl<T: Copy + core::ops::Sub<Output = T> + core::ops::Add<Output = T>> Rect<T> {
#[inline(always)]
#[must_use]
pub fn from_point(point: Vec2<T>, radius: Vec2<T>) -> Rect<T> {
let x = Range::from_point(point.x, radius.x);
let y = Range::from_point(point.y, radius.y);
Rect { x, y }
}
}
impl<B> From<[B;4]> for Rect<B>{
#[inline(always)]
fn from(a:[B;4])->Self{
let [a,b,c,d]=a;
Rect::new(a,b,c,d)
}
}
impl<B> From<Rect<B>> for [B;4]{
#[inline(always)]
fn from(a:Rect<B>)->Self{
[a.x.start,a.x.end,a.y.start,a.y.end]
}
}
impl<B:Copy> From<&Rect<B>> for [B;4]{
#[inline(always)]
fn from(a:&Rect<B>)->Self{
[a.x.start,a.x.end,a.y.start,a.y.end]
}
}
impl<T> Rect<T> {
#[inline(always)]
#[must_use]
pub fn get_range(&self, axis: impl Axis) -> &Range<T> {
if axis.is_xaxis() {
&self.x
} else {
&self.y
}
}
#[inline(always)]
#[must_use]
pub fn get_range_mut(&mut self, axis: impl Axis) -> &mut Range<T> {
if axis.is_xaxis() {
&mut self.x
} else {
&mut self.y
}
}
}
impl<T> Rect<T> {
#[inline(always)]
#[must_use]
pub fn new(xstart: T, xend: T, ystart: T, yend: T) -> Rect<T> {
Rect {
x: Range { start: xstart, end: xend },
y: Range { start: ystart, end: yend },
}
}
}
impl<T: Copy> Rect<T> {
#[inline(always)]
pub fn top_left(&self) -> Vec2<T> {
vec2(self.x.start, self.y.start)
}
#[inline(always)]
pub fn get_corners(&self) -> [Vec2<T>; 4] {
[
vec2(self.x.start, self.y.start),
vec2(self.x.end, self.y.start),
vec2(self.x.end, self.y.end),
vec2(self.x.start, self.y.end),
]
}
#[inline(always)]
pub fn inner_as<B:'static+Copy>(&self) -> Rect<B> where T: num_traits::AsPrimitive<B>{
Rect {
x: self.x.inner_as(),
y: self.y.inner_as(),
}
}
#[inline(always)]
pub fn get(&self) -> ((T, T), (T, T)) {
let f = self;
((f.x.start, f.x.end), (f.y.start, f.y.end))
}
}
impl<T: PartialOrd + Copy> Rect<T> {
#[inline(always)]
pub fn contains_point(&self, a: Vec2<T>) -> bool {
self.x.contains(a.x) && self.y.contains(a.y)
}
}
impl<T: Copy + core::ops::Sub<Output = T> + core::ops::Add<Output = T>> Rect<T> {
#[inline(always)]
#[must_use]
pub fn grow(self, radius: T) -> Self {
Rect{
x:self.x.grow(radius),
y:self.y.grow(radius)
}
}
}
impl<
T: Copy
+ PartialOrd
+ core::ops::Sub<Output = T>
+ core::ops::Mul<Output = T>
+ core::ops::Add<Output = T>,
> Rect<T>
{
#[inline(always)]
pub fn distance_squared_to_point(&self, point: Vec2<T>) -> Option<T> {
let (px, py) = (point.x, point.y);
let ((a, b), (c, d)) = self.get();
let xx = num_traits::clamp(px, a, b);
let yy = num_traits::clamp(py, c, d);
let dis = (xx - px) * (xx - px) + (yy - py) * (yy - py);
if xx > a && xx < b && yy > c && yy < d {
None
} else {
Some(dis)
}
}
#[inline(always)]
pub fn furthest_distance_squared_to_point(&self, point: Vec2<T>) -> T {
let (px, py) = (point.x, point.y);
let ((a, b), (c, d)) = self.get();
fn reverse_clamp<N:PartialOrd+core::ops::Sub<Output=N>+Copy>(px:N,a:N,b:N)->N{
let aa=px-a;
let bb=b-px;
if bb>aa{
b
}else{
a
}
}
let xx = reverse_clamp(px, a, b);
let yy = reverse_clamp(py, c, d);
(xx - px) * (xx - px) + (yy - py) * (yy - py)
}
}
impl<T: num_traits::Num + Copy> Rect<T> {
#[inline(always)]
pub fn derive_center(&self) -> Vec2<T> {
let two = T::one() + T::one();
let ((a, b), (c, d)) = self.get();
vec2(a + (b - a) / two, c + (d - c) / two)
}
}
impl<T: PartialOrd + Copy> Rect<T> {
#[inline(always)]
pub fn subdivide<A: Axis>(&self, axis: A, divider: T) -> (Rect<T>, Rect<T>) {
let ca = axis;
let na = axis.next();
let rel = self.get_range(ca);
let carry_thru = *self.get_range(na);
let (l, r) = rel.subdivide(divider);
if axis.is_xaxis() {
(
Rect {
x: l,
y: carry_thru,
},
Rect {
x: r,
y: carry_thru,
},
)
} else {
(
Rect {
x: carry_thru,
y: l,
},
Rect {
x: carry_thru,
y: r,
},
)
}
}
#[inline(always)]
pub fn is_valid(&self) -> bool {
self.x.is_valid() && self.y.is_valid()
}
#[inline(always)]
pub fn contains_rect(&self, rect: &Rect<T>) -> bool {
self.x.contains_range(&rect.x) && self.y.contains_range(&rect.y)
}
#[inline(always)]
pub fn grow_to_fit_point(&mut self,point:Vec2<T>)->&mut Self{
if point.x<self.x.start{
self.x.start=point.x
}else if self.x.end<point.x{
self.x.end=point.x
}
if point.y<self.y.start{
self.y.start=point.y
}else if self.y.end<point.y{
self.y.end=point.y
}
self
}
#[inline(always)]
pub fn grow_to_fit(&mut self, rect: &Rect<T>) -> &mut Self {
{
macro_rules! macro_axis {
($axis:ident) => {{
let sx = self.get_range_mut($axis);
let rx = rect.get_range($axis);
sx.grow_to_fit(rx);
}};
}
macro_axis!(XAXIS);
macro_axis!(YAXIS);
}
self
}
#[inline(always)]
pub fn intersects_rect(&self, other: &Rect<T>) -> bool {
other.x.intersects(&self.x) && other.y.intersects(&self.y)
}
}
impl<T: PartialOrd + Copy> Rect<T> {
#[inline(always)]
pub fn get_intersect_rect(&self, other: &Rect<T>) -> Option<Rect<T>> {
macro_rules! macro_axis {
($axis:ident) => {{
let xr = other.get_range($axis);
let xf = self.get_range($axis);
let range = Range {
start: partial_min_max::max(xr.start,xf.start),
end: partial_min_max::min(xr.end,xf.end),
};
if range.end <= range.start {
return None;
}
range
}};
}
let x = macro_axis!(XAXIS);
let y = macro_axis!(YAXIS);
Some(Rect { x, y })
}
}