string_art 0.1.0-alpha.1

Convert images into thread patterns for creating string art. It generates detailed instructions in text format and provides graphical previews of the resulting patterns.
Documentation
use std::ops::Deref;

use crate::{
    verboser::Verboser, AsLab, Image
};

pub unsafe trait Builder<S> {
    fn build_line_selector(
        &self,
        image: &Image<S>,
        palette: &[impl AsLab<S>],
        verboser: &mut impl Verboser,
    ) -> Result<LineSelector, Error>;
}

#[derive(Clone, Copy)]
pub struct LineItemSelector {
    color_idx: usize,
    count: usize,
    cap: usize,
}

impl LineItemSelector {
    pub fn new(color_idx: usize, count: usize, cap: usize) -> Self {
        LineItemSelector {
            color_idx,
            count,
            cap,
        }
    }

    pub fn color_idx(&self) -> usize {
        self.color_idx
    }

    pub fn cap(&self) -> usize {
        self.cap
    }
}

pub struct LineGroupSelector(Vec<LineItemSelector>);

impl FromIterator<LineItemSelector> for LineGroupSelector {
    fn from_iter<T: IntoIterator<Item = LineItemSelector>>(iter: T) -> Self {
        LineGroupSelector(iter.into_iter().collect())
    }
}

impl LineGroupSelector {
    fn select_next(&mut self) -> Option<usize> {
        let mut choice = None;
        let mut best_ratio = 1.0;
        for item in self.0.iter_mut() {
            let ratio = item.count as f32 / item.cap as f32;
            if ratio < best_ratio {
                best_ratio = ratio;
                choice = Some(item);
            }
        }

        choice.map(|item| {
            item.count += 1;
            item.color_idx
        })
    }    
}

impl Deref for LineGroupSelector{
    type Target = [LineItemSelector];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

pub struct LineSelector{
    lines: Vec<LineGroupSelector>,
    curr: usize,
}

impl LineSelector {
    pub (crate) fn select_next(&mut self) -> Option<usize> {        
        while let Some(last) = self.lines.get_mut(self.curr) {
            if let Some(res) = last.select_next() {
                return Some(res);
            } else {
                self.curr = if self.curr == 0{
                    self.lines.len()
                } else{
                    unsafe { self.curr.unchecked_sub(1) }
                }
            }
        }

        None
    }    
}

impl Deref for LineSelector {
    type Target = [LineGroupSelector];

    fn deref(&self) -> &Self::Target {
        &self.lines
    }
}

impl FromIterator<LineGroupSelector> for LineSelector {
    fn from_iter<T: IntoIterator<Item = LineGroupSelector>>(iter: T) -> Self {
        let lines: Vec<_> = iter.into_iter().collect();
        LineSelector{
            curr: lines.len().checked_sub(1).unwrap_or(lines.len()),
            lines, 
        
        }
    }
}

#[derive(Debug, thiserror::Error)]
#[error("Invalid group index")]
pub struct Error;