use crate::index::Array2dIndexing;
use crate::storage::{Array2dStorage, Array2dStorageMut, Array2dStorageOwned};
use crate::util::*;
use crate::{Array2dMut, Array2dRef, Boundary, GenericArray2d, IntoBoundary};
use mint::Vector2;
impl<T: Array2dStorage> GenericArray2d<T> {
pub fn is_empty(&self) -> bool {
self.boundary.is_empty()
}
pub fn len(&self) -> usize {
self.boundary.len()
}
pub fn width(&self) -> usize {
self.boundary.dimension.x as usize
}
pub fn height(&self) -> usize {
self.boundary.dimension.y as usize
}
pub fn min_point<U: From<Vector2<i32>>>(&self) -> U {
self.boundary.min.into()
}
pub fn max_point<U: From<Vector2<i32>>>(&self) -> U {
self.boundary.max().into()
}
pub fn dimension<U: From<Vector2<u32>>>(&self) -> U {
self.boundary.dimension.into()
}
pub fn boundary(&self) -> Boundary {
self.boundary
}
pub fn contains(&self, position: impl Into<Vector2<i32>>) -> bool {
self.boundary.contains(position)
}
pub fn get<I: Array2dIndexing<M>, M>(&self, point: I) -> I::Result<'_, T::Item> {
point.index(self)
}
pub fn fetch(&self, point: impl Into<Vector2<i32>>) -> T::Item
where
T::Item: Clone + Default,
{
point.index(self).cloned().unwrap_or_default()
}
pub fn iter<U: From<Vector2<i32>>>(&self) -> impl Iterator<Item = (U, &T::Item)> {
let min = self.boundary.min;
DimensionIter::new(self.boundary.dimension)
.map(move |x| add(x, min))
.map(|x| U::from(x))
.zip(self.values())
}
pub fn rows(&self) -> impl Iterator<Item = &[T::Item]> {
let slice = self.data.slice();
let len = self.boundary.dimension.x as usize;
slice
.chunks(self.pitch.max(1))
.map(move |slice| &slice[..len])
.take(self.boundary.dimension.y as usize)
}
pub fn values(&self) -> impl Iterator<Item = &T::Item> {
self.rows().flatten()
}
pub fn slice(&self, boundary: impl IntoBoundary) -> Array2dRef<T::Item> {
self.slice_internal(boundary.into_boundary()).1
}
pub fn displace(&mut self, by: impl Into<Vector2<i32>>) {
self.boundary.min = add(self.boundary.min, by.into());
}
pub fn displaced(mut self, by: impl Into<Vector2<i32>>) -> Self {
self.boundary.min = add(self.boundary.min, by.into());
self
}
}
impl<T: Array2dStorageMut> GenericArray2d<T> {
pub fn get_mut<I: Array2dIndexing<M>, M>(&mut self, point: I) -> I::ResultMut<'_, T::Item> {
point.index_mut(self)
}
pub fn set(&mut self, point: impl Into<Vector2<i32>>, value: T::Item) -> bool {
if let Some(v) = point.index_mut(self) {
*v = value;
true
} else {
false
}
}
pub fn iter_mut<U: From<Vector2<i32>>>(&mut self) -> impl Iterator<Item = (U, &mut T::Item)> {
let min = self.boundary.min;
DimensionIter::new(self.boundary.dimension)
.map(move |x| add(x, min))
.map(|x| U::from(x))
.zip(self.values_mut())
}
pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [T::Item]> {
let slice = self.data.slice_mut();
let len = self.boundary.dimension.x as usize;
slice
.chunks_mut(self.pitch.max(1))
.map(move |slice| &mut slice[..len])
.take(self.boundary.dimension.x as usize)
}
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T::Item> {
self.rows_mut().flatten()
}
pub fn fill(&mut self, value: T::Item)
where
T::Item: Clone,
{
for row in self.rows_mut() {
for item in row {
*item = value.clone();
}
}
}
pub fn slice_mut(&mut self, boundary: impl IntoBoundary) -> Array2dMut<T::Item> {
self.slice_mut_internal(boundary.into_boundary()).1
}
pub fn paint<U>(
&mut self,
brush: &GenericArray2d<impl Array2dStorage<Item = U>>,
at: impl Into<Vector2<i32>>,
mut paint_fn: impl FnMut(&mut T::Item, &U),
) {
let at = at.into();
let region = Boundary {
min: add(brush.boundary.min, at),
dimension: brush.boundary.dimension,
};
let Some(intersection) = self.boundary.intersection(region) else {
return;
};
let mut base1 = offset_of(intersection.min, self.boundary.min, self.pitch);
let mut base2 = offset_of(intersection.min, region.min, brush.pitch);
for _ in 0..intersection.dimension.y as usize {
for i in 0..intersection.dimension.x as usize {
paint_fn(
&mut self.data.slice_mut()[base1 + i],
&brush.data.slice()[base2 + i],
)
}
base1 += self.pitch;
base2 += brush.pitch;
}
}
}
impl<T: Array2dStorageOwned> GenericArray2d<T> {
pub fn init<U: From<Vector2<i32>>>(
boundary: impl IntoBoundary,
mut init: impl FnMut(U) -> T::Item,
) -> Self {
let boundary = boundary.into_boundary();
let len = boundary.len();
let mut vec = Vec::with_capacity(len);
vec.extend(
DimensionIter::new(boundary.dimension).map(|v| init(add(v, boundary.min).into())),
);
Self {
data: T::from_vec(vec),
boundary,
pitch: boundary.pitch(),
}
}
pub fn underlying_slice(&self) -> &[T::Item] {
&self.data.slice()[..self.len()]
}
pub fn new_filled(boundary: impl IntoBoundary, fill: T::Item) -> Self
where
T::Item: Clone,
{
let boundary = boundary.into_boundary();
let len = boundary.len();
let mut vec = Vec::new();
vec.resize(len, fill.clone());
Self {
data: T::from_vec(vec),
boundary,
pitch: boundary.pitch(),
}
}
#[track_caller]
pub fn from_vec(vec: Vec<T::Item>, boundary: impl IntoBoundary) -> Self {
let boundary = boundary.into_boundary();
assert!(vec.len() >= boundary.len(), "Not enough items.");
GenericArray2d {
data: T::from_vec(vec),
boundary,
pitch: boundary.pitch(),
}
}
pub fn new(boundary: impl IntoBoundary) -> Self
where
T::Item: Default,
{
let boundary = boundary.into_boundary();
let len = boundary.len();
let mut vec = Vec::new();
vec.resize_with(len, Default::default);
Self {
data: T::from_vec(vec),
boundary,
pitch: boundary.pitch(),
}
}
pub fn clear(&mut self)
where
GenericArray2d<T>: Default,
{
*self = Default::default();
}
pub fn iter_owned<U: From<Vector2<i32>>>(self) -> impl Iterator<Item = (U, T::Item)> {
let min = self.boundary.min;
IterOwned {
iter: self.data.into_owned_iter(),
position: Vector2 { x: 0, y: 0 },
dimension: self.boundary.dimension,
pitch: self.pitch as u32,
}
.map(move |(i, v)| (add(i, min).into(), v))
}
}
impl<'t, T> Array2dRef<'t, T> {
pub fn from_slice(slice: &'t [T], boundary: impl IntoBoundary) -> Self {
let boundary = boundary.into_boundary();
assert!(slice.len() >= boundary.len(), "Not enough items.");
Array2dRef {
data: slice,
boundary,
pitch: boundary.pitch(),
}
}
pub fn from_slice_pitch(slice: &'t [T], boundary: impl IntoBoundary, pitch: usize) -> Self {
let boundary = boundary.into_boundary();
assert!(
slice.len() >= boundary.dimension.y as usize * pitch,
"Not enough items."
);
assert!(
pitch >= boundary.pitch(),
"Pitch must be larger than boundary."
);
Array2dRef {
data: slice,
boundary,
pitch,
}
}
}
impl<'t, T> Array2dMut<'t, T> {
pub fn from_slice(slice: &'t mut [T], boundary: impl IntoBoundary) -> Self {
let boundary = boundary.into_boundary();
assert!(slice.len() >= boundary.len(), "Not enough items.");
Array2dMut {
data: slice,
boundary,
pitch: boundary.pitch(),
}
}
pub fn from_slice_pitch(slice: &'t mut [T], boundary: impl IntoBoundary, pitch: usize) -> Self {
let boundary = boundary.into_boundary();
assert!(
slice.len() >= boundary.dimension.y as usize * pitch,
"Not enough items."
);
assert!(
pitch >= boundary.pitch(),
"Pitch must be larger than boundary."
);
Array2dMut {
data: slice,
boundary,
pitch,
}
}
}