1use rand::Rng;
36
37mod color;
38pub use color::Color;
39
40pub struct HsvPalette {
43 iteration: usize,
44 base_divergence: f32,
45 palette_type: PaletteType,
46 hue: Hue,
47}
48
49pub struct ColorPalette(HsvPalette);
50
51pub enum PaletteType {
52 Random,
53 Pastel,
54 Dark,
55}
56
57pub(crate) type Hue = f32;
58pub(crate) type Saturation = f32;
59pub(crate) type Value = f32;
60pub type Hsv = (Hue, Saturation, Value);
61
62impl ColorPalette {
63 pub fn new<T: Rng>(palette_type: PaletteType, adjacent_colors: bool, rng: &mut T) -> Self {
64 ColorPalette(HsvPalette::new(
65 palette_type,
66 adjacent_colors,
67 rng
68 ))
69 }
70
71 pub fn get_inner(&self) -> &HsvPalette {
72 &self.0
73 }
74
75 pub fn get_inner_mut(&mut self) -> &mut HsvPalette {
76 &mut self.0
77 }
78
79 pub fn into_inner(self) -> HsvPalette {
80 self.0
81 }
82}
83
84impl HsvPalette {
85 pub fn new<T: Rng>(palette_type: PaletteType, adjacent_colors: bool, rng: &mut T) -> Self {
86
87 let hue = rng.gen_range(0.0..360.0);
88
89 let mut base_divergence = 80.0;
90
91 if adjacent_colors {
92 base_divergence = 25.0;
93 }
94
95 Self {
96 base_divergence,
97 palette_type,
98 hue,
99 iteration: 0
100 }
101 }
102
103
104 fn palette_dark(&self) -> Hsv {
105 let iteration = self.iteration as f32;
106 let f = (iteration * 43.0).cos().abs();
107 let mut div = self.base_divergence;
108
109 if div < 15.0 {
110 div = 15.0;
111 }
112
113 let hue = (self.hue + div + f).abs() % 360.0;
114 let saturation = 0.32 + ((iteration * 0.75).sin() / 2.0).abs();
115 let value = 0.1 + (iteration.cos() / 6.0).abs();
116 (hue, saturation, value)
117 }
118
119 fn palette_pastel(&self) -> Hsv {
120 let iteration = self.iteration as f32;
121 let f = (iteration * 25.0).cos().abs();
122 let mut div = self.base_divergence;
123
124 if div < 15.0 {
125 div = 15.0;
126 }
127
128 let hue = (self.hue + div + f).abs() % 360.0;
129 let saturation = ((iteration * 0.35).cos() / 5.0).abs();
130 let value = 0.5 + (iteration.cos() / 2.0).abs();
131 (hue, saturation, value)
132 }
133
134 fn palette_random(&self) -> Hsv {
135 let iteration = self.iteration as f32;
136 let f = (iteration * 55.0).tan().abs();
137 let mut div = self.base_divergence;
138
139 if div < 15.0 {
140 div = 15.0;
141 }
142
143 let hue = (self.hue + div + f).abs() % 360.0;
144 let mut saturation = (iteration * 0.35).sin().abs();
145 let mut value = ((6.33 * iteration) * 0.5).cos().abs();
146
147 if saturation < 0.4 {
148 saturation = 0.4;
149 }
150
151 if value < 0.2 {
152 value = 0.2;
153 } else if value > 0.85 {
154 value = 0.85;
155 }
156 (hue, saturation, value)
157 }
158
159 pub fn get(&self) -> Hsv {
160 match self.palette_type {
161 PaletteType::Random => self.palette_random(),
162 PaletteType::Pastel => self.palette_pastel(),
163 PaletteType::Dark => self.palette_dark(),
164 }
165 }
166}
167
168impl Iterator for HsvPalette {
169 type Item = Hsv;
170
171 fn next(&mut self) -> Option<Self::Item> {
172 let (hue, saturation, value) = self.get();
173 self.hue = hue;
174 self.iteration += 1;
175 Some((hue, saturation, value))
176 }
177}
178
179impl Iterator for ColorPalette {
180 type Item = Color;
181
182 fn next(&mut self) -> Option<Self::Item> {
183 if let Some((hue, saturation, value)) = self.0.next() {
184 Some(Color::hsv_to_rgb(hue, saturation, value))
185 } else {
186 None
187 }
188 }
189}
190
191
192
193#[cfg(test)]
194mod tests {
195 use super::ColorPalette;
196 use super::PaletteType;
197
198 #[test]
199 fn generates_palette() {
200 let palette = ColorPalette::new(PaletteType::Random, false, &mut rand::thread_rng());
201
202 let colors = palette.take(7);
203
204 for color in colors {
205 let (red, green, blue) = color.to_tuple();
206 assert!(red >= 0.0);
207 assert!(red <= 1.0);
208
209 assert!(green >= 0.0);
210 assert!(green <= 1.0);
211
212 assert!(blue >= 0.0);
213 assert!(blue <= 1.0);
214 }
215 }
216}