mat/
rectangle.rs

1#[cfg(feature="serde")]
2use serde::{Deserialize, Serialize};
3
4use super::{Coordinate, Dimensions};
5
6/// Rectangle defined by inclusive minimum and maximum coordinates.
7///
8/// ```
9/// # use mat::Rectangle;
10/// let rectangle = Rectangle::from (((1, 2).into(), (5, 3).into()));
11/// assert_eq!(rectangle.height(), 5);
12/// assert_eq!(rectangle.width(),  3);
13/// assert_eq!(rectangle.height(), rectangle.dimensions.rows);
14/// assert_eq!(rectangle.width(),  rectangle.dimensions.columns);
15/// assert_eq!(rectangle.contains ((0, 0).into()), false);
16/// assert_eq!(rectangle.contains ((4, 3).into()), true);
17/// ```
18#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
19#[derive(Clone, Eq, Debug, Default, PartialEq)]
20pub struct Rectangle {
21  pub coordinate : Coordinate,
22  pub dimensions : Dimensions
23}
24
25impl Rectangle {
26  #[inline]
27  pub const fn width (&self) -> usize {
28    self.dimensions.columns
29  }
30  #[inline]
31  pub const fn height (&self) -> usize {
32    self.dimensions.rows
33  }
34  #[inline]
35  pub const fn min (&self) -> Coordinate {
36    self.coordinate
37  }
38  /// Max is inclusive: this is the lower right corner element of the rectangle
39  #[inline]
40  pub const fn max (&self) -> Coordinate {
41    Coordinate {
42      row:    self.coordinate.row + self.height() - 1,
43      column: self.coordinate.column + self.width() - 1,
44    }
45  }
46  #[inline]
47  pub const fn upper_left (&self) -> Coordinate {
48    self.min()
49  }
50  #[inline]
51  pub const fn upper_right (&self) -> Coordinate {
52    Coordinate {
53      row:    self.min().row,
54      column: self.max().column
55    }
56  }
57  #[inline]
58  pub const fn lower_right (&self) -> Coordinate {
59    self.max()
60  }
61  #[inline]
62  pub const fn lower_left (&self) -> Coordinate {
63    Coordinate {
64      row:    self.max().row,
65      column: self.min().column
66    }
67  }
68  #[inline]
69  pub fn row (&self, row : usize) -> Option <Self> {
70    if row < self.height() {
71      let coordinate = self.min() + (row, 0).into();
72      let dimensions = (1, self.width()).into();
73      Some (Rectangle { coordinate, dimensions })
74    } else {
75      None
76    }
77  }
78  #[inline]
79  pub fn column (&self, column : usize) -> Option <Self> {
80    if column < self.width() {
81      let coordinate = self.min() + (0, column).into();
82      let dimensions = (self.height(), 1).into();
83      Some (Rectangle { coordinate, dimensions })
84    } else {
85      None
86    }
87  }
88  /// Rows * columns
89  #[inline]
90  pub const fn area (&self) -> usize {
91    self.height() * self.width()
92  }
93  /// Return true if the coordinate is between `min` and `max` (inclusive)
94  #[inline]
95  pub fn contains (&self, Coordinate { row, column } : Coordinate) -> bool {
96    self.contains_rc (row, column)
97  }
98  #[inline]
99  pub fn contains_rc (&self, row : usize, column : usize) -> bool {
100    self.min().row    <= row    && row    <= self.max().row &&
101    self.min().column <= column && column <= self.max().column
102  }
103  #[inline]
104  pub fn iter (&self) -> impl Iterator <Item = Coordinate> {
105    let row    = self.min().row;
106    let col    = self.min().column;
107    let height = self.height();
108    let width  = self.width();
109    (row..row + height).map (move |row| std::iter::repeat (row)
110      .zip (col..col + width)).flatten().map (Into::into)
111  }
112} // end impl Rectangle
113impl From <(Coordinate, Dimensions)> for Rectangle {
114  fn from ((coordinate, dimensions) : (Coordinate, Dimensions)) -> Self {
115    Rectangle { coordinate, dimensions }
116  }
117}
118impl From <Dimensions> for Rectangle {
119  fn from (dimensions : Dimensions) -> Self {
120    Rectangle { coordinate: (0, 0).into(), dimensions }
121  }
122}