bc-lifehash 0.1.0

LifeHash visual hashing algorithm
Documentation
use crate::{
    color::Color, color_func::ColorFunc, frac_grid::FracGrid, grid::Grid,
    patterns::Pattern,
};

struct Transform {
    transpose: bool,
    reflect_x: bool,
    reflect_y: bool,
}

pub struct ColorGrid {
    pub grid: Grid<Color>,
}

impl ColorGrid {
    pub fn new(
        frac_grid: &FracGrid,
        gradient: &ColorFunc,
        pattern: Pattern,
    ) -> Self {
        let multiplier = if pattern == Pattern::Fiducial { 1 } else { 2 };
        let target_width = frac_grid.grid.width * multiplier;
        let target_height = frac_grid.grid.height * multiplier;

        let mut grid: Grid<Color> = Grid::new(target_width, target_height);
        let max_x = target_width - 1;
        let max_y = target_height - 1;

        let transforms: Vec<Transform> = match pattern {
            Pattern::Snowflake => vec![
                Transform {
                    transpose: false,
                    reflect_x: false,
                    reflect_y: false,
                },
                Transform {
                    transpose: false,
                    reflect_x: true,
                    reflect_y: false,
                },
                Transform {
                    transpose: false,
                    reflect_x: false,
                    reflect_y: true,
                },
                Transform {
                    transpose: false,
                    reflect_x: true,
                    reflect_y: true,
                },
            ],
            Pattern::Pinwheel => vec![
                Transform {
                    transpose: false,
                    reflect_x: false,
                    reflect_y: false,
                },
                Transform {
                    transpose: true,
                    reflect_x: true,
                    reflect_y: false,
                },
                Transform {
                    transpose: true,
                    reflect_x: false,
                    reflect_y: true,
                },
                Transform {
                    transpose: false,
                    reflect_x: true,
                    reflect_y: true,
                },
            ],
            Pattern::Fiducial => vec![Transform {
                transpose: false,
                reflect_x: false,
                reflect_y: false,
            }],
        };

        let frac_width = frac_grid.grid.width;
        let frac_height = frac_grid.grid.height;
        for y in 0..frac_height {
            for x in 0..frac_width {
                let value = frac_grid.grid.get_value(x, y);
                let color = gradient(value);
                for t in &transforms {
                    let mut px = x;
                    let mut py = y;
                    if t.transpose {
                        std::mem::swap(&mut px, &mut py);
                    }
                    if t.reflect_x {
                        px = max_x - px;
                    }
                    if t.reflect_y {
                        py = max_y - py;
                    }
                    grid.set_value(color, px, py);
                }
            }
        }

        Self { grid }
    }

    pub fn colors(&self) -> Vec<f64> {
        let mut result = Vec::with_capacity(self.grid.storage.len() * 3);
        for c in &self.grid.storage {
            result.push(c.r);
            result.push(c.g);
            result.push(c.b);
        }
        result
    }
}