nsys-mat 0.5.4

Dynamically sized 2d storage with rectangular iterators and in-place resizing
Documentation
#[cfg(feature="serde")]
use serde::{Deserialize, Serialize};

use super::{Coordinate, Dimensions};

/// Rectangle defined by inclusive minimum and maximum coordinates.
///
/// ```
/// # use mat::Rectangle;
/// let rectangle = Rectangle::from (((1, 2).into(), (5, 3).into()));
/// assert_eq!(rectangle.height(), 5);
/// assert_eq!(rectangle.width(),  3);
/// assert_eq!(rectangle.height(), rectangle.dimensions.rows);
/// assert_eq!(rectangle.width(),  rectangle.dimensions.columns);
/// assert_eq!(rectangle.contains ((0, 0).into()), false);
/// assert_eq!(rectangle.contains ((4, 3).into()), true);
/// ```
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Clone, Eq, Debug, Default, PartialEq)]
pub struct Rectangle {
  pub coordinate : Coordinate,
  pub dimensions : Dimensions
}

impl Rectangle {
  #[inline]
  pub const fn width (&self) -> usize {
    self.dimensions.columns
  }
  #[inline]
  pub const fn height (&self) -> usize {
    self.dimensions.rows
  }
  #[inline]
  pub const fn min (&self) -> Coordinate {
    self.coordinate
  }
  /// Max is inclusive: this is the lower right corner element of the rectangle
  #[inline]
  pub const fn max (&self) -> Coordinate {
    Coordinate {
      row:    self.coordinate.row + self.height() - 1,
      column: self.coordinate.column + self.width() - 1,
    }
  }
  #[inline]
  pub const fn upper_left (&self) -> Coordinate {
    self.min()
  }
  #[inline]
  pub const fn upper_right (&self) -> Coordinate {
    Coordinate {
      row:    self.min().row,
      column: self.max().column
    }
  }
  #[inline]
  pub const fn lower_right (&self) -> Coordinate {
    self.max()
  }
  #[inline]
  pub const fn lower_left (&self) -> Coordinate {
    Coordinate {
      row:    self.max().row,
      column: self.min().column
    }
  }
  #[inline]
  pub fn row (&self, row : usize) -> Option <Self> {
    if row < self.height() {
      let coordinate = self.min() + (row, 0).into();
      let dimensions = (1, self.width()).into();
      Some (Rectangle { coordinate, dimensions })
    } else {
      None
    }
  }
  #[inline]
  pub fn column (&self, column : usize) -> Option <Self> {
    if column < self.width() {
      let coordinate = self.min() + (0, column).into();
      let dimensions = (self.height(), 1).into();
      Some (Rectangle { coordinate, dimensions })
    } else {
      None
    }
  }
  /// Rows * columns
  #[inline]
  pub const fn area (&self) -> usize {
    self.height() * self.width()
  }
  /// Return true if the coordinate is between `min` and `max` (inclusive)
  #[inline]
  pub fn contains (&self, Coordinate { row, column } : Coordinate) -> bool {
    self.contains_rc (row, column)
  }
  #[inline]
  pub fn contains_rc (&self, row : usize, column : usize) -> bool {
    self.min().row    <= row    && row    <= self.max().row &&
    self.min().column <= column && column <= self.max().column
  }
  #[inline]
  pub fn iter (&self) -> impl Iterator <Item = Coordinate> {
    let row    = self.min().row;
    let col    = self.min().column;
    let height = self.height();
    let width  = self.width();
    (row..row + height).map (move |row| std::iter::repeat (row)
      .zip (col..col + width)).flatten().map (Into::into)
  }
} // end impl Rectangle
impl From <(Coordinate, Dimensions)> for Rectangle {
  fn from ((coordinate, dimensions) : (Coordinate, Dimensions)) -> Self {
    Rectangle { coordinate, dimensions }
  }
}
impl From <Dimensions> for Rectangle {
  fn from (dimensions : Dimensions) -> Self {
    Rectangle { coordinate: (0, 0).into(), dimensions }
  }
}