Skip to main content

polyscope_render/
color_maps.rs

1//! Color map system.
2
3use std::collections::HashMap;
4
5use glam::Vec3;
6
7/// A color map for mapping scalar values to colors.
8#[derive(Debug, Clone)]
9pub struct ColorMap {
10    /// Color map name.
11    pub name: String,
12    /// Color samples (evenly spaced from 0 to 1).
13    pub colors: Vec<Vec3>,
14}
15
16impl ColorMap {
17    /// Creates a new color map.
18    pub fn new(name: impl Into<String>, colors: Vec<Vec3>) -> Self {
19        Self {
20            name: name.into(),
21            colors,
22        }
23    }
24
25    /// Samples the color map at a given value (0 to 1).
26    #[must_use]
27    pub fn sample(&self, t: f32) -> Vec3 {
28        let t = t.clamp(0.0, 1.0);
29
30        if self.colors.is_empty() {
31            return Vec3::ZERO;
32        }
33
34        if self.colors.len() == 1 {
35            return self.colors[0];
36        }
37
38        let n = self.colors.len() - 1;
39        let idx = (t * n as f32).floor() as usize;
40        let idx = idx.min(n - 1);
41        let frac = t * n as f32 - idx as f32;
42
43        self.colors[idx].lerp(self.colors[idx + 1], frac)
44    }
45}
46
47/// Registry for managing color maps.
48#[derive(Default)]
49pub struct ColorMapRegistry {
50    color_maps: HashMap<String, ColorMap>,
51}
52
53impl ColorMapRegistry {
54    /// Creates a new color map registry with default color maps.
55    #[must_use]
56    pub fn new() -> Self {
57        let mut registry = Self::default();
58        registry.register_defaults();
59        registry
60    }
61
62    #[allow(clippy::approx_constant)] // These are color values, not mathematical constants
63    fn register_defaults(&mut self) {
64        // Viridis color map
65        self.register(ColorMap::new(
66            "viridis",
67            vec![
68                Vec3::new(0.267, 0.004, 0.329),
69                Vec3::new(0.282, 0.140, 0.457),
70                Vec3::new(0.253, 0.265, 0.529),
71                Vec3::new(0.206, 0.371, 0.553),
72                Vec3::new(0.163, 0.471, 0.558),
73                Vec3::new(0.127, 0.566, 0.550),
74                Vec3::new(0.134, 0.658, 0.517),
75                Vec3::new(0.266, 0.749, 0.440),
76                Vec3::new(0.477, 0.821, 0.318),
77                Vec3::new(0.741, 0.873, 0.150),
78                Vec3::new(0.993, 0.906, 0.144),
79            ],
80        ));
81
82        // Blues color map
83        self.register(ColorMap::new(
84            "blues",
85            vec![
86                Vec3::new(0.969, 0.984, 1.000),
87                Vec3::new(0.871, 0.922, 0.969),
88                Vec3::new(0.776, 0.859, 0.937),
89                Vec3::new(0.620, 0.792, 0.882),
90                Vec3::new(0.419, 0.682, 0.839),
91                Vec3::new(0.259, 0.573, 0.776),
92                Vec3::new(0.129, 0.443, 0.710),
93                Vec3::new(0.031, 0.318, 0.612),
94                Vec3::new(0.031, 0.188, 0.420),
95            ],
96        ));
97
98        // Reds color map
99        self.register(ColorMap::new(
100            "reds",
101            vec![
102                Vec3::new(1.000, 0.961, 0.941),
103                Vec3::new(0.996, 0.878, 0.824),
104                Vec3::new(0.988, 0.733, 0.631),
105                Vec3::new(0.988, 0.573, 0.447),
106                Vec3::new(0.984, 0.416, 0.290),
107                Vec3::new(0.937, 0.231, 0.173),
108                Vec3::new(0.796, 0.094, 0.114),
109                Vec3::new(0.647, 0.059, 0.082),
110                Vec3::new(0.404, 0.000, 0.051),
111            ],
112        ));
113
114        // Coolwarm color map
115        self.register(ColorMap::new(
116            "coolwarm",
117            vec![
118                Vec3::new(0.230, 0.299, 0.754),
119                Vec3::new(0.552, 0.690, 0.996),
120                Vec3::new(0.866, 0.866, 0.866),
121                Vec3::new(0.956, 0.604, 0.486),
122                Vec3::new(0.706, 0.016, 0.150),
123            ],
124        ));
125
126        // Rainbow color map
127        self.register(ColorMap::new(
128            "rainbow",
129            vec![
130                Vec3::new(0.5, 0.0, 1.0),
131                Vec3::new(0.0, 0.0, 1.0),
132                Vec3::new(0.0, 1.0, 1.0),
133                Vec3::new(0.0, 1.0, 0.0),
134                Vec3::new(1.0, 1.0, 0.0),
135                Vec3::new(1.0, 0.0, 0.0),
136            ],
137        ));
138    }
139
140    /// Registers a color map.
141    pub fn register(&mut self, color_map: ColorMap) {
142        self.color_maps.insert(color_map.name.clone(), color_map);
143    }
144
145    /// Gets a color map by name.
146    #[must_use]
147    pub fn get(&self, name: &str) -> Option<&ColorMap> {
148        self.color_maps.get(name)
149    }
150
151    /// Returns all color map names.
152    pub fn names(&self) -> impl Iterator<Item = &str> {
153        self.color_maps.keys().map(std::string::String::as_str)
154    }
155}