1#[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#[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
81pub trait IntoTuple2<T> {
99 fn into_tuple2(self) -> (T, T);
100}
101
102pub 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#[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 pub fn new(lx: T, ly: T, ux: T, uy: T) -> Option<RectRange<T>> {
176 RectRange::from_ranges(lx..ux, ly..uy)
177 }
178 pub fn zero_start(x: T, y: T) -> Option<RectRange<T>> {
180 RectRange::from_ranges(T::zero()..x, T::zero()..y)
181 }
182 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 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 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 pub fn get_x(&self) -> &Range<T> {
201 &self.x_range
202 }
203 pub fn get_y(&self) -> &Range<T> {
205 &self.y_range
206 }
207 pub fn get_mut_x(&mut self) -> &mut Range<T> {
209 &mut self.x_range
210 }
211 pub fn get_mut_y(&mut self) -> &mut Range<T> {
213 &mut self.y_range
214 }
215 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 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 pub fn cloned_x(&self) -> Range<T> {
231 self.x_range.clone()
232 }
233 pub fn cloned_y(&self) -> Range<T> {
235 self.y_range.clone()
236 }
237 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 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 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 pub fn xlen(&self) -> T {
263 let r = self.x_range.clone();
264 r.end - r.start
265 }
266 pub fn ylen(&self) -> T {
268 let r = self.y_range.clone();
269 r.end - r.start
270 }
271 pub fn area(&self) -> T {
273 self.xlen() * self.ylen()
274 }
275 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 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 pub fn lower_left(&self) -> (T, T) {
298 (&self.x_range, &self.y_range).map(|r| r.start.clone())
299 }
300 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 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 pub fn upper_right(&self) -> (T, T) {
314 (&self.x_range, &self.y_range).map(|r| r.end.clone() - T::one())
315 }
316 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 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 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 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 pub fn iter(&self) -> RectIter<T> {
366 self.clone().into_iter()
367 }
368 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 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 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 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#[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
542pub 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}