diff --git a/src/lib.rs b/src/lib.rs index 7d12d9a..daacf7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,2 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +pub mod mipmap; +pub use mipmap::MipMap1D; diff --git a/src/mipmap.rs b/src/mipmap.rs new file mode 100644 index 0000000..966036d --- /dev/null +++ b/src/mipmap.rs @@ -0,0 +1,86 @@ +use num_traits::{FromPrimitive, Num, ToPrimitive}; + +pub struct MipMap1D { + data: Vec>, +} + +impl MipMap1D { + pub fn build(source: Vec) -> Self { + let mut data = vec![source.clone()]; + let mut current = source; + + while current.len() > 1 { + let mipmap = Self::downsample(¤t); + current.clone_from(&mipmap); + data.push(mipmap); + } + + Self { data } + } + + pub fn num_levels(&self) -> usize { + self.data.len() + } + + pub fn get_level(&self, level: usize) -> Option<&Vec> { + if level > self.num_levels() { + return None; + } + + Some(&self.data[level]) + } + + /// Downsamples a vector to ceil(len / 2) elements. + /// Currently, downsampling is done by averaging the pair of elements + fn downsample(source: &[T]) -> Vec { + source + .chunks(2) + .map(|pair| match pair.len() { + 1 => pair[0], + 2 => T::from_f64((pair[0] + pair[1]).to_f64().unwrap() / 2.0).unwrap(), + _ => panic!("Unsound condition"), + }) + .collect() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_correct_downsample_ints() { + let data = vec![2, 4, 6, 8]; + assert_eq!(MipMap1D::downsample(&data), vec![3, 7]); + } + + #[test] + fn test_uneven_downsample() { + let data = vec![2, 4, 6, 8, 9]; + assert_eq!(MipMap1D::downsample(&data), vec![3, 7, 9]); + } + + #[test] + fn test_uneven_mipmap() { + let data = vec![2, 4, 6, 8, 9]; + let target = vec![vec![2, 4, 6, 8, 9], vec![3, 7, 9], vec![5, 9], vec![7]]; + let mipmap = MipMap1D::build(data); + assert_eq!(mipmap.data, target); + } + + #[test] + fn test_mipmap_levels() { + let data = vec![2, 4, 6, 8, 9]; + let target = [vec![2, 4, 6, 8, 9], vec![3, 7, 9], vec![5, 9], vec![7]]; + let mipmap = MipMap1D::build(data); + + assert_eq!(mipmap.num_levels(), target.len()); + for (level, target_item) in target.iter().enumerate() { + let res = mipmap.get_level(level); + assert!(res.is_some()); + let res = res.unwrap(); + + assert_eq!(*res, *target_item) + } + } +}