use crate::{
geo::raster::RasterInfo,
prelude::{RasterDtype, RasterizeContext},
rasterization::pixel_functions::PixelFn,
};
use ndarray::Array3;
use num_traits::Num;
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
pub struct DenseArray<N> {
raster: Array3<N>,
band_names: Vec<String>,
raster_info: RasterInfo,
}
impl<N: Num> DenseArray<N> {
pub(crate) fn new(raster: Array3<N>, band_names: Vec<String>, raster_info: RasterInfo) -> Self {
Self {
raster,
band_names,
raster_info,
}
}
pub fn into_parts(self) -> (Array3<N>, Vec<String>, RasterInfo) {
(self.raster, self.band_names, self.raster_info)
}
pub fn band_names(&self) -> &[String] {
&self.band_names
}
pub fn raster_info(&self) -> &RasterInfo {
&self.raster_info
}
}
struct Triplets<N> {
rows: Vec<u64>,
cols: Vec<u64>,
data: Vec<N>,
}
impl<N: Num> Triplets<N> {
fn new(rows: Vec<u64>, cols: Vec<u64>, data: Vec<N>) -> Self {
Self { rows, cols, data }
}
}
pub struct SparseArray<N> {
band_names: Vec<String>,
triplets: Triplets<N>,
lengths: Vec<usize>,
raster_info: RasterInfo,
pxfn: PixelFn<N>,
background: N,
}
impl<N> SparseArray<N>
where
N: RasterDtype,
{
pub(crate) fn new(
band_names: Vec<String>,
rows: Vec<u64>,
cols: Vec<u64>,
data: Vec<N>,
lengths: Vec<usize>,
ctx: RasterizeContext<N>,
) -> Self {
let pxfn = ctx.pixel_fn();
let background = ctx.background;
Self {
band_names,
triplets: Triplets::new(rows, cols, data),
lengths,
raster_info: ctx.raster_info,
pxfn,
background,
}
}
pub fn band_names(&self) -> &[String] {
&self.band_names
}
pub fn build_array(&self) -> Array3<N> {
let mut raster = self.raster_info.build_raster(self.band_names.len(), self.background);
let rows = self.triplets.rows.as_slice();
let cols = self.triplets.cols.as_slice();
let data = self.triplets.data.as_slice();
let offsets = self
.lengths
.iter()
.scan(0, |state, &n| {
let start = *state;
*state += n;
Some(start)
})
.collect::<Vec<usize>>();
raster
.outer_iter_mut()
.into_par_iter()
.zip(self.lengths.par_iter())
.zip(offsets.par_iter())
.for_each(|((mut band, n), &off)| {
let end = off + *n;
let band_rows = &rows[off..end];
let band_cols = &cols[off..end];
let band_data = &data[off..end];
for ((band_row, band_col), band_value) in band_rows.iter().zip(band_cols).zip(band_data) {
(self.pxfn)(
&mut band,
*band_row as usize,
*band_col as usize,
*band_value,
self.background,
);
}
});
raster
}
pub fn extent(&self) -> (f64, f64, f64, f64) {
(
self.raster_info.xmin,
self.raster_info.ymin,
self.raster_info.xmax,
self.raster_info.ymax,
)
}
pub fn shape(&self) -> (usize, usize) {
(self.raster_info.nrows, self.raster_info.ncols)
}
pub fn resolution(&self) -> (f64, f64) {
(self.raster_info.xres, self.raster_info.yres)
}
pub fn raster_info(&self) -> &RasterInfo {
&self.raster_info
}
pub fn epsg(&self) -> Option<u16> {
self.raster_info.epsg
}
}
#[cfg(feature = "polars")]
mod feature_gated {
use super::SparseArray;
use crate::prelude::PolarsHandler;
use num_traits::Num;
use polars::prelude::*;
impl<N> SparseArray<N>
where
N: Num + Copy + PolarsHandler,
{
pub fn to_frame(&self) -> DataFrame {
let mut columns: Vec<Column> = Vec::new();
if self.lengths.len() > 1 {
let bands = self
.lengths
.iter()
.enumerate()
.flat_map(|(i, v)| std::iter::repeat_n(i + 1, *v))
.map(|b| b as u64)
.collect::<Vec<u64>>();
let bands_column = Column::new("band".into(), bands);
columns.push(bands_column);
}
columns.push(Column::new("row".into(), self.triplets.rows.as_slice()));
columns.push(Column::new("col".into(), self.triplets.cols.as_slice()));
let height = self.triplets.data.len();
columns.push(N::from_named_vec("values", &self.triplets.data));
DataFrame::new(height, columns).unwrap()
}
}
}