inter_val/
interval_box.rs

1use crate::bound_type::{Left, Right};
2use crate::ndim::NDim;
3use crate::traits::BoundaryOf;
4use crate::{Bound, Exclusive, Inclusive, Interval};
5
6/// n-dimensional axis-aligned box as a cartesian product set of intervals, i.g., *[a, b)^n*.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct BoxN<const N: usize, T, L = Inclusive, R = L>(NDim<N, Interval<T, L, R>>);
9
10impl<const N: usize, T, L, R> std::ops::Deref for BoxN<N, T, L, R> {
11    type Target = NDim<N, Interval<T, L, R>>;
12    fn deref(&self) -> &Self::Target {
13        &self.0
14    }
15}
16impl<const N: usize, T, L, R> std::ops::DerefMut for BoxN<N, T, L, R> {
17    fn deref_mut(&mut self) -> &mut Self::Target {
18        &mut self.0
19    }
20}
21
22impl<const N: usize, T, L, R> From<[Interval<T, L, R>; N]> for BoxN<N, T, L, R> {
23    fn from(src: [Interval<T, L, R>; N]) -> Self {
24        Self(src.into())
25    }
26}
27
28impl<const N: usize, T, L, R> From<BoxN<N, T, L, R>> for [Interval<T, L, R>; N] {
29    fn from(src: BoxN<N, T, L, R>) -> Self {
30        src.0.into_array()
31    }
32}
33
34impl<const N: usize, T, L, R> AsRef<[Interval<T, L, R>; N]> for BoxN<N, T, L, R> {
35    fn as_ref(&self) -> &[Interval<T, L, R>; N] {
36        self.0.as_array()
37    }
38}
39
40impl<const N: usize, T, L, R> BoxN<N, T, L, R> {
41    pub fn from_array(src: [Interval<T, L, R>; N]) -> Self {
42        src.into()
43    }
44    pub fn into_array(self) -> [Interval<T, L, R>; N] {
45        self.into()
46    }
47}
48
49impl<T, L, R> BoxN<2, T, L, R> {
50    pub fn new(x: Interval<T, L, R>, y: Interval<T, L, R>) -> Self {
51        Self([x, y].into())
52    }
53}
54impl<T, L, R> BoxN<3, T, L, R> {
55    pub fn new(x: Interval<T, L, R>, y: Interval<T, L, R>, z: Interval<T, L, R>) -> Self {
56        Self([x, y, z].into())
57    }
58}
59impl<T, L, R> BoxN<4, T, L, R> {
60    pub fn new(
61        x: Interval<T, L, R>,
62        y: Interval<T, L, R>,
63        z: Interval<T, L, R>,
64        w: Interval<T, L, R>,
65    ) -> Self {
66        Self([x, y, z, w].into())
67    }
68}
69
70impl<const N: usize, T: PartialOrd + Clone, L: BoundaryOf<Left>, R: BoundaryOf<Right>>
71    BoxN<N, T, L, R>
72{
73    /// ```
74    /// use inter_val::{Box2, Exclusive};
75    /// let a: Box2<i32> = Box2::try_between(&[0, 0], &[10, 20]).unwrap();
76    /// assert_eq!(a.x.inf(), &0);
77    /// assert_eq!(a.y.sup(), &20);
78    ///
79    /// assert!(Box2::<i32, Exclusive>::try_between(&[0, 0], &[0, 1]).is_none());
80    /// ```
81    pub fn try_between(a: &[T; N], b: &[T; N]) -> Option<Self>
82    where
83        T: Into<Bound<T, L>> + Into<Bound<T, R>>,
84    {
85        let mut tmp: [_; N] =
86            std::array::from_fn(|i| Interval::try_between(a[i].clone(), b[i].clone()));
87        tmp.iter()
88            .all(|i| i.is_some())
89            .then(|| std::array::from_fn(|i| tmp[i].take().unwrap()).into())
90    }
91
92    /// ```
93    /// use inter_val::Box2;
94    /// let a: Box2<i32> = Box2::between(&[0, 0], &[10, 20]);
95    /// assert_eq!(a.inf(), [0, 0]);
96    /// assert_eq!(a.sup(), [10, 20]);
97    pub fn between(a: &[T; N], b: &[T; N]) -> Self
98    where
99        T: Into<Bound<T, L>> + Into<Bound<T, R>>,
100    {
101        std::array::from_fn(|i| Interval::between(a[i].clone(), b[i].clone())).into()
102    }
103
104    pub fn inf(&self) -> NDim<N, T> {
105        std::array::from_fn(|i| self[i].inf().clone()).into()
106    }
107
108    pub fn sup(&self) -> NDim<N, T> {
109        std::array::from_fn(|i| self[i].sup().clone()).into()
110    }
111
112    pub fn contains(&self, t: &[T; N]) -> bool {
113        self.iter().zip(t.iter()).all(|(i, t)| i.contains(t))
114    }
115
116    pub fn includes(&self, other: &Self) -> bool {
117        self.iter().zip(other.iter()).all(|(i, o)| i.includes(o))
118    }
119
120    pub fn overlaps(&self, other: &Self) -> bool {
121        self.iter().zip(other.iter()).all(|(i, j)| i.overlaps(j))
122    }
123
124    pub fn closure(&self) -> BoxN<N, T, Inclusive> {
125        std::array::from_fn(|i| self[i].clone().closure()).into()
126    }
127
128    pub fn interior(&self) -> Option<BoxN<N, T, Exclusive>> {
129        let mut tmp: [_; N] = std::array::from_fn(|i| self[i].clone().interior());
130        tmp.iter()
131            .all(|i| i.is_some())
132            .then(|| std::array::from_fn(|i| tmp[i].take().unwrap()).into())
133    }
134
135    pub fn intersection(&self, other: &Self) -> Option<Self> {
136        let mut tmp: [_; N] = std::array::from_fn(|i| self[i].intersection(&other[i]));
137        tmp.iter()
138            .all(|i| i.is_some())
139            .then(|| std::array::from_fn(|i| tmp[i].take().unwrap()).into())
140    }
141
142    pub fn span(&self, other: &Self) -> Self {
143        std::array::from_fn(|i| self[i].clone().span(&other[i])).into()
144    }
145
146    pub fn dilate(&self, delta: T) -> Self
147    where
148        T: std::ops::Add<Output = T> + std::ops::Sub<Output = T>,
149    {
150        std::array::from_fn(|i| self[i].clone().dilate(delta.clone())).into()
151    }
152
153    /// ```
154    /// use inter_val::Box2;
155    /// let a: Box2<i32> = Box2::between(&[0, 0], &[10, 10]);
156    /// let b = a.hull(&[20, 5]);
157    /// assert_eq!(b, Box2::between(&[0, 0], &[20, 10]));
158    /// ```
159    pub fn hull(self, p: &[T; N]) -> Self {
160        std::array::from_fn(|i| self[i].clone().hull(p[i].clone())).into()
161    }
162
163    pub fn span_many<A: Into<Self>>(items: impl IntoIterator<Item = A>) -> Option<Self> {
164        let mut items = items.into_iter();
165        let first = items.next()?.into();
166        Some(items.fold(first, |acc, item| acc.span(&item.into())))
167    }
168
169    pub fn hull_many<'a>(items: impl IntoIterator<Item = &'a [T; N]>) -> Option<Self>
170    where
171        T: Clone + Into<Bound<T, L>> + Into<Bound<T, R>> + 'a,
172    {
173        let mut items = items.into_iter();
174        let mut lower = items.next()?.clone();
175        let mut upper = lower.clone();
176        for p in items {
177            for i in 0..N {
178                if p[i] < lower[i] {
179                    lower[i] = p[i].clone();
180                } else if upper[i] < p[i] {
181                    upper[i] = p[i].clone();
182                }
183            }
184        }
185        Self::try_between(&lower, &upper)
186    }
187}
188
189impl<const N: usize, T, L, R> BoxN<N, T, L, R>
190where
191    T: PartialOrd + Clone + num::Num,
192    L: BoundaryOf<Left>,
193    R: BoundaryOf<Right>,
194{
195    pub fn size(&self) -> NDim<N, T> {
196        std::array::from_fn(|i| self[i].measure()).into()
197    }
198    pub fn measure(&self) -> T {
199        self.iter()
200            .map(|item| item.measure())
201            .fold(T::one(), |a, b| a * b)
202    }
203}
204
205impl<const N: usize, T: num::Float, L: BoundaryOf<Left>, R: BoundaryOf<Right>> BoxN<N, T, L, R> {
206    pub fn center(&self) -> NDim<N, T> {
207        std::array::from_fn(|i| self[i].center()).into()
208    }
209}