use crate::{point::point_traits::*, PointN};
use core::ops::{Add, AddAssign, Mul, Sub, SubAssign};
use num::Zero;
use serde::{Deserialize, Serialize};
pub type Extent2<T> = ExtentN<[T; 2]>;
pub type Extent2i = ExtentN<[i32; 2]>;
pub type Extent2f = ExtentN<[f32; 2]>;
pub type Extent3<T> = ExtentN<[T; 3]>;
pub type Extent3i = ExtentN<[i32; 3]>;
pub type Extent3f = ExtentN<[f32; 3]>;
#[derive(Debug, Deserialize, Eq, Serialize)]
pub struct ExtentN<N> {
pub minimum: PointN<N>,
pub shape: PointN<N>,
}
impl<N> Clone for ExtentN<N>
where
PointN<N>: Clone,
{
#[inline]
fn clone(&self) -> Self {
Self {
minimum: self.minimum.clone(),
shape: self.shape.clone(),
}
}
}
impl<N> Copy for ExtentN<N> where PointN<N>: Copy {}
impl<N> PartialEq for ExtentN<N>
where
PointN<N>: PartialEq,
{
#[allow(clippy::missing_inline_in_public_items)]
fn eq(&self, other: &Self) -> bool {
self.minimum.eq(&other.minimum) && self.shape.eq(&other.shape)
}
}
impl<N> ExtentN<N> {
#[inline]
pub fn from_min_and_shape(minimum: PointN<N>, shape: PointN<N>) -> Self {
Self { minimum, shape }
}
}
impl<N> ExtentN<N>
where
PointN<N>: Point,
{
#[inline]
pub fn volume(&self) -> <PointN<N> as Point>::Scalar {
self.shape.volume()
}
#[inline]
pub fn with_minimum(&self, new_min: PointN<N>) -> Self {
Self::from_min_and_shape(new_min, self.shape)
}
#[inline]
pub fn least_upper_bound(&self) -> PointN<N> {
self.minimum + self.shape
}
#[inline]
pub fn contains(&self, p: PointN<N>) -> bool {
let lub = self.least_upper_bound();
self.minimum <= p && p < lub
}
#[inline]
pub fn add_to_shape(&self, delta: PointN<N>) -> Self {
Self::from_min_and_shape(self.minimum, self.shape + delta)
}
#[inline]
pub fn padded(&self, pad_amount: <PointN<N> as Point>::Scalar) -> Self
where
<PointN<N> as Point>::Scalar: Add<Output = <PointN<N> as Point>::Scalar>,
{
Self::from_min_and_shape(
self.minimum - PointN::fill(pad_amount),
self.shape + PointN::fill(pad_amount + pad_amount),
)
}
}
impl<N> ExtentN<N>
where
PointN<N>: IntegerPoint<N>,
{
#[inline]
pub fn num_points(&self) -> usize {
self.volume() as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.num_points() == 0
}
#[inline]
pub fn from_min_and_lub(minimum: PointN<N>, least_upper_bound: PointN<N>) -> Self {
let minimum = minimum;
let shape = (least_upper_bound - minimum).join(PointN::zero());
Self { minimum, shape }
}
#[inline]
pub fn intersection(&self, other: &Self) -> Self {
let minimum = self.minimum.join(other.minimum);
let lub = self.least_upper_bound().meet(other.least_upper_bound());
Self::from_min_and_lub(minimum, lub)
}
#[inline]
pub fn is_subset_of(&self, other: &Self) -> bool {
self.intersection(other).eq(self)
}
#[inline]
pub fn from_min_and_max(minimum: PointN<N>, max: PointN<N>) -> Self {
Self::from_min_and_lub(minimum, max + PointN::ONES)
}
#[inline]
pub fn max(&self) -> PointN<N> {
let lub = self.least_upper_bound();
lub - PointN::ONES
}
#[inline]
pub fn from_corners(p1: PointN<N>, p2: PointN<N>) -> Self {
let min = p1.meet(p2);
let max = p1.join(p2);
Self::from_min_and_max(min, max)
}
#[inline]
pub fn iter_points(&self) -> <PointN<N> as IterExtent<N>>::PointIter {
PointN::iter_extent(self.minimum, self.least_upper_bound())
}
}
impl<T> Add<PointN<T>> for ExtentN<T>
where
PointN<T>: Add<Output = PointN<T>>,
{
type Output = Self;
#[inline]
fn add(self, rhs: PointN<T>) -> Self::Output {
ExtentN {
minimum: self.minimum + rhs,
shape: self.shape,
}
}
}
impl<T> Sub<PointN<T>> for ExtentN<T>
where
PointN<T>: Sub<Output = PointN<T>>,
{
type Output = Self;
#[inline]
fn sub(self, rhs: PointN<T>) -> Self::Output {
ExtentN {
minimum: self.minimum - rhs,
shape: self.shape,
}
}
}
impl<T> Mul<PointN<T>> for ExtentN<T>
where
PointN<T>: Copy + Mul<Output = PointN<T>>,
{
type Output = Self;
#[inline]
fn mul(self, rhs: PointN<T>) -> Self::Output {
ExtentN {
minimum: self.minimum * rhs,
shape: self.shape * rhs,
}
}
}
impl<T> AddAssign<PointN<T>> for ExtentN<T>
where
Self: Copy + Add<PointN<T>, Output = ExtentN<T>>,
{
#[inline]
fn add_assign(&mut self, rhs: PointN<T>) {
*self = *self + rhs;
}
}
impl<T> SubAssign<PointN<T>> for ExtentN<T>
where
Self: Copy + Sub<PointN<T>, Output = ExtentN<T>>,
{
#[inline]
fn sub_assign(&mut self, rhs: PointN<T>) {
*self = *self - rhs;
}
}
#[inline]
pub fn bounding_extent<N, I>(mut points: I) -> ExtentN<N>
where
I: Iterator<Item = PointN<N>>,
PointN<N>: IntegerPoint<N>,
{
let first_point = points
.next()
.expect("Cannot find bounding extent of empty set of points");
let mut min_point = first_point;
let mut max_point = first_point;
for p in points {
min_point = min_point.meet(p);
max_point = max_point.join(p);
}
ExtentN::from_min_and_max(min_point, max_point)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn row_major_extent_iter2() {
let extent = Extent2i::from_min_and_shape(PointN([0, 0]), PointN([2, 2]));
let points: Vec<_> = extent.iter_points().collect();
assert_eq!(
points,
vec![
PointN([0, 0]),
PointN([1, 0]),
PointN([0, 1]),
PointN([1, 1]),
]
);
}
#[test]
fn row_major_extent_iter3() {
let extent = Extent3i::from_min_and_shape(PointN([0, 0, 0]), PointN([2, 2, 2]));
let points: Vec<_> = extent.iter_points().collect();
assert_eq!(
points,
vec![
PointN([0, 0, 0]),
PointN([1, 0, 0]),
PointN([0, 1, 0]),
PointN([1, 1, 0]),
PointN([0, 0, 1]),
PointN([1, 0, 1]),
PointN([0, 1, 1]),
PointN([1, 1, 1]),
]
);
}
#[test]
fn empty_intersection_is_empty() {
let e1 = Extent2i::from_min_and_max(PointN([0; 2]), PointN([1; 2]));
let e2 = Extent2i::from_min_and_max(PointN([3; 2]), PointN([4; 2]));
assert_eq!(e1.intersection(&e2).shape, PointN([0; 2]));
assert!(e1.intersection(&e2).is_empty());
}
}