use crate::data::{AnyDataArray, DataArray, ImageData};
pub fn image_quantize(input: &ImageData, scalars: &str, n_levels: usize) -> ImageData {
let arr=match input.point_data().get_array(scalars){Some(a)=>a,None=>return input.clone()};
let n=arr.num_tuples(); let nl=n_levels.max(2);
let mut buf=[0.0f64];
let mut min_v=f64::MAX;let mut max_v=f64::MIN;
for i in 0..n{arr.tuple_as_f64(i,&mut buf);min_v=min_v.min(buf[0]);max_v=max_v.max(buf[0]);}
let range=(max_v-min_v).max(1e-15);
let values: Vec<f64>=(0..n).map(|i|{
arr.tuple_as_f64(i,&mut buf);
let t=(buf[0]-min_v)/range;
let level=(t*(nl-1) as f64).round() as usize;
min_v+level.min(nl-1) as f64*range/(nl-1) as f64
}).collect();
let mut img=input.clone();
let mut attrs=crate::data::DataSetAttributes::new();
for i in 0..input.point_data().num_arrays(){
let a=input.point_data().get_array_by_index(i).unwrap();
if a.name()==scalars{attrs.add_array(AnyDataArray::F64(DataArray::from_vec(scalars,values.clone(),1)));}
else{attrs.add_array(a.clone());}
}
*img.point_data_mut()=attrs;
img
}
pub fn image_posterize(input: &ImageData, scalars: &str, n_levels: usize) -> ImageData {
image_quantize(input, scalars, n_levels)
}
pub fn image_dither_quantize(input: &ImageData, scalars: &str, n_levels: usize, seed: u64) -> ImageData {
let arr=match input.point_data().get_array(scalars){Some(a)=>a,None=>return input.clone()};
let n=arr.num_tuples(); let nl=n_levels.max(2);
let mut buf=[0.0f64];
let mut min_v=f64::MAX;let mut max_v=f64::MIN;
for i in 0..n{arr.tuple_as_f64(i,&mut buf);min_v=min_v.min(buf[0]);max_v=max_v.max(buf[0]);}
let range=(max_v-min_v).max(1e-15);
let step=range/(nl-1) as f64;
let mut rng=seed;
let values: Vec<f64>=(0..n).map(|i|{
arr.tuple_as_f64(i,&mut buf);
rng=rng.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
let noise=((rng>>33) as f64/(1u64<<31) as f64-0.5)*step;
let v=buf[0]+noise;
let t=(v-min_v)/range;
let level=(t*(nl-1) as f64).round() as usize;
min_v+level.min(nl-1) as f64*step
}).collect();
let mut img=input.clone();
let mut attrs=crate::data::DataSetAttributes::new();
for i in 0..input.point_data().num_arrays(){
let a=input.point_data().get_array_by_index(i).unwrap();
if a.name()==scalars{attrs.add_array(AnyDataArray::F64(DataArray::from_vec(scalars,values.clone(),1)));}
else{attrs.add_array(a.clone());}
}
*img.point_data_mut()=attrs;
img
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn quantize_to_2_levels() {
let mut img=ImageData::with_dimensions(5,1,1);
img.point_data_mut().add_array(AnyDataArray::F64(DataArray::from_vec("v",vec![0.0,0.3,0.5,0.7,1.0],1)));
let result=image_quantize(&img,"v",2);
let arr=result.point_data().get_array("v").unwrap();
let mut buf=[0.0f64];
for i in 0..5{arr.tuple_as_f64(i,&mut buf);assert!(buf[0]==0.0||buf[0]==1.0);}
}
#[test]
fn quantize_preserves_range() {
let mut img=ImageData::with_dimensions(3,1,1);
img.point_data_mut().add_array(AnyDataArray::F64(DataArray::from_vec("v",vec![10.0,50.0,90.0],1)));
let result=image_quantize(&img,"v",3);
let arr=result.point_data().get_array("v").unwrap();
let mut buf=[0.0f64];
arr.tuple_as_f64(0,&mut buf); assert_eq!(buf[0],10.0);
arr.tuple_as_f64(2,&mut buf); assert_eq!(buf[0],90.0);
}
#[test]
fn dither_quantize() {
let mut img=ImageData::with_dimensions(10,1,1);
let vals: Vec<f64>=(0..10).map(|i|i as f64).collect();
img.point_data_mut().add_array(AnyDataArray::F64(DataArray::from_vec("v",vals,1)));
let result=image_dither_quantize(&img,"v",3,42);
assert!(result.point_data().get_array("v").is_some());
}
#[test]
fn missing_array() {
let img=ImageData::with_dimensions(3,1,1);
let r=image_quantize(&img,"nope",5);
assert_eq!(r.dimensions(),[3,1,1]);
}
}