use std::cell::RefCell;
use ndarray::Array2;
#[derive(Debug)]
pub struct HeatMapAnnotator {
pub radius: u32,
pub intensity: f32,
pub opacity: f32,
pub(crate) buffer: RefCell<Option<Array2<f32>>>,
}
impl HeatMapAnnotator {
pub fn new(radius: u32, intensity: f32, opacity: f32) -> Self {
Self {
radius,
intensity,
opacity,
buffer: RefCell::new(None),
}
}
pub fn clear(&self) {
*self.buffer.borrow_mut() = None;
}
}
impl Default for HeatMapAnnotator {
fn default() -> Self {
Self::new(20, 0.15, 0.6)
}
}
#[allow(dead_code)]
pub(crate) fn heat_color(t: f32) -> (u8, u8, u8) {
let t = t.clamp(0.0, 1.0);
let stops: [(f32, (u8, u8, u8)); 4] = [
(0.0, (0, 0, 255)),
(0.33, (0, 255, 0)),
(0.66, (255, 255, 0)),
(1.0, (255, 0, 0)),
];
for pair in stops.windows(2) {
let (t0, c0) = pair[0];
let (t1, c1) = pair[1];
if t <= t1 {
let f = if t1 > t0 { (t - t0) / (t1 - t0) } else { 0.0 };
let lerp = |a: u8, b: u8| (a as f32 + (b as f32 - a as f32) * f).round() as u8;
return (lerp(c0.0, c1.0), lerp(c0.1, c1.1), lerp(c0.2, c1.2));
}
}
stops[3].1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn heat_color_endpoints_are_blue_and_red() {
assert_eq!(heat_color(0.0), (0, 0, 255));
assert_eq!(heat_color(1.0), (255, 0, 0));
}
#[test]
fn heat_color_clamps_out_of_range_input() {
assert_eq!(heat_color(-1.0), heat_color(0.0));
assert_eq!(heat_color(2.0), heat_color(1.0));
}
}