hexga_math/geometry/rectangle/
rectangle.rs

1use super::*;
2
3
4pub type Rectangle<T, const N : usize> = RectangleOf<Vector<T, N>>;
5
6/// A `N` dimension rectangle
7///
8#[repr(C)]
9pub struct RectangleOf<T>
10{
11    pub pos  : T,
12    pub size : T,
13}
14impl_fixed_array!(RectangleOf, 2);
15
16impl<T> Default for RectangleOf<T> where T: Number
17{
18    fn default() -> Self { Self::SIZED_ONE }
19}
20
21impl<T> RectangleOf<T> where T: Number
22{
23    pub const SIZED_ONE : Self = Self::new_sized(T::ONE);
24}
25
26impl<T> From<(T,T)> for RectangleOf<T>
27{
28    fn from(value: (T,T)) -> Self {
29        Self::new(value.0, value.1)
30    }
31}
32
33impl<T> From<RectangleOf<T>> for (T,T)
34{
35    fn from(value: RectangleOf<T>) -> Self {
36        (value.pos, value.size)
37    }
38}
39
40// 2D :
41impl<T> Rectangle<T,2> where T: Number
42{
43    pub fn down_left (&self) -> Vector<T,2> { self.pos }
44    pub fn down_right(&self) -> Vector<T,2> where T: One + Mul<T,Output = T> + Add<T, Output=T> { self.pos + self.size * Vector::<T,2>::X }
45
46    /// Same as down_left()
47    pub fn bottom_left (&self) -> Vector<T,2> { self.down_left() }
48    /// Same as down_right()
49    pub fn bottom_right(&self) -> Vector<T,2> where T: One + Mul<T,Output = T> + Add<T, Output=T> { self.down_right() }
50
51    pub fn up_right  (&self) -> Vector<T,2> where T: Add<T, Output=T> { self.pos + self.size }
52    pub fn up_left   (&self) -> Vector<T,2> where T: One, T : Mul<T,Output = T> + Add<T, Output=T> { self.pos + self.size * Vector::<T,2>::Y }
53
54    /// Same as up_right()
55    pub fn top_right  (&self) -> Vector<T,2> where T: Add<T, Output=T> { self.up_right() }
56    /// Same as up_left()
57    pub fn top_left   (&self) -> Vector<T,2> where T: One, T : Mul<T,Output = T> + Add<T, Output=T> { self.up_left() }
58}
59
60impl<T,const N : usize> Rectangle<T,N> where Vector<T,N> : Number, T : Number
61{
62    pub fn new_centered(pos_middle : Vector<T,N>, size : Vector<T,N>) -> Self { Self::new(pos_middle-size/ (Vector::<T,N>::two()), size) }
63    pub fn new_with_center(bottom_left : Vector<T,N>, size : Vector<T,N>, center_coef : Vector<T,N>) -> Self { Self::new(bottom_left - center_coef * size, size) }
64
65    pub fn get_coef(&self, coef : Vector<T,N>) -> Vector<T,N> where Vector<T,N> : Arithmetic { self.pos + self.size * coef }
66
67    /// The center of the coordinate, whatever the dimension
68    pub fn middle      (&self) -> Vector<T,N> { self.pos + self.size.take_half() }
69    pub fn center      (&self) -> Vector<T,N> { self.pos + self.size.take_half() }
70
71    pub fn middle_right(&self) -> Vector<T,N> where Vector<T,N> : HaveX<T> { self.middle().with_x(self.right_value()) }
72    pub fn middle_left (&self) -> Vector<T,N> where Vector<T,N> : HaveX<T> { self.middle().with_x(self.left_value ()) }
73
74    pub fn middle_up   (&self) -> Vector<T,N> where Vector<T,N> : HaveY<T> { self.middle().with_y(self.up_value  ()) }
75    pub fn middle_down (&self) -> Vector<T,N> where Vector<T,N> : HaveY<T> { self.middle().with_y(self.down_value()) }
76
77    pub fn middle_forward  (&self) -> Vector<T,N> where Vector<T,N> : HaveZ<T> { self.middle().with_z(self.forward_value ()) }
78    pub fn middle_backward (&self) -> Vector<T,N> where Vector<T,N> : HaveZ<T> { self.middle().with_z(self.backward_value()) }
79
80    pub fn middle_ana  (&self) -> Vector<T,N> where Vector<T,N> : HaveW<T> { self.middle().with_w(self.ana_value ()) }
81    pub fn middle_kata (&self) -> Vector<T,N> where Vector<T,N> : HaveW<T> { self.middle().with_w(self.kata_value()) }
82
83    pub fn right_value (&self) -> T where Vector<T,N> : HaveX<T> { self.pos.x() + self.size.x() }
84    pub fn left_value  (&self) -> T where Vector<T,N> : HaveX<T> { self.pos.x() }
85
86    pub fn up_value    (&self) -> T where Vector<T,N> : HaveY<T> { self.pos.y() + self.size.y() }
87    pub fn down_value  (&self) -> T where Vector<T,N> : HaveY<T> { self.pos.y() }
88
89    /// Same as up_value()
90    pub fn top_value  (&self) -> T where Vector<T,N> : HaveY<T> { self.up_value() }
91    /// Same as down_value()
92    pub fn bottom_value  (&self) -> T where Vector<T,N> : HaveY<T> { self.down_value() }
93
94    pub fn forward_value (&self) -> T where Vector<T,N> : HaveZ<T> { self.pos.z() + self.size.z() }
95    pub fn backward_value(&self) -> T where Vector<T,N> : HaveZ<T> { self.pos.z() }
96
97    pub fn ana_value (&self) -> T where Vector<T,N> : HaveW<T> { self.pos.w() + self.size.w() }
98    pub fn kata_value(&self) -> T where Vector<T,N> : HaveW<T> { self.pos.w() }
99
100
101
102
103}
104
105impl<T,const N : usize> SetRectangle<T,N> for Rectangle<T,N> where T: Number
106{
107    fn set_size(&mut self, size : Vector<T, N>) -> &mut Self { self.size = size; self }
108    fn set_size_x(&mut self, x : T) -> &mut Self where Vector<T, N> : HaveX<T> { self.size.set_x(x); self }
109    fn set_size_y(&mut self, y : T) -> &mut Self where Vector<T, N> : HaveY<T> { self.size.set_y(y); self }
110    fn set_size_z(&mut self, z : T) -> &mut Self where Vector<T, N> : HaveZ<T> { self.size.set_z(z); self }
111    fn set_size_w(&mut self, w : T) -> &mut Self where Vector<T, N> : HaveW<T> { self.size.set_w(w); self }
112
113    fn with_size(mut self, size : Vector<T, N>) -> Self { self.size = size; self }
114    fn with_size_x(mut self, x : T) -> Self where Vector<T, N> : HaveX<T> { self.size.set_x(x); self }
115    fn with_size_y(mut self, y : T) -> Self where Vector<T, N> : HaveY<T> { self.size.set_y(y); self }
116    fn with_size_z(mut self, z : T) -> Self where Vector<T, N> : HaveZ<T> { self.size.set_z(z); self }
117    fn with_size_w(mut self, w : T) -> Self where Vector<T, N> : HaveW<T> { self.size.set_w(w); self }
118}
119
120/*
121// Todo: make it a trait. Should work for grid view
122pub trait SplitOn<T>
123{
124    type Item;
125     fn split_axis(&self, nb:T, axis: usize)
126}
127*/
128
129impl<T,const N : usize> Rectangle<T,N> where T: Primitive
130{
131    pub fn split_axis(&self, nb:T, axis: usize) -> impl Iterator<Item = Self>
132    {
133        let begin = self.pos[axis];
134        let end = begin + self.size[axis];
135        let step = self.size[axis] / nb;
136
137        let cuts = (begin..=end).step(step);
138
139        cuts
140            .clone()
141            .zip(cuts.skip(1))
142            .map(move |(x0, x1)| {
143                let mut r = self.clone();
144                r.pos[axis] = x0;
145                r.size[axis] = x1 - x0;
146                r
147            })
148    }
149
150    pub fn split_x(&self, nb:T) -> impl Iterator<Item = Self> where Vector<T,N>:HaveX<T>
151    { self.split_axis(nb, Vector::<T,N>::X_INDEX) }
152    pub fn split_y(&self, nb:T) -> impl Iterator<Item = Self> where Vector<T,N>:HaveY<T>
153    { self.split_axis(nb, Vector::<T,N>::Y_INDEX) }
154    pub fn split_z(&self, nb:T) -> impl Iterator<Item = Self> where Vector<T,N>:HaveZ<T>
155    { self.split_axis(nb, Vector::<T,N>::Z_INDEX) }
156    pub fn split_w(&self, nb:T) -> impl Iterator<Item = Self> where Vector<T,N>:HaveW<T>
157    { self.split_axis(nb, Vector::<T,N>::W_INDEX) }
158
159    pub fn split_min(&self, nb:T) -> impl Iterator<Item = Self> { self.split_axis(nb, self.size.min_element_idx()) }
160    pub fn split_max(&self, nb:T) -> impl Iterator<Item = Self> { self.split_axis(nb, self.size.max_element_idx()) }
161}
162
163impl<T,const N : usize> Rectangle<T,N> where T: Number
164{
165    /// Check if a point inside the rectangle.
166    /// Also work for indexing
167    ///
168    /// ```
169    /// use hexga_math::prelude::*;
170    ///
171    /// // inside :
172    /// assert!(rect2i(0, 0, 2, 2).is_inside(point2(1, 1)));
173    /// assert!(rect2i(0, 0, 2, 2).is_inside(point2(0, 0)));
174    ///
175    ///
176    /// // not inside :
177    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2(2, 0)));
178    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2(0, 2)));
179    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2(2, 2)));
180    ///
181    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2( 3,   3)));
182    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2(-1,  -1)));
183    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2(-1,  -1)));
184    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2( 1,  10)));
185    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2( 1, -10)));
186    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2(-10,  1)));
187    /// assert!(!rect2i(0, 0, 2, 2).is_inside(point2( 10,  1)));
188    ///
189    /// ```
190    pub fn is_inside(&self, point : Vector<T, N>) -> bool
191    {
192        self.bounds_min().all_with(&point, |axis, other_axis| other_axis >= axis) &&
193        self.bounds_max().all_with(&point, |axis, other_axis| other_axis <  axis)
194    }
195
196    /// Check if a point inside the rectangle.
197    /// Don't work for indexing
198    pub fn is_inside_inclusif(&self, point : Vector<T, N>) -> bool
199    {
200        self.bounds_min().all_with(&point, |axis, other_axis| other_axis >= axis) &&
201        self.bounds_max().all_with(&point, |axis, other_axis| other_axis <= axis)
202    }
203
204    pub fn is_rect_inside(&self, rect: Rectangle<T, N>) -> bool
205    {
206        self.is_inside(rect.bounds_min()) && self.is_inside_inclusif(rect.bounds_max())
207    }
208
209    pub fn is_empty(&self) -> bool { self.size.is_zero() }
210
211    pub fn clamp_vector(&self, vector : Vector<T, N>) -> Vector<T, N> where Vector<T, N>: Clamp { vector.clamp(self.bounds_min(), self.bounds_max())}
212
213    pub fn intersect_or_empty(self, other : Self) -> Self where Vector<T, N>: Max + Min
214    {
215        Self::from_pos_to_pos(self.bounds_min().max(other.pos), self.bounds_max().min(other.bounds_max()))
216    }
217    /// None if any rectangle is empty
218    pub fn intersect(self, other : Self) -> Option<Self> where Vector<T, N>: Max + Min
219    {
220        let intersect = self.intersect_or_empty(other);
221        if intersect.size.is_zero()
222        {
223            Some(intersect)
224        }
225        else
226        {
227            None
228        }
229    }
230}
231
232impl<T> RectangleOf<T>
233{
234    /// assume the size is valid
235    pub const fn new(pos: T, size: T) -> Self { Self { pos, size } }
236    /// assume the size is valid
237    pub const fn new_sized(size : T) -> Self where T: Zero { Self::new(zero(), size) }
238}
239
240/// Crop a selection to a sub selection, where the sub selection is contained in the selection.
241pub trait Crop<T, const N : usize> : GetRectangle<T, N> + Sized where T: Number
242{
243    /// Crop the current rectangle to the given sub rectangle.
244    ///
245    /// The sub rectangle will always be inside the current rectangle.
246    fn crop(self, subrect : Rectangle<T, N>) -> Option<Self>;
247
248    /// Crop the current rectangle to the given sub rectangle.
249    ///
250    /// The sub rectangle will always be inside the current rectangle.
251    unsafe fn crop_unchecked(self, subrect : Rectangle<T, N>) -> Self { self.crop(subrect).expect("invalid subrect") }
252
253    /// Crop the current rectangle to the given sub rectangle.
254    ///
255    /// The sub rectangle will always be inside the current rectangle.
256    #[track_caller]
257    fn crop_or_panic(self, subrect : Rectangle<T, N>) -> Self { self.crop(subrect).expect("invalid subrect") }
258
259
260    /// Crop the current rectangle to the given sub rectangle.
261    ///
262    /// The sub rectangle will always be inside the current rectangle.
263    /// If the sub rectangle is outside or partially outside the current view, it will be intersected with the current rectangle.
264    fn crop_intersect(self, subrect : Rectangle<T, N>) -> Self
265    {
266        let rect = self.rect().intersect_or_empty(subrect);
267        unsafe { self.crop_unchecked(rect) }
268    }
269
270    fn crop_margin(self, margin_start : Vector<T,N>, margin_end : Vector<T,N>) -> Option<Self>
271    {
272        if margin_start.any(|a| a < &zero()) || margin_end.any(|a| a < &zero()) { return None; }
273
274        let mut subrect = self.rect();
275
276        let removed_size = margin_start + margin_end;
277        if removed_size.any_with(&subrect.size(), |a,b| a > b) { return None; }
278
279        subrect.pos  += margin_start;
280        subrect.size -= removed_size;
281
282        Some(self.crop_or_panic(subrect))
283    }
284
285    unsafe fn crop_margin_unchecked(self, margin_start : Vector<T,N>, margin_end : Vector<T,N>) -> Self
286    {
287        let mut subrect = self.rect();
288        subrect.pos  += margin_start;
289        subrect.size -= margin_start + margin_end;
290        unsafe { self.crop_unchecked(subrect) }
291    }
292
293    /// Crop self by adding a margin to the start and the end of the current rectangle size.
294    ///
295    /// The sub self will always be inside the self.
296    fn crop_margin_intersect(self, margin_start : Vector<T,N>, margin_end : Vector<T,N>) -> Self
297    {
298        let size = self.size() - margin_start - margin_end;
299        self.crop_intersect(Rectangle::new(margin_start, size))
300    }
301}
302
303impl<T,const N : usize> Crop<T,N> for Rectangle<T,N> where T: Number
304{
305    // The Behavior is not well defined with zero sized subrect
306    // Currently it will return None
307
308    fn crop(self, mut subrect : Rectangle<T, N>) -> Option<Self>
309    {
310        subrect.move_by(self.pos);
311        if self.is_rect_inside(subrect) { Some(subrect) } else { None }
312    }
313    unsafe fn crop_unchecked(self, subrect : Rectangle<T, N>) -> Self { subrect.moved_by(self.pos) }
314
315    fn crop_intersect(self, subrect : Rectangle<T, N>) -> Self { self.intersect_or_empty(subrect.moved_by(self.pos)) }
316    unsafe fn crop_margin_unchecked(self, margin_start : Vector<T,N>, margin_end : Vector<T,N>) -> Self { Self::new(self.pos + margin_start, self.size - margin_start - margin_end) }
317}
318
319#[cfg(test)]
320mod rect_crop_test
321{
322    use crate::prelude::*;
323
324    #[test]
325    fn crop_margin_unchecked()
326    {
327        unsafe
328        {
329            assert_eq!(rect2i(5,5,10,10).crop_margin_unchecked(2.splat2(), 2.splat2()), rect2i(7,7,6,6));
330            assert_eq!(rect2i(5,5,10,10).crop_margin_unchecked(-1.splat2(), zero()), rect2i(4,4,11,11));
331        }
332    }
333
334    #[test]
335    fn crop_margin_intersect()
336    {
337        assert_eq!(rect2i(5,5,10,10).crop_margin_intersect(2.splat2(), 2.splat2()), rect2i(7,7,6,6));
338        assert_eq!(rect2i(5,5,10,10).crop_margin_intersect(-1.splat2(), zero()), rect2i(5,5,10,10));
339    }
340}
341
342
343impl<T,const N : usize> Rectangle<T,N> where T: Number
344{
345    pub fn from_pos_to_pos(start_pos : Vector<T,N>, end_pos : Vector<T,N>) -> Self { Self::new(start_pos, (end_pos - start_pos).map_with(zero(), |a,b| a.max_partial(b))) }
346}
347
348impl<T, const N : usize> GetPosition<T, N> for Rectangle<T, N> where T: Number
349{
350    #[inline(always)]
351    fn pos(&self) -> Vector<T,N> { self.pos }
352}
353impl<T, const N : usize> SetPosition<T, N> for Rectangle<T, N> where T: Number
354{
355    #[inline(always)]
356    fn set_pos(&mut self, pos : Vector<T,N>) -> &mut Self {
357        self.pos = pos;
358        self
359    }
360}
361impl<T, const N : usize> GetRectangle<T, N> for Rectangle<T, N> where T: Number
362{
363    #[inline(always)]
364    fn size(&self) -> Vector<T,N> { self.size }
365}
366
367
368pub trait GetRectangle<T, const N : usize> : GetPosition<T,N> where T: Number
369{
370    fn size(&self) -> Vector<T,N>;
371
372    #[inline(always)] fn size_x(&self) -> T where Vector<T,N> : HaveX<T> { self.size().x() }
373    #[inline(always)] fn size_y(&self) -> T where Vector<T,N> : HaveY<T> { self.size().y() }
374    #[inline(always)] fn size_z(&self) -> T where Vector<T,N> : HaveZ<T> { self.size().z() }
375    #[inline(always)] fn size_w(&self) -> T where Vector<T,N> : HaveW<T> { self.size().w() }
376
377    /// Same as `.size_x()`
378    #[inline(always)]
379    fn width (&self) -> T where Vector<T,N> : HaveX<T> { self.size_x() }
380    /// Same as `.size_y()`
381    #[inline(always)]
382    fn height(&self) -> T where Vector<T,N> : HaveY<T> { self.size_y() }
383    /// Same as `.size_z()`
384    #[inline(always)]
385    fn depth (&self) -> T where Vector<T,N> : HaveZ<T> { self.size_z() }
386
387    #[inline(always)]
388    fn area(&self) -> T { self.size().area() }
389    #[inline(always)]
390    fn area_usize(&self) -> usize where T: Integer { self.size().area_usize() }
391
392    #[inline(always)]
393    fn is_inside(&self, pos : Vector<T,N>) -> bool { pos.is_inside(self.size()) }
394    #[inline(always)]
395    fn is_outside(&self, pos : Vector<T,N>) -> bool { !self.is_inside(pos) }
396
397    #[inline(always)]
398    fn begin(&self) -> Vector<T,N> { self.pos()}
399    #[inline(always)]
400    fn end(&self) -> Vector<T,N> { self.pos() + self.size() }
401
402    /// same as `.begin()`
403    #[inline(always)]
404    fn bounds_min(&self) -> Vector<T,N> { self.begin() }
405    /// same as `.end()`
406    #[inline(always)]
407    fn bounds_max(&self) -> Vector<T,N> { self.end() }
408
409    #[inline(always)]
410    fn rect(&self) -> Rectangle<T, N> { Rectangle::new(self.begin(), self.size()) }
411
412    fn iter_x(&self) -> Range<T> where Vector<T,N> : HaveX<T>, Range<T> : IntoIterator { self.bounds_min().x()..self.bounds_max().x() }
413    fn iter_y(&self) -> Range<T> where Vector<T,N> : HaveY<T>, Range<T> : IntoIterator { self.bounds_min().y()..self.bounds_max().y() }
414    fn iter_z(&self) -> Range<T> where Vector<T,N> : HaveZ<T>, Range<T> : IntoIterator { self.bounds_min().z()..self.bounds_max().z() }
415    fn iter_w(&self) -> Range<T> where Vector<T,N> : HaveW<T>, Range<T> : IntoIterator { self.bounds_min().w()..self.bounds_max().w() }
416
417    #[inline(always)] fn is_inside_x(&self, x : T) -> bool where Vector<T,N> : HaveX<T> { x >= self.bounds_min().x() && x < self.bounds_max().x() }
418    #[inline(always)] fn is_inside_y(&self, y : T) -> bool where Vector<T,N> : HaveY<T> { y >= self.bounds_min().y() && y < self.bounds_max().y() }
419    #[inline(always)] fn is_inside_z(&self, z : T) -> bool where Vector<T,N> : HaveZ<T> { z >= self.bounds_min().z() && z < self.bounds_max().z() }
420    #[inline(always)] fn is_inside_w(&self, w : T) -> bool where Vector<T,N> : HaveW<T> { w >= self.bounds_min().w() && w < self.bounds_max().w() }
421
422    #[inline(always)] fn is_outside_x(&self, x : T) -> bool where Vector<T,N> : HaveX<T> { !self.is_inside_x(x) }
423    #[inline(always)] fn is_outside_y(&self, y : T) -> bool where Vector<T,N> : HaveY<T> { !self.is_inside_y(y) }
424    #[inline(always)] fn is_outside_z(&self, z : T) -> bool where Vector<T,N> : HaveZ<T> { !self.is_inside_z(z) }
425    #[inline(always)] fn is_outside_w(&self, w : T) -> bool where Vector<T,N> : HaveW<T> { !self.is_inside_w(w) }
426}
427
428pub trait SetRectangle<T, const N : usize> : GetRectangle<T,N> + SetPosition<T,N> where T: Number
429{
430    fn set_size(&mut self, size : Vector<T, N>) -> &mut Self;
431    #[inline(always)] fn resize(&mut self, size : Vector<T, N>) -> &mut Self { self.set_size(size) }
432
433    fn set_size_x(&mut self, x : T) -> &mut Self where Vector<T, N> : HaveX<T> { let mut p = self.pos(); p.set_x(x); self.set_pos(p); self }
434    #[inline(always)] fn set_size_y(&mut self, y : T) -> &mut Self where Vector<T, N> : HaveY<T> { let mut p = self.pos(); p.set_y(y); self.set_pos(p); self }
435    #[inline(always)] fn set_size_z(&mut self, z : T) -> &mut Self where Vector<T, N> : HaveZ<T> { let mut p = self.pos(); p.set_z(z); self.set_pos(p); self }
436    #[inline(always)] fn set_size_w(&mut self, w : T) -> &mut Self where Vector<T, N> : HaveW<T> { let mut p = self.pos(); p.set_w(w); self.set_pos(p); self }
437
438    #[inline(always)] fn with_size(mut self, size : Vector<T, N>) -> Self where Self : Sized { self.set_size(size); self }
439    #[inline(always)] fn with_size_x(mut self, x : T) -> Self where Vector<T, N> : HaveX<T>, Self : Sized { self.set_size_x(x); self }
440    #[inline(always)] fn with_size_y(mut self, y : T) -> Self where Vector<T, N> : HaveY<T>, Self : Sized { self.set_size_y(y); self }
441    #[inline(always)] fn with_size_z(mut self, z : T) -> Self where Vector<T, N> : HaveZ<T>, Self : Sized { self.set_size_z(z); self }
442    #[inline(always)] fn with_size_w(mut self, w : T) -> Self where Vector<T, N> : HaveW<T>, Self : Sized { self.set_size_w(w); self }
443}
444
445
446/*
447
448impl<T,const N : usize> Rectangle<T,N>
449    where Vector<T,N> : Number,
450    T : Number ,
451    usize : CastInto<T>
452{
453    pub fn split_axis(&self, axis : Vector<T,N>, nb : usize) -> impl Iterator<Item = Rectangle<T,N>> + '_
454    {
455        let coef = (Vector::splat(nb.cast_to()) * axis).max(Vector::ONE);
456        let size = self.size / coef;
457        let offset = size * axis;
458        (0..nb).map(move |i| Rectangle::new(self.pos + offset * Vector::splat(i.cast_to()), size))
459    }
460
461
462    pub fn split_x(&self, nb : usize) -> impl Iterator<Item = Rectangle<T,N>> + '_ where Vector<T,N> : HaveXAndOne<T> { self.split_axis(Vector::<T,N>::X, nb) }
463    pub fn split_y(&self, nb : usize) -> impl Iterator<Item = Rectangle<T,N>> + '_ where Vector<T,N> : HaveYAndOne<T> { self.split_axis(Vector::<T,N>::Y, nb) }
464    pub fn split_z(&self, nb : usize) -> impl Iterator<Item = Rectangle<T,N>> + '_ where Vector<T,N> : HaveZAndOne<T> { self.split_axis(Vector::<T,N>::Z, nb) }
465    pub fn split_w(&self, nb : usize) -> impl Iterator<Item = Rectangle<T,N>> + '_ where Vector<T,N> : HaveWAndOne<T> { self.split_axis(Vector::<T,N>::W, nb) }
466
467    pub fn split_min(&self, nb : usize) -> impl Iterator<Item = Rectangle<T,N>> + '_ where
468    {
469        self.split_axis(Vector::ZERO.with(self.size.min_element_idx(), T::ONE), nb)
470    }
471
472    pub fn split_max(&self, nb : usize) -> impl Iterator<Item = Rectangle<T,N>> + '_ where
473    {
474        self.split_axis(Vector::ZERO.with(self.size.max_element_idx(), T::ONE), nb)
475    }
476
477    pub fn split_on(&self, nb : usize, split_on : SplitOn) -> impl Iterator<Item = Rectangle<T,N>> + '_ where
478    {
479        let v = match split_on
480        {
481            SplitOn::Dim(x) => if x < N { Vector::ZERO.with(x, T::ONE) } else { Vector::ZERO },
482            SplitOn::Min => Vector::ZERO.with(self.size.min_element_idx(), T::ONE),
483            SplitOn::Max => Vector::ZERO.with(self.size.max_element_idx(), T::ONE),
484        };
485        self.split_axis(v, nb)
486    }
487}
488
489#[derive(Clone, Copy, PartialEq, Eq, Debug)]
490pub enum SplitOn
491{
492    Dim(usize),
493    Min,
494    Max,
495}
496
497/*
498impl<T,const N : usize> Rectangle<T,N> where T: ArrayLike<N> + Copy
499{
500    fn map_pos(&mut self, )
501    fn into_map_pos(mut self, )
502}
503*/
504*/
505
506impl<Idx,const N : usize> IterIndex<Idx,N> for Rectangle<Idx,N> where Idx : Integer
507{
508    type IterIndex = RectangleIter<Idx,N>;
509    fn iter_index(&self) -> Self::IterIndex { RectangleIter::from_vec_iter(self.pos, self.size.iter_index()) }
510}
511
512
513
514
515#[cfg(test)]
516mod rect_test
517{
518    use super::*;
519
520
521    #[test]
522    fn crop_margin_unchecked()
523    {
524        unsafe
525        {
526            assert_eq!(rect2i(5,5,10,10).crop_margin_unchecked(2.splat2(), 2.splat2()), rect2i(7,7,6,6));
527
528            assert_eq!(rect2i(5,5,10,10).crop_margin_unchecked(2.splat2(), zero()), rect2i(7,7,8,8));
529            assert_eq!(rect2i(5,5,10,10).crop_margin_unchecked(zero(), 2.splat2()), rect2i(5,5,8,8));
530
531            assert_eq!(rect2i(5,5,10,10).crop_margin_unchecked(-1.splat2(), zero()), rect2i(4,4,11,11));
532            assert_eq!(rect2i(5,5,10,10).crop_margin_unchecked(zero(), -1.splat2()), rect2i(5,5,11,11));
533        }
534    }
535
536
537    #[test]
538    fn crop_margin()
539    {
540        assert_eq!(rect2i(5,5,10,10).crop_margin_intersect(2.splat2(), 2.splat2()), rect2i(7,7,6,6));
541
542        assert_eq!(rect2i(5,5,10,10).crop_margin_intersect(2.splat2(), zero()), rect2i(7,7,8,8));
543        assert_eq!(rect2i(5,5,10,10).crop_margin_intersect(zero(), 2.splat2()), rect2i(5,5,8,8));
544
545        assert_eq!(rect2i(5,5,10,10).crop_margin_intersect(-1.splat2(), zero()), rect2i(5,5,10,10));
546        assert_eq!(rect2i(5,5,10,10).crop_margin_intersect(zero(), -1.splat2()), rect2i(5,5,10,10));
547    }
548
549    #[test]
550    fn crop_normal()
551    {
552        let rect = rect2i(0, 0, 10, 10);
553        let cropped = rect.crop_margin_intersect(point2(1, 1), point2(2, 2));
554        assert_eq!(cropped, rect2i(1, 1, 7, 7));
555    }
556
557    #[test]
558    fn crop_to_much()
559    {
560        let rect = rect2i(0, 0, 10, 10);
561        let cropped = rect.crop_margin_intersect(point2(0, 0), point2(20, 20));
562        assert_eq!(cropped, zero());
563    }
564
565    #[test]
566    fn crop_to_much_2()
567    {
568        let rect = rect2i(0, 0, 10, 10);
569        let cropped = rect.crop_margin_intersect(point2(20, 20), point2(0, 0));
570        assert_eq!(cropped, rect2i(20, 20, 0, 0));
571    }
572
573    #[test]
574    fn crop_to_much_3()
575    {
576        let rect = rect2i(0, 0, 10, 10);
577        let cropped = rect.crop_margin_intersect(point2(20, 20), point2(20, 20));
578        assert_eq!(cropped, rect2i(20, 20, 0, 0));
579    }
580
581    #[test]
582    fn crop_2()
583    {
584        let r = rect2i(0, 0, 2, 3);
585        assert_eq!(r.crop(rect2i(0, 0, 0, 0)), Some(rect2i(0, 0, 0, 0)));
586        assert_eq!(r.crop(r), Some(r));
587        assert_eq!(r.crop(rect2i(0, 0, 2, 4)), None);
588
589        for idx in r.iter_index()
590        {
591            assert_eq!(r.is_inside(idx), true);
592        }
593    }
594}