use super::tables::total_bits_in_layer;
use crate::output::BitMatrix;
#[derive(Debug, Clone)]
pub struct Layout {
pub compact: bool,
pub layers: usize,
pub base_size: usize,
pub size: usize,
pub center: usize,
pub alignment_map: Vec<usize>,
}
impl Layout {
pub fn new(compact: bool, layers: usize) -> Layout {
let base_size = (if compact { 11 } else { 14 }) + layers * 4;
let (size, alignment_map) = if compact {
(base_size, (0..base_size).collect())
} else {
let size = base_size + 1 + 2 * ((base_size / 2 - 1) / 15);
let orig_center = base_size / 2;
let center = size / 2;
let mut map = vec![0usize; base_size];
for i in 0..orig_center {
let new_offset = i + i / 15;
map[orig_center - i - 1] = center - new_offset - 1;
map[orig_center + i] = center + new_offset + 1;
}
(size, map)
};
Layout {
compact,
layers,
base_size,
size,
center: size / 2,
alignment_map,
}
}
fn is_grid_line(&self, p: usize) -> bool {
if self.compact {
return false;
}
let d = p.abs_diff(self.center);
d.is_multiple_of(16)
}
fn draw_reference_grid(&self, m: &mut BitMatrix) {
if self.compact {
return;
}
for y in 0..self.size {
for x in 0..self.size {
if (self.is_grid_line(x) || self.is_grid_line(y)) && (x + y) % 2 == 0 {
m.set(x, y, true);
}
}
}
}
fn draw_bullseye(&self, m: &mut BitMatrix) {
let c = self.center;
let rings = if self.compact { 5 } else { 7 };
let mut i = 0;
while i < rings {
for j in (c - i)..=(c + i) {
m.set(j, c - i, true);
m.set(j, c + i, true);
m.set(c - i, j, true);
m.set(c + i, j, true);
}
i += 2;
}
}
fn draw_orientation(&self, m: &mut BitMatrix) {
let c = self.center;
let r = if self.compact { 5 } else { 7 };
m.set(c - r, c - r, true);
m.set(c - r, c - r + 1, true);
m.set(c + r, c - r, true);
m.set(c - r, c + r, true);
}
pub fn mode_positions(&self) -> Vec<(usize, usize)> {
let c = self.center;
if self.compact {
let mut pos = vec![(0, 0); 28];
for i in 0..7 {
let offset = c - 3 + i;
pos[i] = (offset, c - 5);
pos[i + 7] = (c + 5, offset);
pos[20 - i] = (offset, c + 5);
pos[27 - i] = (c - 5, offset);
}
pos
} else {
let mut pos = vec![(0, 0); 40];
for i in 0..10 {
let offset = c - 5 + i + i / 5;
pos[i] = (offset, c - 7);
pos[i + 10] = (c + 7, offset);
pos[29 - i] = (offset, c + 7);
pos[39 - i] = (c - 7, offset);
}
pos
}
}
pub fn data_positions(&self) -> Vec<(usize, usize)> {
let am = &self.alignment_map;
let b = self.base_size;
let low = if self.compact { 9 } else { 12 };
let total = total_bits_in_layer(self.layers, self.compact);
let mut pos = vec![(0usize, 0usize); total];
let mut row_offset = 0usize;
for i in 0..self.layers {
let row_size = (self.layers - i) * 4 + low;
for j in 0..row_size {
let col = j * 2;
for k in 0..2 {
pos[row_offset + col + k] = (am[i * 2 + k], am[i * 2 + j]);
pos[row_offset + row_size * 2 + col + k] =
(am[i * 2 + j], am[b - 1 - i * 2 - k]);
pos[row_offset + row_size * 4 + col + k] =
(am[b - 1 - i * 2 - k], am[b - 1 - i * 2 - j]);
pos[row_offset + row_size * 6 + col + k] =
(am[b - 1 - i * 2 - j], am[i * 2 + k]);
}
}
row_offset += row_size * 8;
}
pos
}
pub fn draw_fixed(&self, m: &mut BitMatrix) {
self.draw_reference_grid(m);
self.draw_bullseye(m);
self.draw_orientation(m);
}
}