rect_iter/
lib.rs

1//! This crate provides simple Iterator for enumerating rectangle.
2//! # Example
3//! ```rust
4//! extern crate rect_iter;
5//! extern crate euclid;
6//! use euclid::Vector2D;
7//! use rect_iter::{RectRange, FromTuple2, GetMut2D};
8//! type MyVec = Vector2D<u64, ()>;
9//! fn main() {
10//!     let range = RectRange::from_ranges(4..9, 5..10).unwrap();
11//!     let mut buffer = vec![vec![0.0; 100]; 100];
12//!     range.iter().for_each(|t| {
13//!         let len = MyVec::from_tuple2(t).to_f64().length();
14//!         *buffer.get_mut_p(t) = len;
15//!     });
16//! }
17//! ```
18
19#[cfg(feature = "euclid")]
20extern crate euclid;
21
22#[cfg(feature = "image")]
23#[allow(unused_imports)]
24extern crate image;
25
26#[cfg(feature = "ndarray")]
27#[allow(unused_imports)]
28extern crate ndarray;
29extern crate num_traits;
30extern crate tuple_map;
31
32#[cfg(feature = "serde")]
33#[allow(unused_imports)]
34#[macro_use]
35extern crate serde;
36
37#[allow(unused_imports)]
38use std::ops::{Deref, DerefMut, Range};
39
40#[cfg(feature = "euclid")]
41use euclid::{point2, rect, vec2, Point2D, Rect, Vector2D};
42
43#[cfg(feature = "ndarray")]
44use ndarray::{ArrayBase, Data, DataMut, Ix2};
45
46use num_traits::cast::FromPrimitive;
47pub use num_traits::cast::ToPrimitive;
48use num_traits::Num;
49use tuple_map::TupleMap2;
50
51#[cfg(feature = "image")]
52use image::{ImageBuffer, Pixel};
53use std::error::Error;
54use std::fmt;
55
56/// Error type for invalid access to 2D array.
57#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
58pub enum IndexError {
59    X(i64),
60    Y(i64),
61}
62
63unsafe impl Send for IndexError {}
64unsafe impl Sync for IndexError {}
65
66impl Error for IndexError {
67    fn description(&self) -> &str {
68        "Invalid Index access"
69    }
70}
71
72impl fmt::Display for IndexError {
73    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
74        match *self {
75            IndexError::X(x) => write!(f, "Invalid Index x: {}", x),
76            IndexError::Y(y) => write!(f, "Invalid Index y: {}", y),
77        }
78    }
79}
80
81/// To manipulate many Point libraries in the same way, we use tuple as a entry point of API.
82/// If you implement IntoTuple2 to your point type, you can use it as Point in this library.
83/// # Example
84/// ```
85/// # extern crate rect_iter; fn main() {
86/// use rect_iter::IntoTuple2;
87/// struct Point {
88///     x: f64,
89///     y: f64,
90/// }
91/// impl IntoTuple2<f64> for Point {
92///     fn into_tuple2(self) -> (f64, f64) {
93///         (self.x, self.y)
94///     }
95/// }
96/// # }
97/// ```
98pub trait IntoTuple2<T> {
99    fn into_tuple2(self) -> (T, T);
100}
101
102/// To manipulate many Point libraries in the same way, we use tuple as entry points of API.
103/// # Example
104/// ```
105/// # extern crate rect_iter; fn main() {
106/// use rect_iter::FromTuple2;
107/// struct Point {
108///     x: f64,
109///     y: f64,
110/// }
111/// impl FromTuple2<f64> for Point {
112///     fn from_tuple2(t: (f64, f64)) -> Self {
113///         Point { x: t.0, y: t.1 }
114///     }
115/// }
116/// # }
117/// ```
118pub trait FromTuple2<T> {
119    fn from_tuple2(tuple: (T, T)) -> Self;
120}
121
122#[cfg(feature = "euclid")]
123impl<T: Clone, U> IntoTuple2<T> for Point2D<T, U> {
124    fn into_tuple2(self) -> (T, T) {
125        (self.x, self.y)
126    }
127}
128
129#[cfg(feature = "euclid")]
130impl<T: Clone, U> IntoTuple2<T> for Vector2D<T, U> {
131    fn into_tuple2(self) -> (T, T) {
132        (self.x, self.y)
133    }
134}
135
136impl<T> IntoTuple2<T> for (T, T) {
137    fn into_tuple2(self) -> (T, T) {
138        self
139    }
140}
141
142#[cfg(feature = "euclid")]
143impl<T: Copy, U> FromTuple2<T> for Point2D<T, U> {
144    fn from_tuple2(t: (T, T)) -> Point2D<T, U> {
145        point2(t.0, t.1)
146    }
147}
148
149#[cfg(feature = "euclid")]
150impl<T: Clone, U> FromTuple2<T> for Vector2D<T, U> {
151    fn from_tuple2(t: (T, T)) -> Vector2D<T, U> {
152        vec2(t.0, t.1)
153    }
154}
155
156impl<T> FromTuple2<T> for (T, T) {
157    fn from_tuple2(t: (T, T)) -> Self {
158        t
159    }
160}
161
162/// RectRange is rectangle representation using `std::ops::Range`.
163///
164/// Diffrent from Range<T>, RectRange itself isn't a iterator, but
165/// has `IntoIterator` implementation and `iter` method(with 'clone').
166#[derive(Clone, Debug, PartialEq, Eq, Hash)]
167#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
168pub struct RectRange<T: Num + PartialOrd> {
169    x_range: Range<T>,
170    y_range: Range<T>,
171}
172
173impl<T: Num + PartialOrd> RectRange<T> {
174    /// construct a range from left x, lower y, right x, upper y
175    pub fn new(lx: T, ly: T, ux: T, uy: T) -> Option<RectRange<T>> {
176        RectRange::from_ranges(lx..ux, ly..uy)
177    }
178    /// construct a range `x_range: 0..x, y_range: 0..y`
179    pub fn zero_start(x: T, y: T) -> Option<RectRange<T>> {
180        RectRange::from_ranges(T::zero()..x, T::zero()..y)
181    }
182    /// construct a range `x_range: 0..p.x, y_range: 0..p.y`
183    pub fn from_point<P: IntoTuple2<T>>(p: P) -> Option<RectRange<T>> {
184        let p = p.into_tuple2();
185        RectRange::from_ranges(T::zero()..p.0, T::zero()..p.1)
186    }
187    /// construct a range `x_range: 0..x, y_range: 0..y`
188    pub fn from_ranges(x_range: Range<T>, y_range: Range<T>) -> Option<RectRange<T>> {
189        if !Self::range_ok(&x_range) || !Self::range_ok(&y_range) {
190            return None;
191        }
192        Some(RectRange { x_range, y_range })
193    }
194    /// checks if the range contains the point
195    pub fn contains<P: IntoTuple2<T>>(&self, p: P) -> bool {
196        let (x, y) = p.into_tuple2();
197        Self::contains_(&self.x_range, x) && Self::contains_(&self.y_range, y)
198    }
199    /// get a reference of x range
200    pub fn get_x(&self) -> &Range<T> {
201        &self.x_range
202    }
203    /// get a reference of y range
204    pub fn get_y(&self) -> &Range<T> {
205        &self.y_range
206    }
207    /// get a mutable reference of x range
208    pub fn get_mut_x(&mut self) -> &mut Range<T> {
209        &mut self.x_range
210    }
211    /// get a mutable reference of y range
212    pub fn get_mut_y(&mut self) -> &mut Range<T> {
213        &mut self.y_range
214    }
215    /// checks if the range is valid or not
216    pub fn is_valid(&self) -> bool {
217        Self::range_ok(&self.x_range) && Self::range_ok(&self.y_range)
218    }
219    fn range_ok(r: &Range<T>) -> bool {
220        r.start < r.end
221    }
222    /// we should switch to `RangeBound::contains` if it becomes stable
223    fn contains_(r: &Range<T>, val: T) -> bool {
224        r.start <= val && val < r.end
225    }
226}
227
228impl<T: Num + PartialOrd + Clone> RectRange<T> {
229    /// get x range
230    pub fn cloned_x(&self) -> Range<T> {
231        self.x_range.clone()
232    }
233    /// get y range
234    pub fn cloned_y(&self) -> Range<T> {
235        self.y_range.clone()
236    }
237    /// slide range by the given point
238    pub fn slide<P: IntoTuple2<T>>(self, t: P) -> RectRange<T> {
239        let t = t.into_tuple2();
240        RectRange {
241            x_range: self.x_range.start + t.0.clone()..self.x_range.end + t.0,
242            y_range: self.y_range.start + t.1.clone()..self.y_range.end + t.1,
243        }
244    }
245    /// slide start point without checking
246    pub fn slide_start<P: IntoTuple2<T>>(self, t: P) -> RectRange<T> {
247        let t = t.into_tuple2();
248        RectRange {
249            x_range: self.x_range.start + t.0.clone()..self.x_range.end,
250            y_range: self.y_range.start + t.1.clone()..self.y_range.end,
251        }
252    }
253    /// slide end point without checking
254    pub fn slide_end<P: IntoTuple2<T>>(self, t: P) -> RectRange<T> {
255        let t = t.into_tuple2();
256        RectRange {
257            x_range: self.x_range.start..self.x_range.end + t.0,
258            y_range: self.y_range.start..self.y_range.end + t.1,
259        }
260    }
261    /// the length in the x-axis deirection
262    pub fn xlen(&self) -> T {
263        let r = self.x_range.clone();
264        r.end - r.start
265    }
266    /// the length of in the y-axis deirection
267    pub fn ylen(&self) -> T {
268        let r = self.y_range.clone();
269        r.end - r.start
270    }
271    /// calc the area of the range
272    pub fn area(&self) -> T {
273        self.xlen() * self.ylen()
274    }
275    /// judges if 2 ranges have intersection
276    pub fn intersects(&self, other: &RectRange<T>) -> bool {
277        let not_inter = |r1: &Range<T>, r2: &Range<T>| r1.end <= r2.start || r2.end <= r1.start;
278        !(not_inter(&self.x_range, &other.x_range) || not_inter(&self.y_range, &other.y_range))
279    }
280    /// gets the intersection of 2 ranges
281    pub fn intersection(&self, other: &RectRange<T>) -> Option<RectRange<T>> {
282        let inter = |r1: Range<T>, r2: Range<T>| {
283            let s = max(r1.start, r2.start);
284            let e = min(r1.end, r2.end);
285            if s >= e {
286                None
287            } else {
288                Some(s..e)
289            }
290        };
291        Some(RectRange {
292            x_range: inter(self.x_range.clone(), other.x_range.clone())?,
293            y_range: inter(self.y_range.clone(), other.y_range.clone())?,
294        })
295    }
296    /// get the lower left corner(inclusive)
297    pub fn lower_left(&self) -> (T, T) {
298        (&self.x_range, &self.y_range).map(|r| r.start.clone())
299    }
300    /// get the lower right corner(inclusive)
301    pub fn lower_right(&self) -> (T, T) {
302        let x = self.x_range.end.clone() - T::one();
303        let y = self.y_range.start.clone();
304        (x, y)
305    }
306    /// get the upper left corner(inclusive)
307    pub fn upper_left(&self) -> (T, T) {
308        let x = self.x_range.start.clone();
309        let y = self.y_range.end.clone() - T::one();
310        (x, y)
311    }
312    /// get the upper right corner(inclusive)
313    pub fn upper_right(&self) -> (T, T) {
314        (&self.x_range, &self.y_range).map(|r| r.end.clone() - T::one())
315    }
316    /// checks if the point is on the edge of the rectangle
317    pub fn is_edge<P: IntoTuple2<T>>(&self, p: P) -> bool {
318        let (x, y) = p.into_tuple2();
319        self.contains((x.clone(), y.clone()))
320            && ((x, self.x_range.clone()), (y, self.y_range.clone()))
321                .any(|(p, r)| p == r.start || p == r.end - T::one())
322    }
323    /// checks if the point is on the vertical edge of the rectangle
324    pub fn is_vert_edge<P: IntoTuple2<T>>(&self, p: P) -> bool {
325        let (x, y) = p.into_tuple2();
326        let range = self.x_range.clone();
327        self.contains((x.clone(), y.clone())) && (x == range.start || x == range.end - T::one())
328    }
329    /// checks if the point is on the horizoni edge of the rectangle
330    pub fn is_horiz_edge<P: IntoTuple2<T>>(&self, p: P) -> bool {
331        let (x, y) = p.into_tuple2();
332        let range = self.y_range.clone();
333        self.contains((x.clone(), y.clone())) && (y == range.start || y == range.end - T::one())
334    }
335}
336
337impl<T: Num + PartialOrd + Copy> RectRange<T> {
338    #[cfg(feature = "euclid")]
339    pub fn from_rect<U>(rect: Rect<T, U>) -> Option<RectRange<T>> {
340        let orig_x = rect.origin.x;
341        let orig_y = rect.origin.y;
342        RectRange::from_ranges(
343            orig_x..orig_x + rect.size.width,
344            orig_y..orig_y + rect.size.height,
345        )
346    }
347    #[cfg(feature = "euclid")]
348    pub fn to_rect<U>(&self) -> Rect<T, U> {
349        let orig_x = self.x_range.start;
350        let orig_y = self.y_range.start;
351        rect(
352            orig_x,
353            orig_y,
354            self.x_range.end - orig_x,
355            self.y_range.end - orig_y,
356        )
357    }
358    /// generate RectRange from corners(lower: inclusive, upper: exclusive)
359    pub fn from_corners<P: IntoTuple2<T>>(lu: P, rd: P) -> Option<RectRange<T>> {
360        let lu = lu.into_tuple2();
361        let rd = rd.into_tuple2();
362        RectRange::new(lu.0, lu.1, rd.0, rd.1)
363    }
364    /// get iterator from reference
365    pub fn iter(&self) -> RectIter<T> {
366        self.clone().into_iter()
367    }
368    /// expand the rectangle
369    pub fn scale(self, sc: T) -> RectRange<T> {
370        let scale_impl = |r: Range<T>, s| r.start * s..r.end * s;
371        RectRange {
372            x_range: scale_impl(self.x_range, sc),
373            y_range: scale_impl(self.y_range, sc),
374        }
375    }
376}
377
378macro_rules! __cast_impl {
379    ($method:ident, $x:expr, $y:expr) => {
380        Some(RectRange {
381            x_range: $x.start.$method()?..$x.end.$method()?,
382            y_range: $y.start.$method()?..$y.end.$method()?,
383        })
384    };
385}
386impl<T: Num + PartialOrd + ToPrimitive + Copy> RectRange<T> {
387    pub fn to_u8(self) -> Option<RectRange<u8>> {
388        __cast_impl!(to_u8, self.x_range, self.y_range)
389    }
390    pub fn to_u16(self) -> Option<RectRange<u16>> {
391        __cast_impl!(to_u16, self.x_range, self.y_range)
392    }
393    pub fn to_u32(self) -> Option<RectRange<u32>> {
394        __cast_impl!(to_u32, self.x_range, self.y_range)
395    }
396    pub fn to_u64(self) -> Option<RectRange<u64>> {
397        __cast_impl!(to_u64, self.x_range, self.y_range)
398    }
399    pub fn to_i8(self) -> Option<RectRange<i8>> {
400        __cast_impl!(to_i8, self.x_range, self.y_range)
401    }
402    pub fn to_i16(self) -> Option<RectRange<i16>> {
403        __cast_impl!(to_i16, self.x_range, self.y_range)
404    }
405    pub fn to_i32(self) -> Option<RectRange<i32>> {
406        __cast_impl!(to_i32, self.x_range, self.y_range)
407    }
408    pub fn to_i64(self) -> Option<RectRange<i64>> {
409        __cast_impl!(to_i64, self.x_range, self.y_range)
410    }
411    pub fn to_usize(self) -> Option<RectRange<usize>> {
412        __cast_impl!(to_usize, self.x_range, self.y_range)
413    }
414}
415
416impl<T: Num + PartialOrd + Copy + FromPrimitive + ToPrimitive> RectRange<T> {
417    /// returns `self.xlen * self.ylen` as usize
418    pub fn len(&self) -> usize {
419        let (width, height) = (&self.x_range, &self.y_range)
420            .map(|r| r.clone())
421            .map(|r| r.end - r.start);
422        (width * height)
423            .to_usize()
424            .expect("[RectRange::len] invalid cast")
425    }
426    /// return 'nth' element
427    /// same as RectIter::nth, but much faster(O(1))
428    pub fn nth(&self, n: usize) -> Option<(T, T)> {
429        let width = self.x_range.end - self.x_range.start;
430        let width = width.to_usize()?;
431        let x = T::from_usize(n % width)? + self.x_range.start;
432        let y = T::from_usize(n / width)? + self.y_range.start;
433        if y >= self.y_range.end {
434            None
435        } else {
436            Some((x, y))
437        }
438    }
439    /// take Point and return 0-start unique index using the same order as RectIter
440    pub fn index<P: IntoTuple2<T>>(&self, p: P) -> Option<usize> {
441        let t = p.into_tuple2();
442        if !self.contains(t) {
443            return None;
444        }
445        let (x, y) = t.map(|i| i.to_usize());
446        let (start_x, start_y) = (&self.x_range, &self.y_range).map(|r| r.start.to_usize());
447        let xlen = self.xlen().to_usize()?;
448        Some(x? - start_x? + (y? - start_y?) * xlen)
449    }
450}
451
452impl<T: Num + PartialOrd + Copy> IntoIterator for RectRange<T> {
453    type Item = (T, T);
454    type IntoIter = RectIter<T>;
455    fn into_iter(self) -> Self::IntoIter {
456        RectIter {
457            front: (self.x_range.start, self.y_range.start),
458            back: (self.x_range.end - T::one(), self.y_range.end - T::one()),
459            end: false,
460            x_range: self.x_range.clone(),
461            y_range: self.y_range.clone(),
462        }
463    }
464}
465
466/// An Iterator type enumerating rectangle area.
467///
468/// You can construct it by RectRange.
469/// # Example
470/// ```
471/// # extern crate rect_iter; fn main() {
472/// use rect_iter::RectRange;
473/// let range = RectRange::zero_start(3, 4);
474/// for point in range {
475///     // some code here...
476/// }
477/// # }
478/// ```
479#[derive(Clone, Debug)]
480pub struct RectIter<T: Num + PartialOrd + Copy> {
481    front: (T, T),
482    back: (T, T),
483    end: bool,
484    x_range: Range<T>,
485    y_range: Range<T>,
486}
487
488impl<T: Num + PartialOrd + Copy> Iterator for RectIter<T> {
489    type Item = (T, T);
490    fn next(&mut self) -> Option<Self::Item> {
491        if self.end {
492            return None;
493        }
494        if self.front >= self.back {
495            self.end = true;
496            return Some(self.front);
497        }
498        let before = self.front;
499        if self.front.0 == self.x_range.end - T::one() {
500            self.front.0 = self.x_range.start;
501            self.front.1 = T::one() + self.front.1;
502        } else {
503            self.front.0 = T::one() + self.front.0;
504        }
505        Some(before)
506    }
507}
508
509impl<T: Num + PartialOrd + Copy> DoubleEndedIterator for RectIter<T> {
510    fn next_back(&mut self) -> Option<Self::Item> {
511        if self.end {
512            return None;
513        }
514        if self.front >= self.back {
515            self.end = true;
516            return Some(self.front);
517        }
518        let before = self.back;
519        if self.back.0 == self.x_range.start {
520            self.back.0 = self.x_range.end - T::one();
521            self.back.1 = self.back.1 - T::one();
522        } else {
523            self.back.0 = self.back.0 - T::one();
524        }
525        Some(before)
526    }
527}
528
529impl<T: Num + PartialOrd + Copy + ToPrimitive> ExactSizeIterator for RectIter<T> {
530    fn len(&self) -> usize {
531        if self.end {
532            0
533        } else {
534            let (xlen, ylen) = self.back.sub(self.front).add((T::one(), T::one()));
535            (xlen * ylen)
536                .to_usize()
537                .expect("[RectIter::len] invalid cast")
538        }
539    }
540}
541
542/// A trait which provides common access interfaces to 2D Array type.
543pub trait Get2D {
544    type Item;
545    fn get_xy<T: ToPrimitive>(&self, x: T, y: T) -> &Self::Item {
546        self.try_get_xy(x, y).expect("[Get2d::get] Invalid index")
547    }
548    fn get_p<T: ToPrimitive, P: IntoTuple2<T>>(&self, p: P) -> &Self::Item {
549        self.try_get_p(p).expect("[Get2d::get_p] Invalid index")
550    }
551    fn try_get_xy<T: ToPrimitive>(&self, x: T, y: T) -> Result<&Self::Item, IndexError>;
552    fn try_get_p<T: ToPrimitive, P: IntoTuple2<T>>(&self, p: P) -> Result<&Self::Item, IndexError> {
553        let t = p.into_tuple2();
554        self.try_get_xy(t.0, t.1)
555    }
556}
557
558pub trait GetMut2D: Get2D {
559    fn get_mut_xy<T: ToPrimitive>(&mut self, x: T, y: T) -> &mut Self::Item {
560        self.try_get_mut_xy(x, y)
561            .expect("[GetMut2d::get_mut_xy] Invalid index")
562    }
563    fn get_mut_p<T: ToPrimitive, P: IntoTuple2<T>>(&mut self, p: P) -> &mut Self::Item {
564        self.try_get_mut_p(p)
565            .expect("[GetMut2d::get_mut_p] Invalid index")
566    }
567    fn try_get_mut_xy<T: ToPrimitive>(&mut self, x: T, y: T)
568        -> Result<&mut Self::Item, IndexError>;
569    fn try_get_mut_p<T: ToPrimitive, P: IntoTuple2<T>>(
570        &mut self,
571        p: P,
572    ) -> Result<&mut Self::Item, IndexError> {
573        let t = p.into_tuple2();
574        self.try_get_mut_xy(t.0, t.1)
575    }
576}
577
578fn try_to_usize<T: ToPrimitive>(
579    x: T,
580    err: impl Fn(i64) -> IndexError,
581) -> Result<usize, IndexError> {
582    x.to_usize().ok_or_else(|| err(x.to_i64().unwrap()))
583}
584
585impl<D> Get2D for Vec<Vec<D>> {
586    type Item = D;
587    fn try_get_xy<T: ToPrimitive>(&self, x: T, y: T) -> Result<&Self::Item, IndexError> {
588        let x = try_to_usize(x, IndexError::X)?;
589        let y = try_to_usize(y, IndexError::Y)?;
590        let line = match self.get(y) {
591            Some(l) => l,
592            None => return Err(IndexError::Y(y as i64)),
593        };
594        match line.get(x) {
595            Some(res) => Ok(res),
596            None => Err(IndexError::X(x as i64)),
597        }
598    }
599}
600
601impl<D> GetMut2D for Vec<Vec<D>> {
602    fn try_get_mut_xy<T: ToPrimitive>(
603        &mut self,
604        x: T,
605        y: T,
606    ) -> Result<&mut Self::Item, IndexError> {
607        let x = try_to_usize(x, IndexError::X)?;
608        let y = try_to_usize(y, IndexError::Y)?;
609        let line = match self.get_mut(y) {
610            Some(l) => l,
611            None => return Err(IndexError::Y(y as i64)),
612        };
613        match line.get_mut(x) {
614            Some(res) => Ok(res),
615            None => Err(IndexError::X(x as i64)),
616        }
617    }
618}
619
620pub fn copy_rect_conv<T, U, I, J>(
621    source: &impl Get2D<Item = T>,
622    dest: &mut impl GetMut2D<Item = U>,
623    source_range: RectRange<I>,
624    dest_range: RectRange<J>,
625    convert: impl Fn(&T) -> U,
626) -> Result<(), IndexError>
627where
628    I: Num + PartialOrd + ToPrimitive + Copy,
629    J: Num + PartialOrd + ToPrimitive + Copy,
630{
631    source_range
632        .into_iter()
633        .zip(dest_range.into_iter())
634        .try_for_each(|(s, d)| {
635            *dest.try_get_mut_p(d)? = convert(source.try_get_p(s)?);
636            Ok(())
637        })
638}
639
640pub fn copy_rect<T, I, J>(
641    source: &impl Get2D<Item = T>,
642    dest: &mut impl GetMut2D<Item = T>,
643    source_range: RectRange<I>,
644    dest_range: RectRange<J>,
645) -> Result<(), IndexError>
646where
647    T: Clone,
648    I: Num + PartialOrd + ToPrimitive + Copy,
649    J: Num + PartialOrd + ToPrimitive + Copy,
650{
651    source_range
652        .into_iter()
653        .zip(dest_range.into_iter())
654        .try_for_each(|(s, d)| {
655            *dest.try_get_mut_p(d)? = source.try_get_p(s)?.clone();
656            Ok(())
657        })
658}
659
660pub fn gen_rect_conv<D, T, U, I, J>(
661    source: &impl Get2D<Item = T>,
662    gen_dist: impl Fn() -> D,
663    source_range: RectRange<I>,
664    dest_range: RectRange<J>,
665    convert: impl Fn(&T) -> U,
666) -> Result<D, IndexError>
667where
668    D: GetMut2D<Item = U> + Default,
669    T: Clone,
670    I: Num + PartialOrd + ToPrimitive + Copy,
671    J: Num + PartialOrd + ToPrimitive + Copy,
672{
673    source_range
674        .into_iter()
675        .zip(dest_range.into_iter())
676        .try_fold(gen_dist(), |mut dest, (s, d)| {
677            *dest.try_get_mut_p(d)? = convert(source.try_get_p(s)?);
678            Ok(dest)
679        })
680}
681
682pub fn gen_rect<D, T, I, J>(
683    source: &impl Get2D<Item = T>,
684    gen_dist: impl Fn() -> D,
685    source_range: RectRange<I>,
686    dest_range: RectRange<J>,
687) -> Result<D, IndexError>
688where
689    D: GetMut2D<Item = T> + Default,
690    T: Clone,
691    I: Num + PartialOrd + ToPrimitive + Copy,
692    J: Num + PartialOrd + ToPrimitive + Copy,
693{
694    source_range
695        .into_iter()
696        .zip(dest_range.into_iter())
697        .try_fold(gen_dist(), |mut dest, (s, d)| {
698            *dest.try_get_mut_p(d)? = source.try_get_p(s)?.clone();
699            Ok(dest)
700        })
701}
702
703#[cfg(feature = "image")]
704fn try_to_u32<T: ToPrimitive>(x: T, err: impl Fn(i64) -> IndexError) -> Result<u32, IndexError> {
705    x.to_u32().ok_or_else(|| err(x.to_i64().unwrap()))
706}
707
708#[cfg(feature = "image")]
709impl<P, C> Get2D for ImageBuffer<P, C>
710where
711    P: Pixel + 'static,
712    P::Subpixel: 'static,
713    C: Deref<Target = [P::Subpixel]>,
714{
715    type Item = P;
716    fn try_get_xy<T: ToPrimitive>(&self, x: T, y: T) -> Result<&Self::Item, IndexError> {
717        let x = try_to_u32(x, IndexError::X)?;
718        let y = try_to_u32(y, IndexError::Y)?;
719        if x >= self.width() {
720            return Err(IndexError::X(i64::from(x)));
721        }
722        if y >= self.height() {
723            return Err(IndexError::Y(i64::from(y)));
724        }
725        Ok(self.get_pixel(x, y))
726    }
727}
728
729#[cfg(feature = "image")]
730impl<P, C> GetMut2D for ImageBuffer<P, C>
731where
732    P: Pixel + 'static,
733    P::Subpixel: 'static,
734    C: Deref<Target = [P::Subpixel]> + DerefMut,
735{
736    fn try_get_mut_xy<T: ToPrimitive>(
737        &mut self,
738        x: T,
739        y: T,
740    ) -> Result<&mut Self::Item, IndexError> {
741        let x = try_to_u32(x, IndexError::X)?;
742        let y = try_to_u32(y, IndexError::Y)?;
743        if x >= self.width() {
744            return Err(IndexError::X(i64::from(x)));
745        }
746        if y >= self.height() {
747            return Err(IndexError::Y(i64::from(y)));
748        }
749        Ok(self.get_pixel_mut(x, y))
750    }
751}
752
753#[cfg(feature = "ndarray")]
754impl<S: Data> Get2D for ArrayBase<S, Ix2> {
755    type Item = S::Elem;
756    fn try_get_xy<T: ToPrimitive>(&self, x: T, y: T) -> Result<&Self::Item, IndexError> {
757        let x = try_to_usize(x, IndexError::X)?;
758        let y = try_to_usize(y, IndexError::Y)?;
759        {
760            let shape = self.shape();
761            if x >= shape[1] {
762                return Err(IndexError::X(x as i64));
763            }
764            if y >= shape[0] {
765                return Err(IndexError::Y(y as i64));
766            }
767        }
768        Ok(unsafe { self.uget([y, x]) })
769    }
770}
771
772#[cfg(feature = "ndarray")]
773impl<S: DataMut> GetMut2D for ArrayBase<S, Ix2> {
774    fn try_get_mut_xy<T: ToPrimitive>(
775        &mut self,
776        x: T,
777        y: T,
778    ) -> Result<&mut Self::Item, IndexError> {
779        let x = try_to_usize(x, IndexError::X)?;
780        let y = try_to_usize(y, IndexError::Y)?;
781        {
782            let shape = self.shape();
783            if x >= shape[1] {
784                return Err(IndexError::X(x as i64));
785            }
786            if y >= shape[0] {
787                return Err(IndexError::Y(y as i64));
788            }
789        }
790        Ok(unsafe { self.uget_mut([y, x]) })
791    }
792}
793
794fn min<T: Clone + PartialOrd>(x: T, y: T) -> T {
795    if x <= y {
796        x
797    } else {
798        y
799    }
800}
801
802fn max<T: Clone + PartialOrd>(x: T, y: T) -> T {
803    if x >= y {
804        x
805    } else {
806        y
807    }
808}
809
810#[cfg(test)]
811mod tests {
812    use super::*;
813    #[test]
814    fn iter_test_normal() {
815        let r = RectRange::from_ranges(4..7, 3..5).unwrap();
816        let correct = [(4, 3), (5, 3), (6, 3), (4, 4), (5, 4), (6, 4)];
817        for (i, (x, y)) in r.into_iter().enumerate() {
818            assert_eq!(correct[i], (x, y));
819        }
820    }
821    #[test]
822    fn iter_test_rev() {
823        let r = RectRange::from_ranges(4..7, 3..5).unwrap();
824        let correct = [(4, 3), (5, 3), (6, 3), (4, 4), (5, 4), (6, 4)];
825        for (&c, t) in correct.into_iter().rev().zip(r.into_iter().rev()) {
826            assert_eq!(c, t);
827        }
828    }
829    #[test]
830    fn test_intersects_true() {
831        let r1 = RectRange::from_ranges(4..7, 3..5).unwrap();
832        let r2 = RectRange::from_ranges(6..10, 4..6).unwrap();
833        assert_eq!(r1.intersects(&r2), true)
834    }
835    #[test]
836    fn test_intersection_some() {
837        let r1 = RectRange::from_ranges(4..7, 3..5).unwrap();
838        let r2 = RectRange::from_ranges(6..10, 4..6).unwrap();
839        let inter = RectRange::from_ranges(6..7, 4..5).unwrap();
840        assert_eq!(r1.intersection(&r2).unwrap(), inter);
841    }
842    #[test]
843    fn test_intersects_false() {
844        let r1 = RectRange::from_ranges(4..7, 3..5).unwrap();
845        let r2 = RectRange::from_ranges(7..9, 5..6).unwrap();
846        assert_eq!(r1.intersects(&r2), false)
847    }
848    #[test]
849    fn test_intersection_none() {
850        let r1 = RectRange::from_ranges(4..7, 3..5).unwrap();
851        let r2 = RectRange::from_ranges(7..9, 5..6).unwrap();
852        assert!(r1.intersection(&r2).is_none());
853    }
854    #[test]
855    fn test_get_vec() {
856        let a = vec![vec![3; 5]; 7];
857        assert_eq!(&3, a.get_xy(3, 3));
858        assert_eq!(Err(IndexError::Y(7)), a.try_get_xy(5, 7));
859    }
860    #[test]
861    fn test_copy_rect() {
862        let mut a = vec![vec![3; 5]; 7];
863        let r1 = RectRange::from_ranges(3..5, 2..6).unwrap();
864        let b = vec![vec![80; 100]; 100];
865        copy_rect(&b, &mut a, r1.clone(), r1.clone()).unwrap();
866        r1.into_iter().for_each(|p| assert_eq!(a.get_p(p), &80));
867    }
868    #[test]
869    fn test_gen_rect() {
870        let r = RectRange::zero_start(5, 7).unwrap();
871        let b = vec![vec![80; 100]; 100];
872        let a = gen_rect(&b, || vec![vec![0; 5]; 7], r.clone(), r.clone()).unwrap();
873        for i in r {
874            println!("{:?}", i);
875        }
876        assert_eq!(vec![vec![80; 5]; 7], a);
877    }
878    #[test]
879    fn test_length() {
880        let r = RectRange::zero_start(7, 8).unwrap();
881        assert_eq!(r.len(), 56);
882        let iter = r.into_iter();
883        assert_eq!(iter.len(), 56);
884    }
885    #[test]
886    fn test_nth() {
887        let r = RectRange::from_ranges(4..7, 3..7).unwrap();
888        assert_eq!(r.nth(7), r.iter().nth(7));
889        assert_eq!(r.nth(12), None);
890    }
891    #[test]
892    fn test_contains() {
893        let r = RectRange::from_ranges(4..7, 3..7).unwrap();
894        assert!(r.contains((6, 6)));
895        assert!(!r.contains((6, 7)));
896    }
897    #[test]
898    fn test_is_edge() {
899        let r = RectRange::from_ranges(4..7, 3..7).unwrap();
900        assert!(r.is_edge((6, 6)));
901        assert!(r.is_edge((4, 5)));
902        assert!(!r.is_edge((4, 7)));
903    }
904    #[test]
905    fn test_index() {
906        let r = RectRange::from_ranges(4..7, 3..7).unwrap();
907        for i in 0..r.len() {
908            let cd = r.nth(i).unwrap();
909            assert_eq!(r.index(cd), Some(i));
910        }
911        assert_eq!(r.index((6, 7)), None);
912    }
913    #[test]
914    fn test_is_vert_edge() {
915        let r = RectRange::from_ranges(4..7, 3..7).unwrap();
916        assert!(r.is_vert_edge((4, 5)));
917        assert!(!r.is_vert_edge((5, 6)));
918    }
919    #[test]
920    fn test_is_horiz_edge() {
921        let r = RectRange::from_ranges(4..7, 3..7).unwrap();
922        assert!(!r.is_horiz_edge((4, 5)));
923        assert!(r.is_horiz_edge((5, 6)));
924    }
925    #[test]
926    fn test_corners() {
927        let r = RectRange::from_ranges(4..7, 3..7).unwrap();
928        assert_eq!(r.lower_left(), (4, 3));
929        assert_eq!(r.lower_right(), (6, 3));
930        assert_eq!(r.upper_left(), (4, 6));
931        assert_eq!(r.upper_right(), (6, 6));
932    }
933
934    #[cfg(feature = "ndarray")]
935    #[test]
936    fn test_ndarray() {
937        use super::ndarray::arr2;
938        let a = arr2(&[[1, 2], [3, 4]]);
939        assert_eq!(a.get_xy(1, 0), &2);
940        assert!(a.try_get_xy(4, 0).is_err());
941        assert!(a.try_get_xy(-1, 0).is_err());
942    }
943}