devela/num/geom/metric/extent/
methods.rs

1// devela::num::geom::metric::extent::methods
2//
3//!
4//
5
6use super::{Extent, Extent2d, Extent3d};
7use crate::{cfor, iif, Bound, ConstDefault, Interval};
8
9#[rustfmt::skip]
10impl<T, const D: usize> Extent<T, D> {
11    /// Constructs a new `Extent` from the given dimensions.
12    pub const fn new(dimensions: [T; D]) -> Self {
13        Self { size: dimensions }
14    }
15
16    /// Returns a shared reference to the extent as a slice.
17    #[must_use]
18    pub const fn as_slice(&self) -> &[T] {
19        &self.size
20    }
21    /// Returns an exclusive reference to the extent as a slice.
22    #[must_use]
23    pub fn as_slice_mut(&mut self) -> &mut [T] {
24        &mut self.size
25    }
26
27    /// Returns `true` if all dimensions of the extent are equal.
28    #[must_use]
29    pub fn is_uniform_nd(&self) -> bool where T: PartialEq {
30        iif![D == 0; return true];
31        let mut i = 1;
32        while i < D {
33            iif![self.size[i] != self.size[0]; return false];
34            i += 1;
35        }
36        true
37    }
38}
39
40/// # Interval-related methods
41// TODO: CHECK whether these interval ops are useful | make sense
42impl<T, const D: usize> Extent<T, D> {
43    /// TODO
44    #[must_use]
45    pub fn as_intervals(self) -> [Interval<T>; D]
46    where
47        T: Default,
48    {
49        self.size.map(|dim| Interval {
50            lower: Bound::Included(T::default()),
51            upper: Bound::Included(dim),
52        })
53    }
54
55    /// TODO
56    #[must_use]
57    pub const fn as_intervals_const(self) -> [Interval<T>; D]
58    where
59        T: Copy + ConstDefault,
60    {
61        let mut intervals = [Interval {
62            lower: Bound::Included(T::DEFAULT),
63            upper: Bound::Included(T::DEFAULT),
64        }; D];
65        let mut i = 0;
66        while i < D {
67            intervals[i] = Interval {
68                lower: Bound::Included(T::DEFAULT),
69                upper: Bound::Included(self.size[i]),
70            };
71            i += 1;
72        }
73        intervals
74    }
75
76    /// Converts each dimension into an interval from zero to the dimension's extent.
77    #[must_use]
78    pub fn to_intervals(&self) -> [Interval<T>; D]
79    where
80        T: Clone + Default,
81    {
82        self.size.clone().map(|dim| Interval {
83            lower: Bound::Included(T::default()),
84            upper: Bound::Included(dim),
85        })
86    }
87
88    /// Checks if each dimension of the extent is within the given interval.
89    #[must_use]
90    pub fn fits_within(&self, interval: &Interval<T>) -> bool
91    where
92        T: PartialOrd,
93    {
94        self.size.iter().all(|dim| {
95            matches!(interval.lower, Bound::Included(ref lb) if dim >= lb)
96                && matches!(interval.upper, Bound::Included(ref ub) if dim <= ub)
97        })
98    }
99}
100
101/* manual impls for specific dimensionalities */
102
103#[rustfmt::skip]
104impl<T> Extent2d<T> {
105    /// Returns a copy of the first dimension `x`.
106    #[must_use]
107    pub const fn x(self) -> T where T: Copy { self.size[0] }
108    /// Returns a copy of the second dimension `y`.
109    #[must_use]
110    pub const fn y(self) -> T where T: Copy { self.size[1] }
111
112    /// Returns a shared reference to the first dimension `x`.
113    #[must_use]
114    pub const fn x_ref(&self) -> &T { &self.size[0] }
115    /// Returns a shared reference to the second dimension `y`.
116    #[must_use]
117    pub const fn y_ref(&self) -> &T { &self.size[1] }
118
119    /// Returns an exclusive reference to the first dimension `x`.
120    #[must_use]
121    pub fn x_mut(&mut self) -> &mut T { &mut self.size[0] }
122    /// Returns an exclusive reference to the second dimension `y`.
123    #[must_use]
124    pub fn y_mut(&mut self) -> &mut T { &mut self.size[1] }
125
126    /// Returns `true` if the 2 dimensions of the extent are equal.
127    #[must_use]
128    pub fn is_uniform(&self) -> bool where T: PartialEq {
129        self.size[0] == self.size[1]
130    }
131}
132
133#[rustfmt::skip]
134impl<T> Extent3d<T> {
135    /// Returns a copy of the first dimension `x`.
136    #[must_use]
137    pub const fn x(self) -> T where T: Copy { self.size[0] }
138    /// Returns a copy of the second dimension `y`.
139    #[must_use]
140    pub const fn y(self) -> T where T: Copy { self.size[1] }
141    /// Returns a copy of the third dimension `z`.
142    #[must_use]
143    pub const fn z(self) -> T where T: Copy { self.size[2] }
144
145    /// Returns a shared reference to the first dimension `x`.
146    #[must_use]
147    pub const fn x_ref(&self) -> &T { &self.size[0] }
148    /// Returns a shared reference to the second dimension `y`.
149    #[must_use]
150    pub const fn y_ref(&self) -> &T { &self.size[1] }
151    /// Returns a shared reference to the third dimension `z`.
152    #[must_use]
153    pub const fn z_ref(&self) -> &T { &self.size[2] }
154
155    /// Returns an exclusive reference to the first dimension `x`.
156    #[must_use]
157    pub fn x_mut(&mut self) -> &mut T { &mut self.size[0] }
158    /// Returns an exclusive reference to the second dimension `y`.
159    #[must_use]
160    pub fn y_mut(&mut self) -> &mut T { &mut self.size[1] }
161    /// Returns an exclusive reference to the third dimension `z`.
162    #[must_use]
163    pub fn z_mut(&mut self) -> &mut T { &mut self.size[2] }
164
165    /// Returns `true` if the 3 dimensions of the extent are equal.
166    #[must_use]
167    pub fn is_uniform_3d(&self) -> bool where T: PartialEq {
168        self.size[0] == self.size[1] && self.size[0] == self.size[2]
169    }
170}
171
172/// Implement `Extent`.
173macro_rules! impl_extent {
174    () => {
175        impl_extent![sint i8, i16, i32, i64, i128, isize];
176        impl_extent![uint u8, u16, u32, u64, u128, usize];
177        impl_extent![float f32, f64];
178    };
179    // integers common methods
180    //
181    // $t: the inner integer primitive type
182    (int $($t:ty),+) => { $( impl_extent![@int $t]; )+ };
183    (@int $t:ty) => {
184        impl<const D: usize> Extent<$t, D> {
185            /// Returns the internal measure, the product of the extents.
186            ///
187            /// It's equivalent to length, area, and volume in 1, 2 and 3 dimensions.
188            pub const fn c_measure(self) -> $t {
189                let mut measure = 1;
190                cfor!(i in 0..D => {
191                    measure *= self.size[i];
192                });
193                measure
194            }
195            /// Returns the external boundary, the sum of the extents.
196            ///
197            /// It's equivalent to 2, perimeter and surface area in 1, 2 and 3 dimensions.
198            pub const fn c_boundary(self) -> $t {
199                let mut boundary = 0;
200                cfor!(i in 0..D => {
201                    let mut face_measure = 1;
202                    cfor!(j in 0..D => {
203                        iif![i != j; face_measure *= self.size[j]];
204                    });
205                    boundary += face_measure;
206                });
207                2 * boundary // Each dimension's contribution is counted twice
208            }
209        }
210
211        impl Extent<$t, 1> {
212            /// The length of the 1d extent.
213            #[must_use]
214            pub const fn c_length(self) -> $t { self.size[0] }
215        }
216        impl Extent2d<$t> {
217            /// The area of the 2d extent.
218            #[must_use]
219            pub const fn c_area(self) -> $t { self.size[0] * self.size[1] }
220
221            /// The perimeter of the 2d extent.
222            #[must_use]
223            pub const fn c_perimeter(self) -> $t { 2 * (self.size[0] + self.size[1]) }
224
225        }
226        impl Extent3d<$t> {
227            /// The volume of the 3d extent.
228            #[must_use]
229            pub const fn c_volume(self) -> $t {
230                self.size[0] * self.size[1] * self.size[2]
231            }
232
233            /// The surface area of the 3d extent.
234            #[must_use]
235            pub const fn c_surface_area(self) -> $t {
236                2 * (self.size[0] * self.size[1]
237                    + self.size[1] * self.size[2]
238                    + self.size[2] * self.size[0])
239            }
240        }
241    };
242
243    (sint $($t:ty),+) => { $( impl_extent![@sint $t]; )+ };
244    (@sint $t:ty ) => {
245        impl_extent![int $t];
246    };
247    (uint $($t:ty),+) => { $( impl_extent![@uint $t]; )+ };
248    (@uint $t:ty ) => {
249        impl_extent![int $t];
250    };
251
252    // $f: the inner floating-point primitive type
253    (float $($f:ty),+) => { $( impl_extent![@float $f]; )+ };
254    (@float $f:ty) => {
255        impl<const D: usize> Extent<$f, D> {
256            /// Returns the internal measure, the product of the extents.
257            ///
258            /// It's equivalent to length, area, and volume in 1, 2 and 3 dimensions.
259            #[must_use]
260            pub const fn measure(self) -> $f {
261                let mut measure = 1.0;
262                cfor!(i in 0..D => {
263                    measure *= self.size[i];
264                });
265                measure
266            }
267            /// Returns the external boundary, the sum of the extents.
268            ///
269            /// It's equivalent to 2, perimeter and surface area in 1, 2 and 3 dimensions.
270            #[must_use]
271            pub const fn boundary(self) -> $f {
272                let mut boundary = 0.0;
273                cfor!(i in 0..D => {
274                    let mut face_measure = 1.0;
275                    cfor!(j in 0..D => {
276                        iif![i != j; face_measure *= self.size[j]];
277                    });
278                    boundary += face_measure;
279                });
280                2.0 * boundary // Each dimension's contribution is counted twice
281            }
282        }
283
284        impl Extent<$f, 1> {
285            /// The length of the 1d extent.
286            #[must_use]
287            pub const fn length(self) -> $f { self.size[0] }
288        }
289        impl Extent2d<$f> {
290            /// The area of the 2d extent.
291            #[must_use]
292            pub const fn area(self) -> $f { self.size[0] * self.size[1] }
293
294            /// The perimeter of the 2d extent.
295            #[must_use]
296            pub const fn perimeter(self) -> $f { 2.0 * (self.size[0] + self.size[1]) }
297
298        }
299        impl Extent3d<$f> {
300            /// The volume of the 3d extent.
301            #[must_use]
302            pub const fn volume(self) -> $f {
303                self.size[0] * self.size[1] * self.size[2]
304            }
305
306            /// The surface area of the 3d extent.
307            #[must_use]
308            pub const fn surface_area(self) -> $f {
309                2.0 * (self.size[0] * self.size[1]
310                    + self.size[1] * self.size[2]
311                    + self.size[2] * self.size[0])
312            }
313        }
314    };
315}
316impl_extent![];