equidistributed_colors/
lib.rs

1use hsl::HSL;
2pub use rgb::RGB8;
3
4use oklab::*;
5
6const PHI: f64 = 0.618033988749895;
7
8#[derive(Copy, Clone)]
9/// Iterator over colors which are distributed evenly according to the equidistribution theorem.
10/// Attempts to make the next color look as different as possible from all of the previously generated colors. 
11/// 
12/// Call [`EquiColor::next()`] to produce the next color. 
13pub struct EquiColor {
14    state: f64,
15    s: f32,
16    l: f32,
17}
18
19impl EquiColor {
20    /// Create a color generator with the provided saturation and lightness (in range `[0.0, 1.0)`)
21    pub fn new(s: f32, l: f32) -> Self {
22        EquiColor {
23            state: 0.0,
24            s, l,
25        }
26    }
27}
28
29impl Default for EquiColor {
30    fn default() -> Self {
31        Self::new(1.0, 0.6)
32    }
33}
34
35impl Iterator for EquiColor {
36    type Item = RGB8;
37
38    fn next(&mut self) -> Option<Self::Item> {
39        let (r, g, b) = HSL {
40            h: 360.0*self.state,
41            s: self.s as f64,
42            l: self.l as f64,
43        }.to_rgb();
44
45        self.state = (self.state + PHI) % 1.0;
46
47        let mut oklab = srgb_to_oklab(RGB8 { r, g, b});
48        oklab.l = self.l;
49
50        Some(oklab_to_srgb(oklab))
51    }
52}
53
54#[test]
55fn first_three_colors_correct() {
56    let mut equicolor = EquiColor::default();
57    assert_eq!(equicolor.next(), Some(Rgb { r: 237, g: 22, b: 33 }));
58    assert_eq!(equicolor.next(), Some(Rgb { r: 54, g: 115, b: 255 }));
59    assert_eq!(equicolor.next(), Some(Rgb { r: 74, g: 152, b: 0 }));
60}