use core::ops::Neg;
use crate::geom::{Align, Edge, Point2, Quad, Range, Scalar, Tri, quad, scalar};
use crate::glam::{DVec2, Vec2};
use crate::math::{self, num_traits::Float};
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Rect<S = scalar::Default> {
pub x: Range<S>,
pub y: Range<S>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Padding<S = scalar::Default> {
pub x: Range<S>,
pub y: Range<S>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Corner {
TopLeft,
TopRight,
BottomLeft,
BottomRight,
}
#[derive(Clone)]
pub struct Subdivisions<S = scalar::Default> {
ranges: SubdivisionRanges<S>,
subdivision_index: u8,
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct SubdivisionRanges<S = scalar::Default> {
pub x_a: Range<S>,
pub x_b: Range<S>,
pub y_a: Range<S>,
pub y_b: Range<S>,
}
#[derive(Clone, Debug)]
pub struct Corners<S = scalar::Default> {
rect: Rect<S>,
index: u8,
}
pub type Triangles<S> = quad::Triangles<[S; 2]>;
pub const NUM_SUBDIVISIONS: u8 = 4;
pub const NUM_CORNERS: u8 = 4;
pub const NUM_TRIANGLES: u8 = 2;
impl<S> Padding<S>
where
S: Scalar,
{
pub fn none() -> Self {
Padding {
x: Range::new(S::zero(), S::zero()),
y: Range::new(S::zero(), S::zero()),
}
}
}
macro_rules! subdivision_from_index {
($ranges:expr,0) => {
Rect {
x: $ranges.x_a,
y: $ranges.y_a,
}
};
($ranges:expr,1) => {
Rect {
x: $ranges.x_b,
y: $ranges.y_a,
}
};
($ranges:expr,2) => {
Rect {
x: $ranges.x_a,
y: $ranges.y_b,
}
};
($ranges:expr,3) => {
Rect {
x: $ranges.x_b,
y: $ranges.y_b,
}
};
}
macro_rules! corner_from_index {
($rect:expr,0) => {
[$rect.x.start, $rect.y.end]
};
($rect:expr,1) => {
[$rect.x.end, $rect.y.end]
};
($rect:expr,2) => {
[$rect.x.end, $rect.y.start]
};
($rect:expr,3) => {
[$rect.x.start, $rect.y.start]
};
}
impl<S> Rect<S>
where
S: Scalar + Float,
{
pub fn from_x_y_w_h(x: S, y: S, w: S, h: S) -> Self {
Rect {
x: Range::from_pos_and_len(x, w),
y: Range::from_pos_and_len(y, h),
}
}
pub fn from_w_h(w: S, h: S) -> Self {
Self::from_x_y_w_h(S::zero(), S::zero(), w, h)
}
pub fn x(&self) -> S {
self.x.middle()
}
pub fn y(&self) -> S {
self.y.middle()
}
pub fn x_y(&self) -> (S, S) {
(self.x(), self.y())
}
pub fn x_y_w_h(&self) -> (S, S, S, S) {
let (x, y) = self.x_y();
let (w, h) = self.w_h();
(x, y, w, h)
}
pub fn align_x_of(self, align: Align, other: Self) -> Self {
Rect {
x: self.x.align_to(align, other.x),
y: self.y,
}
}
pub fn align_y_of(self, align: Align, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_to(align, other.y),
}
}
pub fn align_middle_x_of(self, other: Self) -> Self {
Rect {
x: self.x.align_middle_of(other.x),
y: self.y,
}
}
pub fn align_middle_y_of(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_middle_of(other.y),
}
}
pub fn mid_top_of(self, other: Self) -> Self {
self.align_middle_x_of(other).align_top_of(other)
}
pub fn mid_bottom_of(self, other: Self) -> Self {
self.align_middle_x_of(other).align_bottom_of(other)
}
pub fn mid_left_of(self, other: Self) -> Self {
self.align_left_of(other).align_middle_y_of(other)
}
pub fn mid_right_of(self, other: Self) -> Self {
self.align_right_of(other).align_middle_y_of(other)
}
pub fn middle_of(self, other: Self) -> Self {
self.align_middle_x_of(other).align_middle_y_of(other)
}
pub fn subdivision_ranges(&self) -> SubdivisionRanges<S> {
let (x, y) = self.x_y();
let x_a = Range::new(self.x.start, x);
let x_b = Range::new(x, self.x.end);
let y_a = Range::new(self.y.start, y);
let y_b = Range::new(y, self.y.end);
SubdivisionRanges { x_a, x_b, y_a, y_b }
}
pub fn subdivisions(&self) -> [Self; NUM_SUBDIVISIONS as usize] {
self.subdivision_ranges().rects()
}
pub fn subdivisions_iter(&self) -> Subdivisions<S> {
self.subdivision_ranges().rects_iter()
}
}
impl<S> Rect<S>
where
S: Scalar,
{
pub fn from_corner_points([ax, ay]: [S; 2], [bx, by]: [S; 2]) -> Self {
let (left, right) = if ax < bx { (ax, bx) } else { (bx, ax) };
let (bottom, top) = if ay < by { (ay, by) } else { (by, ay) };
Rect {
x: Range {
start: left,
end: right,
},
y: Range {
start: bottom,
end: top,
},
}
}
pub fn absolute(self) -> Self {
let x = self.x.absolute();
let y = self.y.absolute();
Rect { x, y }
}
pub fn overlap(self, other: Self) -> Option<Self> {
self.x
.overlap(other.x)
.and_then(|x| self.y.overlap(other.y).map(|y| Rect { x, y }))
}
pub fn max(self, other: Self) -> Self
where
S: Float,
{
Rect {
x: self.x.max(other.x),
y: self.y.max(other.y),
}
}
pub fn bottom(&self) -> S {
self.y.absolute().start
}
pub fn top(&self) -> S {
self.y.absolute().end
}
pub fn left(&self) -> S {
self.x.absolute().start
}
pub fn right(&self) -> S {
self.x.absolute().end
}
pub fn l_r_b_t(&self) -> (S, S, S, S) {
(self.left(), self.right(), self.bottom(), self.top())
}
pub fn shift_x(self, x: S) -> Self {
Rect {
x: self.x.shift(x),
..self
}
}
pub fn shift_y(self, y: S) -> Self {
Rect {
y: self.y.shift(y),
..self
}
}
pub fn left_of(self, other: Self) -> Self {
Rect {
x: self.x.align_before(other.x),
y: self.y,
}
}
pub fn right_of(self, other: Self) -> Self {
Rect {
x: self.x.align_after(other.x),
y: self.y,
}
}
pub fn below(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_before(other.y),
}
}
pub fn above(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_after(other.y),
}
}
pub fn align_left_of(self, other: Self) -> Self {
Rect {
x: self.x.align_start_of(other.x),
y: self.y,
}
}
pub fn align_right_of(self, other: Self) -> Self {
Rect {
x: self.x.align_end_of(other.x),
y: self.y,
}
}
pub fn align_bottom_of(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_start_of(other.y),
}
}
pub fn align_top_of(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_end_of(other.y),
}
}
pub fn top_left_of(self, other: Self) -> Self {
self.align_left_of(other).align_top_of(other)
}
pub fn top_right_of(self, other: Self) -> Self {
self.align_right_of(other).align_top_of(other)
}
pub fn bottom_left_of(self, other: Self) -> Self {
self.align_left_of(other).align_bottom_of(other)
}
pub fn bottom_right_of(self, other: Self) -> Self {
self.align_right_of(other).align_bottom_of(other)
}
pub fn contains_point(self, [x, y]: [S; 2]) -> bool {
self.x.contains(x) && self.y.contains(y)
}
pub fn stretch_to_point(self, [px, py]: [S; 2]) -> Self {
let Rect { x, y } = self;
Rect {
x: x.stretch_to_value(px),
y: y.stretch_to_value(py),
}
}
pub fn closest_corner(&self, [x, y]: [S; 2]) -> Corner {
let x_edge = self.x.closest_edge(x);
let y_edge = self.y.closest_edge(y);
match (x_edge, y_edge) {
(Edge::Start, Edge::Start) => Corner::BottomLeft,
(Edge::Start, Edge::End) => Corner::TopLeft,
(Edge::End, Edge::Start) => Corner::BottomRight,
(Edge::End, Edge::End) => Corner::TopRight,
}
}
pub fn corners(&self) -> Quad<[S; 2]> {
Quad::from([
corner_from_index!(self, 0),
corner_from_index!(self, 1),
corner_from_index!(self, 2),
corner_from_index!(self, 3),
])
}
pub fn corners_iter(&self) -> Corners<S> {
let rect = *self;
let index = 0;
Corners { rect, index }
}
pub fn triangles(&self) -> (Tri<[S; 2]>, Tri<[S; 2]>) {
self.corners().triangles()
}
pub fn triangles_iter(self) -> Triangles<S> {
self.corners().triangles_iter()
}
pub fn corner_at_index(&self, index: u8) -> Option<[S; 2]> {
match index {
0 => Some(corner_from_index!(self, 0)),
1 => Some(corner_from_index!(self, 1)),
2 => Some(corner_from_index!(self, 2)),
3 => Some(corner_from_index!(self, 3)),
_ => None,
}
}
}
impl Rect<f32> {
pub fn from_xy_wh(p: Point2, s: Vec2) -> Self {
Self::from_x_y_w_h(p.x, p.y, s.x, s.y)
}
pub fn from_wh(s: Vec2) -> Self {
Self::from_w_h(s.x, s.y)
}
pub fn from_corners(a: Point2, b: Point2) -> Self {
Self::from_corner_points(a.into(), b.into())
}
pub fn xy(&self) -> Point2 {
[self.x(), self.y()].into()
}
pub fn wh(&self) -> Vec2 {
[self.w(), self.h()].into()
}
pub fn xy_wh(&self) -> (Point2, Vec2) {
(self.xy(), self.wh())
}
pub fn top_left(&self) -> Point2 {
[self.left(), self.top()].into()
}
pub fn bottom_left(&self) -> Point2 {
[self.left(), self.bottom()].into()
}
pub fn top_right(&self) -> Point2 {
[self.right(), self.top()].into()
}
pub fn bottom_right(&self) -> Point2 {
[self.right(), self.bottom()].into()
}
pub fn mid_left(&self) -> Point2 {
[self.left(), self.y()].into()
}
pub fn mid_top(&self) -> Point2 {
[self.x(), self.top()].into()
}
pub fn mid_right(&self) -> Point2 {
[self.right(), self.y()].into()
}
pub fn mid_bottom(&self) -> Point2 {
[self.x(), self.bottom()].into()
}
pub fn shift(self, v: Vec2) -> Self {
self.shift_x(v.x).shift_y(v.y)
}
pub fn contains(&self, p: Point2) -> bool {
self.contains_point(p.into())
}
pub fn stretch_to(self, p: Point2) -> Self {
self.stretch_to_point(p.into())
}
}
impl Rect<f64> {
pub fn from_xy_wh_f64(p: DVec2, s: DVec2) -> Self {
Self::from_x_y_w_h(p.x, p.y, s.x, s.y)
}
pub fn from_wh_f64(s: DVec2) -> Self {
Self::from_w_h(s.x, s.y)
}
pub fn from_corners_f64(a: DVec2, b: DVec2) -> Self {
Self::from_corner_points(a.into(), b.into())
}
pub fn xy(&self) -> DVec2 {
[self.x(), self.y()].into()
}
pub fn wh(&self) -> DVec2 {
[self.w(), self.h()].into()
}
pub fn xy_wh(&self) -> (DVec2, DVec2) {
(self.xy(), self.wh())
}
pub fn top_left(&self) -> DVec2 {
[self.left(), self.top()].into()
}
pub fn bottom_left(&self) -> DVec2 {
[self.left(), self.bottom()].into()
}
pub fn top_right(&self) -> DVec2 {
[self.right(), self.top()].into()
}
pub fn bottom_right(&self) -> DVec2 {
[self.right(), self.bottom()].into()
}
pub fn mid_left(&self) -> DVec2 {
[self.left(), self.y()].into()
}
pub fn mid_top(&self) -> DVec2 {
[self.x(), self.top()].into()
}
pub fn mid_right(&self) -> DVec2 {
[self.right(), self.y()].into()
}
pub fn mid_bottom(&self) -> DVec2 {
[self.x(), self.bottom()].into()
}
pub fn shift(self, v: DVec2) -> Self {
self.shift_x(v.x).shift_y(v.y)
}
pub fn contains(&self, p: DVec2) -> bool {
self.contains_point(p.into())
}
pub fn stretch_to(self, p: DVec2) -> Self {
self.stretch_to_point(p.into())
}
}
impl<S> SubdivisionRanges<S>
where
S: Copy,
{
pub fn rects(&self) -> [Rect<S>; NUM_SUBDIVISIONS as usize] {
let r1 = subdivision_from_index!(self, 0);
let r2 = subdivision_from_index!(self, 1);
let r3 = subdivision_from_index!(self, 2);
let r4 = subdivision_from_index!(self, 3);
[r1, r2, r3, r4]
}
pub fn rects_iter(self) -> Subdivisions<S> {
Subdivisions {
ranges: self,
subdivision_index: 0,
}
}
fn subdivision_at_index(&self, index: u8) -> Option<Rect<S>> {
let rect = match index {
0 => subdivision_from_index!(self, 0),
1 => subdivision_from_index!(self, 1),
2 => subdivision_from_index!(self, 2),
3 => subdivision_from_index!(self, 3),
_ => return None,
};
Some(rect)
}
}
impl<S> Rect<S>
where
S: Scalar + Neg<Output = S>,
{
pub fn w(&self) -> S {
self.x.len()
}
pub fn h(&self) -> S {
self.y.len()
}
pub fn w_h(&self) -> (S, S) {
(self.w(), self.h())
}
pub fn len(&self) -> S {
math::partial_max(self.w(), self.h())
}
pub fn l_t_w_h(&self) -> (S, S, S, S) {
let (w, h) = self.w_h();
(self.left(), self.top(), w, h)
}
pub fn l_b_w_h(&self) -> (S, S, S, S) {
let (w, h) = self.w_h();
(self.left(), self.bottom(), w, h)
}
pub fn pad_left(self, pad: S) -> Self {
Rect {
x: self.x.pad_start(pad),
..self
}
}
pub fn pad_right(self, pad: S) -> Self {
Rect {
x: self.x.pad_end(pad),
..self
}
}
pub fn pad_bottom(self, pad: S) -> Self {
Rect {
y: self.y.pad_start(pad),
..self
}
}
pub fn pad_top(self, pad: S) -> Self {
Rect {
y: self.y.pad_end(pad),
..self
}
}
pub fn pad(self, pad: S) -> Self {
let Rect { x, y } = self;
Rect {
x: x.pad(pad),
y: y.pad(pad),
}
}
pub fn padding(self, padding: Padding<S>) -> Self {
Rect {
x: self.x.pad_ends(padding.x.start, padding.x.end),
y: self.y.pad_ends(padding.y.start, padding.y.end),
}
}
pub fn relative_to_x(self, x: S) -> Self {
Rect {
x: self.x.shift(-x),
..self
}
}
pub fn relative_to_y(self, y: S) -> Self {
Rect {
y: self.y.shift(-y),
..self
}
}
pub fn relative_to(self, [x, y]: [S; 2]) -> Self {
self.relative_to_x(x).relative_to_y(y)
}
pub fn invert_x(self) -> Self {
Rect {
x: self.x.invert(),
..self
}
}
pub fn invert_y(self) -> Self {
Rect {
y: self.y.invert(),
..self
}
}
}
impl<S> Iterator for Subdivisions<S>
where
S: Copy,
{
type Item = Rect<S>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(sd) = self.ranges.subdivision_at_index(self.subdivision_index) {
self.subdivision_index += 1;
return Some(sd);
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<S> DoubleEndedIterator for Subdivisions<S>
where
S: Copy,
{
fn next_back(&mut self) -> Option<Self::Item> {
let next_index = self.subdivision_index + 1;
if let Some(sd) = self
.ranges
.subdivision_at_index(NUM_SUBDIVISIONS - next_index)
{
self.subdivision_index = next_index;
return Some(sd);
}
None
}
}
impl<S> ExactSizeIterator for Subdivisions<S>
where
S: Copy,
{
fn len(&self) -> usize {
NUM_SUBDIVISIONS as usize - self.subdivision_index as usize
}
}
impl<S> Iterator for Corners<S>
where
S: Scalar,
{
type Item = [S; 2];
fn next(&mut self) -> Option<Self::Item> {
if let Some(corner) = self.rect.corner_at_index(self.index) {
self.index += 1;
return Some(corner);
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<S> DoubleEndedIterator for Corners<S>
where
S: Scalar,
{
fn next_back(&mut self) -> Option<Self::Item> {
let next_index = self.index + 1;
if let Some(corner) = self.rect.corner_at_index(NUM_CORNERS - next_index) {
self.index = next_index;
return Some(corner);
}
None
}
}
impl<S> ExactSizeIterator for Corners<S>
where
S: Scalar,
{
fn len(&self) -> usize {
(NUM_CORNERS - self.index) as usize
}
}