use super::{mod_ceil, ChunkConfig};
impl ChunkConfig {
pub fn with_dims(width: usize, height: usize) -> Self {
if width < 1 || height < 1 {
panic!("dimensions must both be at least 1");
}
ChunkConfig {
width,
height,
block_size: 1,
data_height: 1,
padding: 0,
start: 0,
end: height,
}
}
#[cfg(feature = "gdal")]
pub fn for_dataset<I: IntoIterator<Item = isize>>(
ds: &gdal::Dataset,
bands: Option<I>,
) -> crate::Result<Self> {
use anyhow::Context;
let size = ds.raster_size();
let mut cfg = ChunkConfig::with_dims(size.0, size.1);
if let Some(bands) = bands {
for band_idx in bands {
let band = ds
.rasterband(band_idx)
.with_context(|| format!("unable to open rasterband {}", band_idx))?;
cfg = cfg.add_block_size(band.block_size().1);
}
}
Ok(cfg)
}
}
impl ChunkConfig {
pub fn add_block_size(mut self, block_size: usize) -> Self {
if block_size < 1 {
panic!("block_size should be at least 1");
}
self.block_size = lcm(self.block_size, block_size);
self.adjust_block_height();
self
}
pub fn with_min_data_height(mut self, min_data_height: usize) -> Self {
self.data_height = min_data_height.max(1);
self.adjust_block_height();
self
}
pub fn with_min_data_size(self, min_data_size: usize) -> Self {
let min_height = (min_data_size + self.width - 1) / self.width;
self.with_min_data_height(min_height)
}
pub fn with_padding(mut self, padding: usize) -> Self {
self.padding = padding;
self.adjust_start();
self
}
pub fn with_start(mut self, start: usize) -> Self {
self.start = start;
self.adjust_start();
self
}
pub fn with_end(mut self, end: usize) -> Self {
self.end = end.min(self.height);
self
}
#[inline]
fn adjust_block_height(&mut self) {
self.data_height = mod_ceil(self.data_height, self.block_size);
}
#[inline]
fn adjust_start(&mut self) {
self.start = self.start.max(self.padding);
}
}
impl ChunkConfig {
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
pub fn block_size(&self) -> usize {
self.block_size
}
pub fn data_height(&self) -> usize {
self.data_height
}
pub fn padding(&self) -> usize {
self.padding
}
pub fn start(&self) -> usize {
self.start
}
pub fn end(&self) -> usize {
self.end
}
}
#[inline]
fn lcm(a: usize, b: usize) -> usize {
a / gcd(a, b) * b
}
fn gcd(a: usize, b: usize) -> usize {
if b == 0 {
return a;
}
gcd(b, a % b)
}