254 lines
6.4 KiB
Rust
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
|
|
// }
|
|
// }
|