use std::fmt::Debug; use femtovg::Color; use image::imageops::ColorMap; use num_traits::{AsPrimitive, FromPrimitive, NumOps}; type BoundaryNormDiscrete = ColorMapper>; macro_rules! color_mapper_comb { ($comb: ident, $($key: tt,)+) => { impl $comb { pub fn color(&self, value: T) -> Option { match self { $( Self::$key(mapper) => mapper.color(value), )+ } } } }; } pub enum ColorMapperComb { BoundaryNormDiscrete(BoundaryNormDiscrete), } color_mapper_comb!(ColorMapperComb, BoundaryNormDiscrete,); pub trait VMap { type Ty; fn map(&self, v: Self::Ty) -> Option; } pub trait CMap { fn map(&self, v: f32) -> femtovg::Color; } pub struct ColorMapper where CMAP: CMap, VMAP: VMap, { cmap: CMAP, vmap: VMAP, } impl ColorMapper where T: PartialEq + PartialOrd, CMAP: CMap, VMAP: VMap, { pub fn new(cmap: CMAP, vmap: VMAP) -> Self { Self { cmap, vmap } } pub fn color(&self, value: T) -> Option { self.vmap.map(value).map(|v| self.cmap.map(v)) } } #[derive(Debug)] pub struct BoundaryNorm { boundaries: Vec, extrand: bool, invalid_value: Option, } impl BoundaryNorm { pub fn new(boundaries: Vec, extrand: bool, invalid_value: Option) -> Self { Self { boundaries, extrand, invalid_value, } } } impl VMap for BoundaryNorm where T: PartialOrd + PartialEq + Debug, { type Ty = T; fn map(&self, v: Self::Ty) -> Option { let mut index = 0; if let Some(invalid_value) = &self.invalid_value { if v == *invalid_value { return None; } } for (i, boundary) in self.boundaries.iter().enumerate() { if v < *boundary { break; } index = i; } Some(index as f32 / self.boundaries.len() as f32) } } #[derive(Debug)] pub struct Gradient {} #[derive(Debug)] pub struct Discrete { colors: Vec, } impl Discrete { pub fn new(colors: Vec) -> Self { Self { colors } } } impl CMap for Discrete { fn map(&self, v: f32) -> Color { let size = (self.colors.len() as f32 * v) as usize; self.colors.get(size).unwrap().clone() } } // #[derive(Debug, Clone)] // pub struct BoundaryNorm { // boundaries: Vec, // extrand: bool, // colors: Vec, // invalid_value: T, // } // // impl Default for BoundaryNorm { // fn default() -> Self { // Self { // boundaries: vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65], // extrand: true, // colors: vec![ // Color::rgb(0, 172, 164), // Color::rgb(192, 192, 254), // Color::rgb(122, 114, 238), // Color::rgb(30, 38, 208), // Color::rgb(166, 252, 168), // Color::rgb(0, 234, 0), // Color::rgb(16, 146, 26), // Color::rgb(252, 244, 100), // Color::rgb(200, 200, 2), // Color::rgb(140, 140, 0), // Color::rgb(254, 172, 172), // Color::rgb(254, 100, 92), // Color::rgb(238, 2, 48), // Color::rgb(212, 142, 254), // Color::rgb(170, 36, 250), // ], // invalid_value: -125, // } // } // } // // impl BoundaryNorm { // pub fn new( // boundaries: Vec, // colors: Vec, // extrand: bool, // invalid_value: T, // ) -> Self { // // assert_eq!(boundaries.len(), colors.len() + 1); // BoundaryNorm { // boundaries, // extrand, // colors, // invalid_value, // } // } // // pub fn map_value_to_color(&self, value: f64, invalid_value: f64) -> Option { // let mut index = 0; // if value == invalid_value { // return None; // } // for (i, boundary) in self.boundaries.iter().enumerate() { // if value < *boundary { // break; // } // index = i; // } // index = index.saturating_sub(1).min(self.colors.len() - 1); // Some(self.colors[index]) // } // } // // impl ColorMapper for BoundaryNorm // where // T: NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, // { // // type Ty = T; // fn map_value_to_color(&self, value: Self::Ty, invalid_value: Self::Ty) -> Option { // self.map_value_to_color(value, invalid_value) // } // // fn min_max(&self) -> (f64, f64) { // ( // self.boundaries.first().unwrap().clone().as_(), // self.boundaries.last().unwrap().clone().as_(), // ) // } // // fn invalid(&self) -> f64 { // self.invalid_value.clone().as_() // } // // fn map_min_to_max(&self) -> Vec { // self.boundaries // .iter() // .map(|x| self.map_value_to_color(*x, self.invalid_value).unwrap()) // .collect() // } // } // pub struct BoundaryNorm(); // // impl ColorMapper for BoundaryNorm { // type Ty = T; // fn map_value_to_color(&self, value: Self::Ty, invalid: T) -> Option { // let mut index = 0; // if value == invalid_value { // return None; // } // for (i, boundary) in self.boundaries.iter().enumerate() { // if value < *boundary { // break; // } // index = i; // } // index = index.saturating_sub(1).min(self.colors.len() - 1); // Some(self.colors[index]) // } // // fn map_min_to_max(&self) -> Vec { // vec![] // } // // fn min_max(&self) -> (f64, f64) { // (0.0, 0.0) // } // // fn invalid(&self) -> f64 { // 0.0 // } // }