use super::ChunkedRaster;
use super::chunk::{Chunk, RasterError, RasterSource};
pub struct ChunkIterator<'r, R: RasterSource> {
raster: &'r ChunkedRaster<R>,
current_x: usize,
current_y: usize,
}
impl<'r, R: RasterSource> ChunkIterator<'r, R> {
pub fn new(raster: &'r ChunkedRaster<R>) -> Self {
Self {
raster,
current_x: 0,
current_y: 0,
}
}
}
impl<'r, R: RasterSource> Iterator for ChunkIterator<'r, R> {
type Item = Result<Chunk, RasterError>;
fn next(&mut self) -> Option<Self::Item> {
if self.current_y >= self.raster.total_height {
return None;
}
let x = self.current_x;
let y = self.current_y;
let halo = self.raster.halo;
let w = self.raster.chunk_size.min(self.raster.total_width - x);
let h = self.raster.chunk_size.min(self.raster.total_height - y);
let full_w = w + 2 * halo;
let full_h = h + 2 * halo;
let mut data = vec![0.0_f32; full_w * full_h];
let src_left = x.saturating_sub(halo);
let src_top = y.saturating_sub(halo);
let left_pad = halo.saturating_sub(x); let top_pad = halo.saturating_sub(y);
let src_right = (x + w + halo).min(self.raster.total_width);
let src_bottom = (y + h + halo).min(self.raster.total_height);
let src_w = src_right.saturating_sub(src_left);
let src_h = src_bottom.saturating_sub(src_top);
if src_w > 0 && src_h > 0 {
let src_data = match self
.raster
.source
.read_window(src_left, src_top, src_w, src_h)
{
Ok(d) => d,
Err(e) => return Some(Err(e)),
};
for row in 0..src_h {
let dst_row = row + top_pad;
for col in 0..src_w {
let dst_col = col + left_pad;
data[dst_row * full_w + dst_col] = src_data[row * src_w + col];
}
}
}
self.current_x += w;
if self.current_x >= self.raster.total_width {
self.current_x = 0;
self.current_y += h;
}
Some(Ok(Chunk {
x,
y,
width: w,
height: h,
halo,
data,
}))
}
}