|
14 | 14 | }
|
15 | 15 |
|
16 | 16 |
|
| 17 | +/// This struct is used to dynamically construct colormaps by giving it a slice of colors. |
| 18 | +/// It can then be used when being intantiated, but not with associated functions. |
| 19 | +/// ``` |
| 20 | +/// use plotters::prelude::{BLACK,BLUE,WHITE,DerivedColorMap,ColorMap}; |
| 21 | +/// |
| 22 | +/// let derived_colormap = DerivedColorMap::new( |
| 23 | +/// &[BLACK, |
| 24 | +/// BLUE, |
| 25 | +/// WHITE] |
| 26 | +/// ); |
| 27 | +/// |
| 28 | +/// assert_eq!(derived_colormap.get_color(0.0), BLACK); |
| 29 | +/// assert_eq!(derived_colormap.get_color(0.5), BLUE); |
| 30 | +/// assert_eq!(derived_colormap.get_color(1.0), WHITE); |
| 31 | +/// ``` |
| 32 | +pub struct DerivedColorMap<ColorType> { |
| 33 | + colors: Vec<ColorType>, |
| 34 | +} |
| 35 | + |
| 36 | + |
| 37 | +impl<ColorType: crate::style::Color + Clone> DerivedColorMap<ColorType> { |
| 38 | + pub fn new(colors: &[ColorType]) -> Self { |
| 39 | + DerivedColorMap { colors: colors.iter().map(|color| color.clone()).collect::<Vec<_>>() } |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | + |
| 44 | +macro_rules! calculate_new_color_value( |
| 45 | + ($relative_difference:expr, $colors:expr, $index_upper:expr, $index_lower:expr, RGBColor) => { |
| 46 | + RGBColor( |
| 47 | + // These equations are a very complicated way of writing a simple linear extrapolation with lots of casting between numerical values |
| 48 | + // In principle every cast should be safe which is why we choose to unwrap |
| 49 | + // (1.0 - r) * color_value_1 + r * color_value_2 |
| 50 | + ((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].0).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].0).unwrap()).round().to_u8().unwrap(), |
| 51 | + ((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].1).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].1).unwrap()).round().to_u8().unwrap(), |
| 52 | + ((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].2).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].2).unwrap()).round().to_u8().unwrap() |
| 53 | + ) |
| 54 | + }; |
| 55 | + ($relative_difference:expr, $colors:expr, $index_upper:expr, $index_lower:expr, RGBAColor) => { |
| 56 | + RGBAColor( |
| 57 | + // These equations are a very complicated way of writing a simple linear extrapolation with lots of casting between numerical values |
| 58 | + // In principle every cast should be safe which is why we choose to unwrap |
| 59 | + // (1.0 - r) * color_value_1 + r * color_value_2 |
| 60 | + ((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].0).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].0).unwrap()).round().to_u8().unwrap(), |
| 61 | + ((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].1).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].1).unwrap()).round().to_u8().unwrap(), |
| 62 | + ((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].2).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].2).unwrap()).round().to_u8().unwrap(), |
| 63 | + ((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].3).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].3).unwrap()).to_f64().unwrap() |
| 64 | + ) |
| 65 | + }; |
| 66 | + ($relative_difference:expr, $colors:expr, $index_upper:expr, $index_lower:expr, HSLColor) => { |
| 67 | + HSLColor( |
| 68 | + // These equations are a very complicated way of writing a simple linear extrapolation with lots of casting between numerical values |
| 69 | + // In principle every cast should be safe which is why we choose to unwrap |
| 70 | + // (1.0 - r) * color_value_1 + r * color_value_2 |
| 71 | + ((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].0).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].0).unwrap()).to_f64().unwrap(), |
| 72 | + ((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].1).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].1).unwrap()).to_f64().unwrap(), |
| 73 | + ((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].2).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].2).unwrap()).to_f64().unwrap(), |
| 74 | + ) |
| 75 | + }; |
| 76 | +); |
| 77 | + |
| 78 | + |
| 79 | +macro_rules! implement_color_scale_for_derived_ColorMap{ |
| 80 | + ($($color_type:tt),+) => { |
| 81 | + $( |
| 82 | + impl<FloatType: Float + FromPrimitive + ToPrimitive> ColorMap<$color_type, FloatType> for DerivedColorMap<$color_type> { |
| 83 | + fn get_color_normalized(&self, h: FloatType, min: FloatType, max: FloatType) -> $color_type { |
| 84 | + // Ensure that we do have a value in bounds |
| 85 | + let h = h.max(min).min(max); |
| 86 | + // Make sure that we really have a minimal value which is smaller than the maximal value |
| 87 | + assert_eq!(min<max, true); |
| 88 | + // Next calculate a normalized value between 0.0 and 1.0 |
| 89 | + let t = (h - min)/(max-min); |
| 90 | + let approximate_index = t * (FloatType::from_usize(self.colors.len()).unwrap() - FloatType::one()).max(FloatType::zero()); |
| 91 | + // Calculate which index are the two most nearest of the supplied value |
| 92 | + let index_lower = approximate_index.floor().to_usize().unwrap(); |
| 93 | + let index_upper = approximate_index.ceil().to_usize().unwrap(); |
| 94 | + // Calculate the relative difference, ie. is the actual value more towards the color of index_upper or index_lower? |
| 95 | + let relative_difference = approximate_index.ceil() - approximate_index; |
| 96 | + // Interpolate the final color linearly |
| 97 | + calculate_new_color_value!(relative_difference, self.colors, index_upper, index_lower, $color_type) |
| 98 | + } |
| 99 | + } |
| 100 | + )+ |
| 101 | + } |
| 102 | +} |
| 103 | + |
| 104 | +implement_color_scale_for_derived_ColorMap!{RGBAColor, RGBColor, HSLColor} |
| 105 | + |
| 106 | + |
17 | 107 | macro_rules! count {
|
18 | 108 | () => (0usize);
|
19 | 109 | ($x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
|
|
0 commit comments