mod alignment;
mod corner_finder;
mod data_module_iter;
mod finder;
mod functional;
mod info;
mod mask;
mod module;
mod optimize;
mod penalty;
mod placement;
mod timing;
#[cfg(test)]
use alloc::string::String;
use alloc::{vec, vec::Vec};
pub use self::{functional::is_functional, mask::MaskPattern, module::Module};
use crate::{
cast::As,
types::{Color, EcLevel, Version},
};
#[derive(Clone, Debug)]
pub struct Canvas {
width: i16,
height: i16,
version: Version,
ec_level: EcLevel,
modules: Vec<Module>,
}
impl Canvas {
#[must_use]
pub fn new(version: Version, ec_level: EcLevel) -> Self {
let (width, height) = (version.width(), version.height());
let modules = vec![Module::Empty; (width * height).as_usize()];
Self {
width,
height,
version,
ec_level,
modules,
}
}
#[cfg(test)]
fn to_debug_str(&self) -> String {
let width = self.width;
let mut res = String::with_capacity((width * (width + 1)).as_usize());
for y in 0..self.height {
res.push('\n');
for x in 0..width {
res.push(match self.get(x, y) {
Module::Empty => '?',
Module::Masked(Color::Light) => '.',
Module::Masked(Color::Dark) => '#',
Module::Unmasked(Color::Light) => '-',
Module::Unmasked(Color::Dark) => '*',
});
}
}
res
}
#[cfg(test)]
fn to_debug_str_mask_same(&self) -> String {
let width = self.width;
let mut res = String::with_capacity((width * (width + 1)).as_usize());
for y in 0..self.height {
res.push('\n');
for x in 0..width {
res.push(match self.get(x, y) {
Module::Empty => '?',
Module::Masked(Color::Light) | Module::Unmasked(Color::Light) => '.',
Module::Masked(Color::Dark) | Module::Unmasked(Color::Dark) => '#',
});
}
}
res
}
fn coords_to_index(&self, x: i16, y: i16) -> usize {
let x = if x < 0 { x + self.width } else { x }.as_usize();
let y = if y < 0 { y + self.height } else { y }.as_usize();
y * self.width.as_usize() + x
}
#[must_use]
pub fn get(&self, x: i16, y: i16) -> Module {
self.modules[self.coords_to_index(x, y)]
}
pub fn get_mut(&mut self, x: i16, y: i16) -> &mut Module {
let index = self.coords_to_index(x, y);
&mut self.modules[index]
}
pub fn put(&mut self, x: i16, y: i16, color: Color) {
*self.get_mut(x, y) = Module::Masked(color);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_index() {
let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
assert_eq!(c.get(0, 4), Module::Empty);
assert_eq!(c.get(-1, -7), Module::Empty);
assert_eq!(c.get(21 - 1, 21 - 7), Module::Empty);
c.put(0, 0, Color::Dark);
c.put(-1, -7, Color::Light);
assert_eq!(c.get(0, 0), Module::Masked(Color::Dark));
assert_eq!(c.get(21 - 1, -7), Module::Masked(Color::Light));
assert_eq!(c.get(-1, 21 - 7), Module::Masked(Color::Light));
}
#[test]
fn test_debug_str() {
let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
for i in 3_i16..20 {
for j in 3_i16..20 {
*c.get_mut(i, j) = match ((i * 3) ^ j) % 5 {
0 => Module::Empty,
1 => Module::Masked(Color::Light),
2 => Module::Masked(Color::Dark),
3 => Module::Unmasked(Color::Light),
4 => Module::Unmasked(Color::Dark),
_ => unreachable!(),
};
}
}
assert_eq!(
c.to_debug_str(),
concat!(
"\n",
"?????????????????????\n",
"?????????????????????\n",
"?????????????????????\n",
"?????####****....---?\n",
"???--.##-..##?..#??.?\n",
"???#*?-.*?#.-*#?-*.??\n",
"?????*?*?****-*-*---?\n",
"???*.-.-.-?-?#?#?#*#?\n",
"???.*#.*.*#.*#*#.*#*?\n",
"?????.#-#--??.?.#---?\n",
"???-.?*.-#?-.?#*-#?.?\n",
"???##*??*..##*--*..??\n",
"?????-???--??---?---?\n",
"???*.#.*.#**.#*#.#*#?\n",
"???##.-##..##..?#..??\n",
"???.-?*.-?#.-?#*-?#*?\n",
"????-.#?-.**#?-.#?-.?\n",
"???**?-**??--**?-**??\n",
"???#?*?#?*#.*-.-*-.-?\n",
"???..-...--??###?###?\n",
"?????????????????????"
)
);
}
}