use std::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct VolumeShape {
pub nx: usize,
pub ny: usize,
pub nz: usize,
}
impl VolumeShape {
pub const fn new(nx: usize, ny: usize, nz: usize) -> Self {
Self { nx, ny, nz }
}
pub fn from_header(header: &crate::Header) -> Self {
Self {
nx: header.nx as usize,
ny: header.ny as usize,
nz: header.nz as usize,
}
}
pub fn total_voxels(&self) -> Option<usize> {
self.nx.checked_mul(self.ny)?.checked_mul(self.nz)
}
pub const fn is_empty(&self) -> bool {
self.nx == 0 || self.ny == 0 || self.nz == 0
}
pub fn contains_block(&self, offset: [usize; 3], shape: [usize; 3]) -> bool {
let [ox, oy, oz] = offset;
let [sx, sy, sz] = shape;
ox.checked_add(sx).is_some_and(|x| x <= self.nx)
&& oy.checked_add(sy).is_some_and(|y| y <= self.ny)
&& oz.checked_add(sz).is_some_and(|z| z <= self.nz)
}
pub fn checked_linear_index(&self, offset: [usize; 3]) -> Option<usize> {
let [ox, oy, oz] = offset;
ox.checked_add(
oy.checked_mul(self.nx)?
.checked_add(oz.checked_mul(self.nx)?.checked_mul(self.ny)?)?,
)
}
}
#[derive(Debug, Clone)]
pub struct VoxelBlock<T> {
pub offset: [usize; 3],
pub shape: [usize; 3],
pub data: Vec<T>,
}
impl<T> VoxelBlock<T> {
pub fn new(
offset: [usize; 3],
shape: [usize; 3],
data: Vec<T>,
) -> Result<Self, crate::Error> {
Self::try_new(offset, shape, data)
}
pub fn try_new(
offset: [usize; 3],
shape: [usize; 3],
data: Vec<T>,
) -> Result<Self, crate::Error> {
let expected = shape[0]
.checked_mul(shape[1])
.and_then(|v| v.checked_mul(shape[2]))
.ok_or(crate::Error::BoundsError)?;
if data.len() != expected {
return Err(crate::Error::BlockShapeMismatch {
expected,
actual: data.len(),
});
}
Ok(Self {
offset,
shape,
data,
})
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn is_full_volume(&self, volume_shape: &VolumeShape) -> bool {
self.offset == [0, 0, 0]
&& self.shape == [volume_shape.nx, volume_shape.ny, volume_shape.nz]
}
}