use super::*;
use crate::vector::{ Vec2, Axis2::{ self, X, Y } };
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Side2 {
Top,
Bottom,
Left,
Right
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub struct Rect2<T: Scalar>(pub Vec2<T>, pub Vec2<T>);
impl <T: Scalar> RectAbstract<T, Vec2<T>, Rect2<T>> for Rect2<T> {}
impl <T: Scalar> Rect<T, Vec2<T>, Rect2<T>, Axis2, Side2> for Rect2<T> {
fn new(position: Vec2<T>, size: Vec2<T>) -> Rect2<T> {
Rect2(position, size)
}
fn encompass_points(points: &[Vec2<T>]) -> Rect2<T> {
let top: T = points.iter().map(|p| p[Y]).reduce(T::min).unwrap();
let bottom: T = points.iter().map(|p| p[Y]).reduce(T::max).unwrap();
let left: T = points.iter().map(|p| p[X]).reduce(T::min).unwrap();
let right: T = points.iter().map(|p| p[X]).reduce(T::max).unwrap();
Rect2::from_offsets(left, top, right, bottom)
}
fn identity(&self) -> &Rect2<T> {
self
}
fn position(&self) -> Vec2<T> {
self.0
}
fn position_mut(&mut self) -> &mut Vec2<T> {
&mut self.0
}
fn size(&self) -> Vec2<T> {
self.1
}
fn size_mut(&mut self) -> &mut Vec2<T> {
&mut self.1
}
fn set_position(&mut self, position: Vec2<T>) {
self.0 = position;
}
fn set_size(&mut self, size: Vec2<T>) {
self.1 = size;
}
fn vertex(&self, idx: usize) -> Vec2<T> {
match idx {
0 => self.position(),
1 => self.position() + &self.size().of_x(),
2 => self.position() + self.size(),
3 => self.position() + &self.size().of_y(),
_ => panic!("Vertex index out of bounds.")
}
}
fn longest_axis(&self) -> Axis2 {
if self.size()[Y] > self.size()[X] {
return Y;
}
X
}
fn shortest_axis(&self) -> Axis2 {
if self.size()[Y] < self.size()[X] {
return Y;
}
X
}
fn axis_length(&self, axis: Axis2) -> T {
self.size()[axis]
}
fn expand_to_include(&self, point: Vec2<T>) -> Rect2<T> {
let mut origin: Vec2<T> = self.position();
let mut end: Vec2<T> = self.end();
if point[X] < origin[X] {
origin[X] = point[X];
}
if point[Y] < origin[Y] {
origin[Y] = point[Y];
}
if point[X] > end[X] {
end[X] = point[X];
}
if point[Y] > end[Y] {
end[Y] = point[Y];
}
Rect2(origin, end)
}
fn grow_side(&self, side: Side2, amount: T) -> Rect2<T> {
match side {
Side2::Top => Rect2(self.0 - Vec2::on_y(amount), self.1 + Vec2::on_y(amount)),
Side2::Bottom => Rect2(self.0, self.1 + Vec2::on_y(amount)),
Side2::Left => Rect2(self.0 - Vec2::on_x(amount), self.1 + Vec2::on_x(amount)),
Side2::Right => Rect2(self.0, self.1 + Vec2::on_x(amount))
}
}
fn intersects(&self, other: &Rect2<T>, including_borders: bool) -> bool {
if including_borders {
if self.position()[X] > other.position()[X] + other.size()[X] {
return false;
}
if self.position()[X] + self.size()[X] < other.position()[X] {
return false;
}
if self.position()[Y] > other.position()[Y] + other.size()[Y] {
return false;
}
if self.position()[Y] + self.size()[Y] < other.position()[Y] {
return false;
}
} else {
if self.position()[X] >= other.position()[X] + other.size()[X] {
return false;
}
if self.position()[X] + self.size()[X] <= other.position()[X] {
return false;
}
if self.position()[Y] >= other.position()[Y] + other.size()[Y] {
return false;
}
if self.position()[Y] + self.size()[Y] <= other.position()[Y] {
return false;
}
}
true
}
}
impl <T: SignedScalar> SignedRect<T, Vec2<T>, Rect2<T>, Axis2, Side2, T> for Rect2<T> {}
impl <T: FloatScalar> FloatRect<T, Vec2<T>, Rect2<T>, Axis2, Side2, T> for Rect2<T> {}
impl <T: Scalar> Rect2<T> {
pub fn from_offsets(left: T, top: T, right: T, bottom: T) -> Rect2<T> {
Rect2(Vec2(left, top), Vec2(right - left, bottom - top))
}
pub fn from_components(x: T, y: T, width: T, height: T) -> Rect2<T> {
Rect2(Vec2(x, y), Vec2(width, height))
}
pub fn cast<U: Scalar>(&self) -> Option<Rect2<U>> {
match (self.0.cast(), self.1.cast()) {
(Some(position), Some(dimensions)) => Some(Rect2(position, dimensions)),
_ => None
}
}
pub fn x(&self) -> T {
self.0[X]
}
pub fn y(&self) -> T {
self.0[Y]
}
pub fn width(&self) -> T {
self.1[X]
}
pub fn height(&self) -> T {
self.1[Y]
}
}
impl <T: Scalar> Default for Rect2<T> {
fn default() -> Self {
Rect2(Vec2::default(), Vec2::default())
}
}
impl <T: Scalar> Display for Rect2<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Rect2({}, {})", self.0, self.1)
}
}