#![allow(dead_code)]
use crate::common::Result;
use crate::common::cpp_essentials::{
BarAndSpace, GetPatternRow, NormalizedPattern, PatternRow, PatternType, ToInt, UpdateMinMax,
};
use crate::qrcode::cpp_port::detector::AppendBit;
use crate::{RXingResult, common::cpp_essentials::PatternView};
use super::dxfilm_edge_reader::Clock;
type Pattern = PatternRow;
type Counter = PatternRow;
type Index = Vec<u32>;
type Alphabet = Vec<char>;
#[derive(Default, Debug, Clone)]
pub struct DecodingState {
pub centerRow: u32,
pub clocks: Vec<Clock>,
}
pub trait RowReader {
fn decodePattern(
&self,
rowNumber: u32,
next: &mut PatternView,
state: &mut Option<DecodingState>,
) -> Result<RXingResult>;
fn PatternMatchVariance(
counters: &Counter,
pattern: &Pattern,
length: usize,
maxIndividualVariance: f32,
) -> f32 {
let mut maxIndividualVariance = maxIndividualVariance;
let total: PatternType = counters.sum(); let patternLength: PatternType = pattern.sum(); if total < patternLength {
return f32::MAX;
}
let unitBarWidth: f32 = total as f32 / patternLength as f32;
maxIndividualVariance *= unitBarWidth;
let mut totalVariance: f32 = 0.0;
for x in 0..length {
let variance: f32 = (counters[x] as f32 - pattern[x] as f32 * unitBarWidth).abs();
if variance > maxIndividualVariance {
return f32::MAX;
}
totalVariance += variance;
}
totalVariance / total as f32
}
fn PatternMatchVarianceNoLength(
counters: &Counter,
pattern: &Pattern,
maxIndividualVariance: f32,
) -> f32 {
assert!(counters.len() == pattern.len());
Self::PatternMatchVariance(counters, pattern, counters.len(), maxIndividualVariance)
}
fn DecodeDigit(
counters: &Counter,
patterns: Vec<Pattern>,
maxAvgVariance: f32,
maxIndividualVariance: f32,
requireUnambiguousMatch: Option<bool>,
) -> i32 {
let requireUnambiguousMatch = requireUnambiguousMatch.unwrap_or(true);
let mut bestVariance: f32 = maxAvgVariance; const INVALID_MATCH: i32 = -1;
let mut bestMatch = INVALID_MATCH;
for (i, pattern) in patterns.iter().enumerate() {
let variance: f32 =
Self::PatternMatchVarianceNoLength(counters, pattern, maxIndividualVariance);
if variance < bestVariance {
bestVariance = variance;
bestMatch = i as i32;
} else if requireUnambiguousMatch && variance == bestVariance {
bestMatch = INVALID_MATCH;
}
}
bestMatch
}
fn NarrowWideThreshold(view: &PatternView) -> BarAndSpace<i32> {
let mut m: BarAndSpace<i32> = BarAndSpace::new(view[0] as i32, view[1] as i32);
let mut M: BarAndSpace<i32> = m.clone();
for i in 0..view.size() {
UpdateMinMax(&mut m[i], &mut M[i], view[i] as i32);
}
let mut res = BarAndSpace::default();
for i in 0..2 {
if M[i] > 4 * (m[i] + 1) || M[i] > 3 * M[i + 1] || m[i] > 2 * (m[i + 1] + 1) {
return BarAndSpace::default();
}
res[i] = std::cmp::max((m[i] + M[i]) / 2, m[i] * 3 / 2);
}
res
}
fn NarrowWideBitPattern(view: &PatternView) -> i32 {
let threshold = Self::NarrowWideThreshold(view);
if !threshold.isValid() {
return -1;
}
let mut pattern: i32 = 0;
for i in 0..view.size() {
if view[i] as i32 > threshold[i] * 2 {
return -1;
}
AppendBit(&mut pattern, view[i] as i32 > threshold[i]);
}
pattern
}
fn OneToFourBitPattern<const LEN: usize, const SUM: usize>(view: &PatternView) -> Option<u32> {
ToInt(&NormalizedPattern::<LEN, SUM>(view).ok()?.map(|x| x as u32))
}
fn LookupBitPattern(pattern: u32, table: &Index, alphabet: &Alphabet) -> char {
if let Some(i) = table.iter().position(|e| *e == pattern) {
alphabet[i]
} else {
char::from(0)
}
}
fn DecodeNarrowWidePattern(view: &PatternView, table: &Index, alphabet: &Alphabet) -> char {
Self::LookupBitPattern(Self::NarrowWideBitPattern(view) as u32, table, alphabet)
}
}
fn DecodeSingleRow<Range, RR>(reader: &RR, range: &[Range]) -> Result<RXingResult>
where
Range: Into<PatternType> + Copy + Default + From<Range>,
RR: RowReader,
{
let mut row = PatternRow::default();
GetPatternRow(range, &mut row);
let mut view = PatternView::new(&row);
let state = DecodingState::default();
reader.decodePattern(0, &mut view, &mut Some(state))
}