palettes
This commit is contained in:
parent
187cd9dc39
commit
d292ae0193
|
@ -1,19 +1,7 @@
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
#[macro_export]
|
#[derive(Copy, Clone)]
|
||||||
macro_rules! color {
|
|
||||||
($v:expr,$r:expr,$g:expr,$b:expr) => { (OrderedFloat(f64::from($v)), Color { red: $r, green: $g, blue: $b, alpha: 255 }) };
|
|
||||||
($v:expr,$r:expr,$g:expr,$b:expr,$a:expr) => { (OrderedFloat(f64::from($v)), Color { red: $r, green: $g, blue: $b, alpha: $a }) };
|
|
||||||
(rgb: $r:expr,$g:expr,$b:expr) => { Color { red: $r, green: $g, blue: $b, alpha: 255 }};
|
|
||||||
(rgba: $r:expr,$g:expr,$b:expr,$a:expr) => { Color { red: $r, green: $g, blue: $b, alpha: $a }};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Palette {
|
|
||||||
pub colors: BTreeMap<OrderedFloat<f64>, Color>,
|
|
||||||
pub clear_value: f64
|
|
||||||
}
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
pub red: u8,
|
pub red: u8,
|
||||||
pub green: u8,
|
pub green: u8,
|
||||||
|
@ -21,70 +9,74 @@ pub struct Color {
|
||||||
pub alpha: u8
|
pub alpha: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
pub type Palette = Vec<((OrderedFloat<f64>, OrderedFloat<f64>), (Color, Color))>;
|
||||||
pub fn average(self, other: Color) -> Color {
|
|
||||||
Color {
|
macro_rules! c {
|
||||||
red: (self.red + other.red) / 2,
|
($r:expr,$g:expr,$b:expr) => {
|
||||||
green: (self.green + other.green) / 2,
|
Color { red: $r, green: $g, blue: $b, alpha: 255 }
|
||||||
blue: (self.blue + other.blue) / 2,
|
};
|
||||||
alpha: (self.alpha + other.alpha) / 2
|
($r:expr,$g:expr,$b:expr,$a:expr) => {
|
||||||
}
|
Color { red: $r, green: $g, blue: $b, alpha: $a }
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
macro_rules! r {
|
||||||
|
($f:expr,$t:expr) => {
|
||||||
|
(OrderedFloat($f), OrderedFloat($t))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Palette {
|
pub fn create_test_palette() -> Palette {
|
||||||
pub fn color_for(&self, val: f64) -> Color {
|
let mut out = vec![];
|
||||||
if val <= self.clear_value {
|
|
||||||
Color { red: 0, green: 0, blue: 0, alpha: 0 }
|
out.push((r!(f64::NEG_INFINITY, 10.0), (c!(164, 164, 255), c!(164, 164, 255))));
|
||||||
} else if self.colors.is_empty() {
|
out.push((r!(10.0, 20.0), (c!(64, 128, 255), c!(32, 64, 128))));
|
||||||
panic!("color_for() on empty palette");
|
out.push((r!(20.0, 30.0), (c!(0, 255, 0), c!(0, 128, 0))));
|
||||||
} else {
|
out.push((r!(30.0, 40.0), (c!(255, 255, 0), c!(255, 128, 0))));
|
||||||
let mut best_v: Option<Color> = None;
|
out.push((r!(40.0, 50.0), (c!(255, 255, 0), c!(255, 128, 0))));
|
||||||
for (k, v) in &self.colors {
|
out.push((r!(50.0, 60.0), (c!(255, 0, 0), c!(160, 0, 0))));
|
||||||
if val < **k {
|
out.push((r!(60.0, 70.0), (c!(255, 0, 255), c!(128, 0, 128))));
|
||||||
best_v = Some(*v);
|
out.push((r!(70.0, 80.0), (c!(255, 255, 255), c!(128, 128, 128))));
|
||||||
}
|
out.push((r!(80.0, f64::INFINITY), (c!(128, 128, 128), c!(128, 128, 128))));
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ColorPalette {
|
||||||
|
fn colorize(&self, at: f64) -> Color;
|
||||||
|
}
|
||||||
|
impl ColorPalette for Palette {
|
||||||
|
fn colorize(&self, at: f64) -> Color {
|
||||||
|
for (raw_range, color_range) in self {
|
||||||
|
let range = *raw_range.0 .. *raw_range.1;
|
||||||
|
if range.contains(&at) {
|
||||||
|
|
||||||
|
let mapped_end = *raw_range.1 - *raw_range.0;
|
||||||
|
let mapped_point = at - *raw_range.0;
|
||||||
|
let t = mapped_point / mapped_end;
|
||||||
|
|
||||||
|
let color_start = color_range.0;
|
||||||
|
let color_end = color_range.1;
|
||||||
|
|
||||||
|
return lerp_color(color_start, color_end, t);
|
||||||
}
|
}
|
||||||
best_v.expect("color_for() on empty palette?")
|
}
|
||||||
|
Color {
|
||||||
|
red: 0,
|
||||||
|
green: 0,
|
||||||
|
blue: 0,
|
||||||
|
alpha: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use crate::Palette;
|
|
||||||
use crate::Color;
|
|
||||||
use ordered_float::OrderedFloat;
|
|
||||||
|
|
||||||
#[test]
|
fn lerp(p0: f64, p1: f64, t: f64) -> f64 {
|
||||||
fn basic_palette_test() {
|
p0 + t * (p1 - p0)
|
||||||
let pal = Palette {
|
|
||||||
colors: BTreeMap::from([
|
|
||||||
color!(-30, 165, 165, 165),
|
|
||||||
color!(10, 0, 165, 255),
|
|
||||||
color!(20, 16, 255, 8),
|
|
||||||
color!(35, 251, 238, 0),
|
|
||||||
color!(50, 255, 0, 0),
|
|
||||||
color!(65, 247, 1, 249),
|
|
||||||
color!(75, 255, 255, 255),
|
|
||||||
color!(85, 184, 184, 184),
|
|
||||||
color!(95, 184, 184, 184)
|
|
||||||
]),
|
|
||||||
clear_value: -99.0
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
assert_eq!(pal.color_for(-999.0), color!(rgba: 0, 0, 0, 0));
|
|
||||||
assert_eq!(pal.color_for(-99.0), color!(rgba: 0, 0, 0, 0));
|
|
||||||
|
|
||||||
assert_eq!(pal.color_for(-30.0), color!(rgb: 165, 165, 165));
|
|
||||||
assert_eq!(pal.color_for(-25.0), color!(rgb: 165, 165, 165));
|
|
||||||
|
|
||||||
assert_eq!(pal.color_for(10.0), color!(rgb: 0, 165, 255));
|
|
||||||
assert_eq!(pal.color_for(15.0), color!(rgb: 0, 165, 255));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fn lerp_color(c0: Color, c1: Color, t: f64) -> Color {
|
||||||
*/
|
Color {
|
||||||
|
red: lerp(c0.red as f64, c1.red as f64, t) as u8,
|
||||||
|
green: lerp(c0.green as f64, c1.green as f64, t) as u8,
|
||||||
|
blue: lerp(c0.blue as f64, c1.blue as f64, t) as u8,
|
||||||
|
alpha: lerp(c0.alpha as f64, c1.alpha as f64, t) as u8
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,11 +10,10 @@ use flate2::read::GzDecoder;
|
||||||
use ndarray::{Zip};
|
use ndarray::{Zip};
|
||||||
use ordered_float::{FloatCore, OrderedFloat};
|
use ordered_float::{FloatCore, OrderedFloat};
|
||||||
use png::{BitDepth, ColorType, Encoder};
|
use png::{BitDepth, ColorType, Encoder};
|
||||||
use wxbox_pal::{Color, Palette};
|
use wxbox_pal::{Color, ColorPalette, create_test_palette, Palette};
|
||||||
use crate::{AppState, LutKey};
|
use crate::{AppState, LutKey};
|
||||||
use crate::grib2::{closest_key, LookupTable2D};
|
use crate::grib2::{closest_key, LookupTable2D};
|
||||||
use crate::pixmap::Pixmap;
|
use crate::pixmap::Pixmap;
|
||||||
use wxbox_pal::color;
|
|
||||||
use crate::tile::xyz_to_bbox;
|
use crate::tile::xyz_to_bbox;
|
||||||
|
|
||||||
#[get("/mrms_cref/{z}/{x}/{y}.png")]
|
#[get("/mrms_cref/{z}/{x}/{y}.png")]
|
||||||
|
@ -90,7 +89,7 @@ async fn mrms_cref(path: web::Path<(u8, u32, u32)>, data: Data<AppState>) -> Htt
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(map) = data.lut_cache.read().await.get(&LutKey::NoaaMrmsCref) {
|
if let Some(map) = data.lut_cache.read().await.get(&LutKey::NoaaMrmsCref) {
|
||||||
|
/*
|
||||||
let pal = Palette {
|
let pal = Palette {
|
||||||
colors: BTreeMap::from([
|
colors: BTreeMap::from([
|
||||||
color!(-30, 165, 165, 165, 0),
|
color!(-30, 165, 165, 165, 0),
|
||||||
|
@ -106,6 +105,8 @@ async fn mrms_cref(path: web::Path<(u8, u32, u32)>, data: Data<AppState>) -> Htt
|
||||||
clear_value: -99.0
|
clear_value: -99.0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
let mut image: Pixmap = Pixmap::new();
|
let mut image: Pixmap = Pixmap::new();
|
||||||
|
|
||||||
let degrees_lat_per_px = (max_lat - min_lat) / 256.0;
|
let degrees_lat_per_px = (max_lat - min_lat) / 256.0;
|
||||||
|
@ -145,10 +146,14 @@ async fn mrms_cref(path: web::Path<(u8, u32, u32)>, data: Data<AppState>) -> Htt
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pal = create_test_palette();
|
||||||
|
|
||||||
let color = match value {
|
let color = match value {
|
||||||
-999.0 => Color { red: 0, green: 0, blue: 0, alpha: 30 },
|
-999.0 => Color { red: 0, green: 0, blue: 0, alpha: 30 },
|
||||||
-99.0 => Color { red: 0, green: 0, blue: 0, alpha: 0 },
|
-99.0 => Color { red: 0, green: 0, blue: 0, alpha: 0 },
|
||||||
value_at_pos => {
|
value_at_pos => {
|
||||||
|
pal.colorize(*value_at_pos)
|
||||||
|
/*
|
||||||
match *value_at_pos {
|
match *value_at_pos {
|
||||||
..=-30.0 => color!(rgb: 165, 165, 165),
|
..=-30.0 => color!(rgb: 165, 165, 165),
|
||||||
-30.0..=10.0 => color!(rgb: 0, 165, 255),
|
-30.0..=10.0 => color!(rgb: 0, 165, 255),
|
||||||
|
@ -160,6 +165,8 @@ async fn mrms_cref(path: web::Path<(u8, u32, u32)>, data: Data<AppState>) -> Htt
|
||||||
75.0.. => color!(rgb: 184, 184, 184),
|
75.0.. => color!(rgb: 184, 184, 184),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
image.set(y, x, color);
|
image.set(y, x, color);
|
||||||
|
|
Loading…
Reference in New Issue