string_art/
line_selector.rs1use std::ops::Deref;
2
3use crate::{
4 verboser::Verboser, AsLab, Image
5};
6
7pub unsafe trait Builder<S> {
8 fn build_line_selector(
9 &self,
10 image: &Image<S>,
11 palette: &[impl AsLab<S>],
12 verboser: &mut impl Verboser,
13 ) -> Result<LineSelector, Error>;
14}
15
16#[derive(Clone, Copy)]
17pub struct LineItemSelector {
18 color_idx: usize,
19 count: usize,
20 cap: usize,
21}
22
23impl LineItemSelector {
24 pub fn new(color_idx: usize, count: usize, cap: usize) -> Self {
25 LineItemSelector {
26 color_idx,
27 count,
28 cap,
29 }
30 }
31
32 pub fn color_idx(&self) -> usize {
33 self.color_idx
34 }
35
36 pub fn cap(&self) -> usize {
37 self.cap
38 }
39}
40
41pub struct LineGroupSelector(Vec<LineItemSelector>);
42
43impl FromIterator<LineItemSelector> for LineGroupSelector {
44 fn from_iter<T: IntoIterator<Item = LineItemSelector>>(iter: T) -> Self {
45 LineGroupSelector(iter.into_iter().collect())
46 }
47}
48
49impl LineGroupSelector {
50 fn select_next(&mut self) -> Option<usize> {
51 let mut choice = None;
52 let mut best_ratio = 1.0;
53 for item in self.0.iter_mut() {
54 let ratio = item.count as f32 / item.cap as f32;
55 if ratio < best_ratio {
56 best_ratio = ratio;
57 choice = Some(item);
58 }
59 }
60
61 choice.map(|item| {
62 item.count += 1;
63 item.color_idx
64 })
65 }
66}
67
68impl Deref for LineGroupSelector{
69 type Target = [LineItemSelector];
70
71 fn deref(&self) -> &Self::Target {
72 &self.0
73 }
74}
75
76pub struct LineSelector{
77 lines: Vec<LineGroupSelector>,
78 curr: usize,
79}
80
81impl LineSelector {
82 pub (crate) fn select_next(&mut self) -> Option<usize> {
83 while let Some(last) = self.lines.get_mut(self.curr) {
84 if let Some(res) = last.select_next() {
85 return Some(res);
86 } else {
87 self.curr = if self.curr == 0{
88 self.lines.len()
89 } else{
90 unsafe { self.curr.unchecked_sub(1) }
91 }
92 }
93 }
94
95 None
96 }
97}
98
99impl Deref for LineSelector {
100 type Target = [LineGroupSelector];
101
102 fn deref(&self) -> &Self::Target {
103 &self.lines
104 }
105}
106
107impl FromIterator<LineGroupSelector> for LineSelector {
108 fn from_iter<T: IntoIterator<Item = LineGroupSelector>>(iter: T) -> Self {
109 let lines: Vec<_> = iter.into_iter().collect();
110 LineSelector{
111 curr: lines.len().checked_sub(1).unwrap_or(lines.len()),
112 lines,
113
114 }
115 }
116}
117
118#[derive(Debug, thiserror::Error)]
119#[error("Invalid group index")]
120pub struct Error;