1use std::collections::HashMap;
2use std::f64::consts::LN_2;
3use std::fs;
4use std::io::Cursor;
5use std::iter::FromIterator;
6use std::io::{self};
7
8use kd_tree::{KdPoint, KdTree};
9use kolor::Vec3;
10use ndarray::Array1;
11use ndarray::Array2;
12use serde_json::{json, Value};
13
14struct Item {
16 point: [f64; 3],
17 id: usize,
18}
19
20impl KdPoint for Item {
22 type Scalar = f64;
23 type Dim = typenum::U3;
24 fn at(&self, k: usize) -> f64 { self.point[k] }
26}
27
28pub struct C3 {
29 color: Array2<i64>,
30 c: usize,
31 w: usize,
32 a: Vec<f64>,
33 t: HashMap<i64, i64>,
34 terms: Vec<String>,
35 min_e: f64,
36 max_e: f64,
37 color_count: Array1<i64>,
38 terms_count: Array1<i64>,
39 tree: KdTree<Item>,
40}
41
42impl C3 {
44 pub fn new() -> C3 {
45
46 let body = include_str!("data.json");
47 let json: Value = serde_json::from_str(&body).unwrap();
48 let _colorvec: Vec<i64> = serde_json::from_value(json["color"].clone()).unwrap();
49 let rows = _colorvec.len() / 3;
50 let _color = Array2::from_shape_vec((rows, 3), _colorvec).unwrap();
51
52 let _c = _color.shape()[0];
53
54
55 let _a: Vec<f64> = serde_json::from_value(json["A"].clone()).unwrap();
56 let mut _t = HashMap::new();
57 let t_vec: Vec<i64> = serde_json::from_value(json["T"].clone()).unwrap();
58
59
60 for pair in t_vec.chunks(2) {
62 _t.insert(pair[0], pair[1]);
63 }
64 let tmp_vec = vec!["green", "blue", "purple", "red", "pink", "yellow", "orange", "brown", "teal", "lightblue", "grey", "limegreen", "magenta", "lightgreen", "brightgreen", "skyblue", "cyan", "turquoise", "darkblue", "darkgreen", "aqua", "olive", "navyblue", "lavender", "fuchsia", "black", "royalblue", "violet", "hotpink", "tan", "forestgreen", "lightpurple", "neongreen", "yellowgreen", "maroon", "darkpurple", "salmon", "peach", "beige", "lime", "seafoamgreen", "mustard", "brightblue", "lilac", "seagreen", "palegreen", "bluegreen", "mint", "lightbrown", "mauve", "darkred", "greyblue", "burntorange", "darkpink", "indigo", "periwinkle", "bluegrey", "lightpink", "aquamarine", "gold", "brightpurple", "grassgreen", "redorange", "bluepurple", "greygreen", "kellygreen", "puke", "rose", "darkteal", "babyblue", "paleblue", "greenyellow", "brickred", "lightgrey", "darkgrey", "white", "brightpink", "chartreuse", "purpleblue", "royalpurple", "burgundy", "goldenrod", "darkbrown", "lightorange", "darkorange", "redbrown", "paleyellow", "plum", "offwhite", "pinkpurple", "darkyellow", "lightyellow", "mustardyellow", "brightred", "peagreen", "khaki", "orangered", "crimson", "deepblue", "springgreen", "cream", "palepink", "yelloworange", "deeppurple", "pinkred", "pastelgreen", "sand", "rust", "lightred", "taupe", "armygreen", "robinseggblue", "huntergreen", "greenblue", "lightteal", "cerulean", "flesh", "orangebrown", "slateblue", "slate", "coral", "blueviolet", "ochre", "leafgreen", "electricblue", "seablue", "midnightblue", "steelblue", "brick", "palepurple", "mediumblue", "burntsienna", "darkmagenta", "eggplant", "sage", "darkturquoise", "puce", "bloodred", "neonpurple", "mossgreen", "terracotta", "oceanblue", "yellowbrown", "brightyellow", "dustyrose", "applegreen", "neonpink", "skin", "cornflowerblue", "lightturquoise", "wine", "deepred", "azure"];
65 let _terms: Vec<String> = tmp_vec.iter().map(|s| s.to_string()).collect();
66
67
68 let _w = _terms.len();
69 let mut color_count: Array1<i64> = Array1::zeros(_c);
70 let mut terms_count: Array1<i64> = Array1::zeros(_w);
71 for key in _t.keys() {
72 let mut v = 0;
73 if let Some(x) = _t.get(key) {
74 v = *x;
75 }
76 color_count[(*key as f64 / _w as f64).floor() as usize] += v;
77 terms_count[(*key % _w as i64) as usize] += v;
78 }
79 let pts = _color
80 .outer_iter()
81 .enumerate()
82 .map(|(i, row)| Item { point: [row[0] as f64, row[1] as f64, row[2] as f64], id: i })
83 .collect();
84 let tree: KdTree<Item> = KdTree::build_by_ordered_float(pts);
85 C3 {
87 c: _c,
88 color: _color,
89 a: _a,
90 t: _t,
91 w: _w,
92 terms: _terms,
93 min_e: -4.5,
94 max_e: 0.0,
95 color_count,
96 terms_count,
97 tree,
98 }
99 }
100 fn color_entropy(&self, c: usize) -> f64 {
101 let mut h: f64 = 0.0;
102 for w in 0..self.w {
103 let val = c as i64 * self.w as i64 + w as i64;
104 let mut p = 0.0;
105 if let Some(x) = self.t.get(&val as &i64) {
106 p = *x as f64 / self.color_count[c] as f64;
107 }
108 if p > 0.0 {
109 h += p * f64::ln(p) / LN_2;
110 }
111 }
112 h
113 }
114 fn color_related_terms(
115 &self,
116 c: usize,
117 limit: Option<usize>,
118 min_count: Option<usize>,
119 salience_threshold: Option<f64>,
120 ) -> Vec<HashMap<&str, f64>> {
121 let cc = c * self.w;
122 let mut list = Vec::new();
123 let mut sum = 0.0;
124 for w in 0..self.w {
125 if self.t.contains_key(&(cc as i64 + w as i64)) {
126 sum += self.t[&(cc as i64 + w as i64)] as f64;
127 list.push(HashMap::from_iter([
128 ("index", w as f64),
129 ("score", self.t[&(cc as i64 + w as i64)] as f64),
130 ]));
131 }
132 }
133 let mut filtered_list = list.iter().map(|x: &HashMap<&str, f64>| {
134 let score = x["score"] / sum;
135 let index = x["index"];
136 HashMap::from_iter([("score", score), ("index", index)])
137 }).collect::<Vec<HashMap<&str, f64>>>();
138
139 if let Some(threshold) = salience_threshold {
140 filtered_list = filtered_list.into_iter().filter(|x: &HashMap<&str, f64>| x["score"] > threshold).collect();
141 }
142 if let Some(min_count) = min_count {
143 filtered_list = filtered_list
144 .into_iter()
145 .filter(|x| self.terms_count[x["index"] as usize] > min_count as i64)
146 .collect();
147 }
148 filtered_list.sort_by(|a, b| b["score"].partial_cmp(&a["score"]).unwrap());
149 if let Some(limit) = limit {
150 filtered_list.truncate(limit);
151 }
152 filtered_list
153 }
154 pub(crate) fn color_cosine(
155 &self,
156 a: usize,
157 b: usize,
158 ) -> f64 {
159 let mut sa = 0.0;
160 let mut sb = 0.0;
161 let mut sc = 0.0;
162 for w in 0..self.w {
163 let mut ta = 0.0;
164 let mut tb = 0.0;
165 if let Some(val) = self.t.get(&((a * self.w + w) as i64)) {
166 ta = *val as f64;
167 }
168 if let Some(val) = self.t.get(&((b * self.w + w) as i64)) {
169 tb = *val as f64;
170 }
171 sa += ta * ta;
172 sb += tb * tb;
173 sc += ta * tb;
174 }
175 sc / (sa.sqrt() * sb.sqrt())
176 }
177 fn color_index(&self, c: [f64; 3]) -> usize {
178 let found = self.tree.nearest(&c ).unwrap();
181 let item = found.item.id;
182 item
183 }
184
185 fn color(&self, _x: [f64; 3]) -> HashMap<&str, f64> {
186 let c = self.color_index(_x);
187 let h = (self.color_entropy(c) - self.min_e) / (self.max_e - self.min_e);
188 let mut map: HashMap<&str, f64> = HashMap::new();
189 map.insert("c", c as f64);
190 map.insert("h", h);
191 map
192 }
193
194 fn analyze_palette(&self, palette: Array2<f64>) -> Vec<HashMap<&str, f64>> {
195 palette
196 .outer_iter()
197 .map(|row| self.color([row[0], row[1], row[2]]))
198 .collect()
199 }
200 fn get_palette_terms(&self, palette: Array2<f64>, color_term_limit: usize) -> Vec<Vec<HashMap<&str, f64>>> {
201 let mut terms = Vec::new();
202 for row in palette.outer_iter() {
203 let c = self.color_index([row[0], row[1], row[2]]);
204 let related_terms = self.color_related_terms(c, Some(color_term_limit), None, None);
205 terms.push(related_terms);
206 }
207 terms
208 }
209 fn compute_color_name_distance_matrix(&self, data: Vec<HashMap<&str, f64>>) -> Array2<f64> {
210 let n = data.len();
211 let mut matrix = Array2::zeros((n, n));
212
213 for i in 0..n {
214 for j in 0..i {
215 let cosine_distance = 1.0 - self.color_cosine(*data[i].get("c").unwrap() as usize, *data[j].get("c").unwrap() as usize);
216 matrix[[i, j]] = cosine_distance;
217 matrix[[j, i]] = cosine_distance;
218 }
219 }
220 matrix
221 }
222}
223