#[derive(Debug, Clone, PartialEq)]
pub enum RasterError {
OutOfBounds,
InvalidChunkSize,
IoError(String),
AlgorithmError(String),
}
impl std::fmt::Display for RasterError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::OutOfBounds => write!(f, "raster read out of bounds"),
Self::InvalidChunkSize => write!(f, "chunk size must be > 0"),
Self::IoError(s) => write!(f, "IO error: {}", s),
Self::AlgorithmError(s) => write!(f, "algorithm error: {}", s),
}
}
}
impl std::error::Error for RasterError {}
pub trait RasterSource {
fn width(&self) -> usize;
fn height(&self) -> usize;
fn read_window(&self, x: usize, y: usize, w: usize, h: usize) -> Result<Vec<f32>, RasterError>;
}
pub struct InMemoryRasterSource {
data: Vec<f32>,
width: usize,
height: usize,
}
impl InMemoryRasterSource {
pub fn new(data: Vec<f32>, width: usize, height: usize) -> Self {
assert_eq!(
data.len(),
width * height,
"data length must equal width * height"
);
Self {
data,
width,
height,
}
}
pub fn data(&self) -> &[f32] {
&self.data
}
}
impl RasterSource for InMemoryRasterSource {
fn width(&self) -> usize {
self.width
}
fn height(&self) -> usize {
self.height
}
fn read_window(&self, x: usize, y: usize, w: usize, h: usize) -> Result<Vec<f32>, RasterError> {
if x >= self.width || y >= self.height {
return Err(RasterError::OutOfBounds);
}
let mut out = Vec::with_capacity(w * h);
for row in 0..h {
for col in 0..w {
let src_x = x + col;
let src_y = y + row;
if src_x < self.width && src_y < self.height {
out.push(self.data[src_y * self.width + src_x]);
} else {
out.push(0.0_f32);
}
}
}
Ok(out)
}
}
pub struct Chunk {
pub x: usize,
pub y: usize,
pub width: usize,
pub height: usize,
pub halo: usize,
pub data: Vec<f32>,
}
impl Chunk {
#[inline]
pub fn get_core(&self, col: usize, row: usize) -> f32 {
let full_w = self.width + 2 * self.halo;
self.data[(row + self.halo) * full_w + (col + self.halo)]
}
#[inline]
pub fn full_width(&self) -> usize {
self.width + 2 * self.halo
}
#[inline]
pub fn full_height(&self) -> usize {
self.height + 2 * self.halo
}
}