use crate::geom::{quad, scalar, Align, Edge, Point2, Quad, Range, Tri, Vector2};
use crate::math::num_traits::Float;
use crate::math::{self, BaseNum};
use std::ops::Neg;
#[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<Point2<S>>;
pub const NUM_SUBDIVISIONS: u8 = 4;
pub const NUM_CORNERS: u8 = 4;
pub const NUM_TRIANGLES: u8 = 2;
impl<S> Padding<S>
where
S: BaseNum,
{
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.top_left()
};
($rect:expr,1) => {
$rect.top_right()
};
($rect:expr,2) => {
$rect.bottom_right()
};
($rect:expr,3) => {
$rect.bottom_left()
};
}
impl<S> Rect<S>
where
S: BaseNum,
{
pub fn from_xy_wh(p: Point2<S>, wh: Vector2<S>) -> Self {
Rect {
x: Range::from_pos_and_len(p.x, wh.x),
y: Range::from_pos_and_len(p.y, wh.y),
}
}
pub fn from_x_y_w_h(x: S, y: S, w: S, h: S) -> Self {
Rect::from_xy_wh(Point2 { x, y }, Vector2 { x: w, y: h })
}
pub fn from_wh(wh: Vector2<S>) -> Self {
let p = Point2 {
x: S::zero(),
y: S::zero(),
};
Self::from_xy_wh(p, wh)
}
pub fn from_w_h(w: S, h: S) -> Self {
Self::from_wh(Vector2 { x: w, y: h })
}
pub fn from_corners(a: Point2<S>, b: Point2<S>) -> Self {
let (left, right) = if a.x < b.x { (a.x, b.x) } else { (b.x, a.x) };
let (bottom, top) = if a.y < b.y { (a.y, b.y) } else { (b.y, a.y) };
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: x, y: 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 x(&self) -> S {
self.x.middle()
}
pub fn y(&self) -> S {
self.y.middle()
}
pub fn xy(&self) -> Point2<S> {
[self.x(), self.y()].into()
}
pub fn x_y(&self) -> (S, S) {
(self.x(), self.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 top_left(&self) -> Point2<S> {
[self.left(), self.top()].into()
}
pub fn bottom_left(&self) -> Point2<S> {
[self.left(), self.bottom()].into()
}
pub fn top_right(&self) -> Point2<S> {
[self.right(), self.top()].into()
}
pub fn bottom_right(&self) -> Point2<S> {
[self.right(), self.bottom()].into()
}
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 shift(self, v: Vector2<S>) -> Self {
self.shift_x(v.x).shift_y(v.y)
}
pub fn contains(&self, p: Point2<S>) -> bool {
self.x.contains(p.x) && self.y.contains(p.y)
}
pub fn stretch_to_point(self, p: Point2<S>) -> Self {
let Rect { x, y } = self;
Rect {
x: x.stretch_to_value(p.x),
y: y.stretch_to_value(p.y),
}
}
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.x),
}
}
pub fn above(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_after(other.x),
}
}
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_left_of(self, other: Self) -> Self {
Rect {
x: self.x.align_start_of(other.x),
y: self.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_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_middle_y_of(self, other: Self) -> Self {
Rect {
x: self.x,
y: self.y.align_middle_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 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 closest_corner(&self, p: Point2<S>) -> Corner {
let x_edge = self.x.closest_edge(p.x);
let y_edge = self.y.closest_edge(p.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<Point2<S>> {
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<Point2<S>>, Tri<Point2<S>>) {
self.corners().triangles()
}
pub fn triangles_iter(self) -> Triangles<S> {
self.corners().triangles_iter()
}
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()
}
pub fn corner_at_index(&self, index: u8) -> Option<Point2<S>> {
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<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: BaseNum + Neg<Output = S>,
{
pub fn w(&self) -> S {
self.x.len()
}
pub fn h(&self) -> S {
self.y.len()
}
pub fn wh(&self) -> Vector2<S> {
[self.w(), self.h()].into()
}
pub fn w_h(&self) -> (S, S) {
(self.w(), self.h())
}
pub fn xy_wh(&self) -> (Point2<S>, Vector2<S>) {
(self.xy(), self.wh())
}
pub fn x_y_w_h(&self) -> (S, S, S, S) {
let (xy, wh) = self.xy_wh();
(xy[0], xy[1], wh[0], wh[1])
}
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, p: Point2<S>) -> Self {
self.relative_to_x(p.x).relative_to_y(p.y)
}
}
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: BaseNum,
{
type Item = Point2<S>;
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: BaseNum,
{
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: BaseNum,
{
fn len(&self) -> usize {
(NUM_CORNERS - self.index) as usize
}
}