use std::path::Path;
use ndarray::Array2;
use crate::error::Result;
use crate::io::strip_reader::StripReader;
use crate::io::strip_writer::{StripWriterConfig, write_geotiff_streaming};
pub trait WindowAlgorithm: Send + Sync {
fn kernel_radius(&self) -> usize;
fn process_chunk(
&self,
input: &Array2<f64>,
output: &mut Array2<f64>,
nodata: Option<f64>,
cell_size_x: f64,
cell_size_y: f64,
);
}
pub struct StripProcessor {
pub chunk_rows: usize,
}
impl StripProcessor {
pub fn new(chunk_rows: usize) -> Self {
Self { chunk_rows }
}
pub fn process<A: WindowAlgorithm>(
&self,
input_path: &Path,
output_path: &Path,
algorithm: &A,
compress: bool,
) -> Result<(usize, usize)> {
let reader = StripReader::open(input_path)?;
let rows = reader.rows();
let cols = reader.cols();
let radius = algorithm.kernel_radius();
let nodata = reader.nodata();
let config = StripWriterConfig {
rows,
cols,
transform: reader.transform().clone(),
crs: reader.crs().cloned(),
nodata: nodata.or(Some(f64::NAN)),
compress,
rows_per_strip: self.chunk_rows as u32,
};
let cell_size_x = reader.transform().pixel_width.abs();
let cell_size_y = reader.transform().pixel_height.abs();
let reader_cell = std::cell::RefCell::new(reader);
let mut current_out_row = 0usize;
write_geotiff_streaming(output_path, &config, |_strip_idx, out_strip_rows| {
let mut reader = reader_cell.borrow_mut();
let out_start = current_out_row;
let out_end = (current_out_row + out_strip_rows).min(rows);
let actual_out_rows = out_end - out_start;
let in_start = out_start.saturating_sub(radius);
let in_end = (out_end + radius).min(rows);
let raw_input = reader.read_rows(in_start, in_end - in_start)?;
let padded_rows = actual_out_rows + 2 * radius;
let mut input = Array2::<f64>::from_elem((padded_rows, cols), f64::NAN);
let top_pad = radius.saturating_sub(out_start);
let copy_rows = raw_input.nrows().min(padded_rows - top_pad);
input
.slice_mut(ndarray::s![top_pad..top_pad + copy_rows, ..])
.assign(&raw_input.slice(ndarray::s![..copy_rows, ..]));
let mut output = Array2::<f64>::from_elem((actual_out_rows, cols), f64::NAN);
algorithm.process_chunk(&input, &mut output, nodata, cell_size_x, cell_size_y);
current_out_row = out_end;
Ok(output)
})?;
Ok((rows, cols))
}
}