radar-g/src/predefined/color_mapper.rs
2024-04-15 22:29:35 +08:00

254 lines
6.4 KiB
Rust

use std::fmt::Debug;
use femtovg::Color;
use image::imageops::ColorMap;
use num_traits::{AsPrimitive, FromPrimitive, NumOps};
type BoundaryNormDiscrete<T> = ColorMapper<T, Discrete, BoundaryNorm<T>>;
macro_rules! color_mapper_comb {
($comb: ident, $($key: tt,)+) => {
impl<T: PartialEq + PartialOrd + Debug> $comb<T> {
pub fn color(&self, value: T) -> Option<femtovg::Color> {
match self {
$(
Self::$key(mapper) => mapper.color(value),
)+
}
}
}
};
}
pub enum ColorMapperComb<T: PartialEq + PartialOrd + Debug> {
BoundaryNormDiscrete(BoundaryNormDiscrete<T>),
}
color_mapper_comb!(ColorMapperComb, BoundaryNormDiscrete,);
pub trait VMap {
type Ty;
fn map(&self, v: Self::Ty) -> Option<f32>;
}
pub trait CMap {
fn map(&self, v: f32) -> femtovg::Color;
}
pub struct ColorMapper<T, CMAP, VMAP>
where
CMAP: CMap,
VMAP: VMap<Ty = T>,
{
cmap: CMAP,
vmap: VMAP,
}
impl<T, CMAP, VMAP> ColorMapper<T, CMAP, VMAP>
where
T: PartialEq + PartialOrd,
CMAP: CMap,
VMAP: VMap<Ty = T>,
{
pub fn new(cmap: CMAP, vmap: VMAP) -> Self {
Self { cmap, vmap }
}
pub fn color(&self, value: T) -> Option<femtovg::Color> {
self.vmap.map(value).map(|v| self.cmap.map(v))
}
}
#[derive(Debug)]
pub struct BoundaryNorm<T: PartialOrd + PartialEq> {
boundaries: Vec<T>,
extrand: bool,
invalid_value: Option<T>,
}
impl<T: PartialEq + PartialOrd> BoundaryNorm<T> {
pub fn new(boundaries: Vec<T>, extrand: bool, invalid_value: Option<T>) -> Self {
Self {
boundaries,
extrand,
invalid_value,
}
}
}
impl<T> VMap for BoundaryNorm<T>
where
T: PartialOrd + PartialEq + Debug,
{
type Ty = T;
fn map(&self, v: Self::Ty) -> Option<f32> {
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<femtovg::Color>,
}
impl Discrete {
pub fn new(colors: Vec<femtovg::Color>) -> 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<T: NumOps + PartialOrd> {
// boundaries: Vec<T>,
// extrand: bool,
// colors: Vec<femtovg::Color>,
// invalid_value: T,
// }
//
// impl Default for BoundaryNorm<i8> {
// 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<T: NumOps + PartialOrd> BoundaryNorm<T> {
// pub fn new(
// boundaries: Vec<T>,
// colors: Vec<femtovg::Color>,
// 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<femtovg::Color> {
// 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<T> ColorMapper for BoundaryNorm<T>
// where
// T: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
// {
//
// type Ty<V> = T;
// fn map_value_to_color<T>(&self, value: Self::Ty<T>, invalid_value: Self::Ty<T>) -> Option<femtovg::Color> {
// 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<femtovg::Color> {
// 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> = T;
// fn map_value_to_color<T>(&self, value: Self::Ty<T>, invalid: T) -> Option<femtovg::Color> {
// 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<femtovg::Color> {
// vec![]
// }
//
// fn min_max(&self) -> (f64, f64) {
// (0.0, 0.0)
// }
//
// fn invalid(&self) -> f64 {
// 0.0
// }
// }