#pragma once
#include "ODRowReader.h"
#include "Range.h"
#include "Pattern.h"
#include <array>
#include <cmath>
#include <numeric>
namespace ZXing::OneD::DataBar {
inline bool IsFinder(int a, int b, int c, int d, int e)
{
int w = 2 * (b + c), n = d + e;
bool x = (w + 5 > 9 * n) &&
(w - 5 < 13 * n) &&
(a < 2 + 4 * e) &&
(4 * a > n);
#if defined(PRINT_DEBUG) && 0
printf("[");
for (bool v :
{w + 5 > 9 * n,
w - 5 < 13 * n,
a < 2 + 4 * e,
4 * a > n})
printf(" %d", v);
printf("]"); fflush(stdout);
#endif
return x;
};
inline PatternView Finder(const PatternView& view)
{
return view.subView(8, 5);
}
inline PatternView LeftChar(const PatternView& view)
{
return view.subView(0, 8);
}
inline PatternView RightChar(const PatternView& view)
{
return view.subView(13, 8);
}
inline float ModSizeFinder(const PatternView& view)
{
return Finder(view).sum() / 15.f;
}
inline bool IsGuard(int a, int b)
{
return a > b * 3 / 4 - 2 && a < b * 5 / 4 + 2;
}
inline bool IsCharacter(const PatternView& view, int modules, float modSizeRef)
{
float err = std::abs(float(view.sum()) / modules / modSizeRef - 1);
return err < 0.1f;
}
struct Character
{
int value = -1, checksum = 0;
operator bool() const noexcept { return value != -1; }
bool operator==(const Character& o) const noexcept { return value == o.value && checksum == o.checksum; }
bool operator!=(const Character& o) const { return !(*this == o); }
};
struct Pair
{
Character left, right;
int finder = 0, xStart = -1, xStop = 1, y = -1, count = 1;
operator bool() const noexcept { return finder != 0; }
bool operator==(const Pair& o) const noexcept { return finder == o.finder && left == o.left && right == o.right; }
bool operator!=(const Pair& o) const noexcept { return !(*this == o); }
int center() const { return std::midpoint(xStart, xStop); }
};
struct PairHash
{
std::size_t operator()(const Pair& p) const noexcept
{
return p.left.value ^ p.left.checksum ^ p.right.value ^ p.right.checksum ^ p.finder;
}
};
constexpr int FULL_PAIR_SIZE = 8 + 5 + 8;
constexpr int HALF_PAIR_SIZE = 8 + 5 + 2;
template<int N>
int ParseFinderPattern(const PatternView& view, bool reversed, const std::array<std::array<int, 3>, N>& e2ePatterns)
{
const auto e2e = NormalizedE2EPattern<5>(view, 15, reversed);
int best_i = -1, best_e = 3;
for (int i = 0; i < Size(e2ePatterns); ++i) {
int e = 0;
for (int j = 0; j < 3; ++j)
e += std::abs(e2ePatterns[i][j] - e2e[j]);
if (e < best_e) {
best_e = e;
best_i = i;
}
}
int i = best_e <= 1 ? 1 + best_i : 0;
return reversed ? -i : i;
}
template <typename T>
struct OddEven
{
T odd = {}, evn = {};
T& operator[](int i) { return i & 1 ? evn : odd; }
};
using Array4I = std::array<int, 4>;
template <int LEN>
std::array<int, LEN> NormalizedPatternFromE2E(const PatternView& view, int mods, bool reversed = false)
{
bool minOddIsOne = mods == 15 || mods == 17;
const auto e2e = NormalizedE2EPattern<LEN>(view, mods, reversed);
std::array<int, LEN> widths;
int barSum = widths[0] = minOddIsOne ? 8 : 1; for (int i = 0; i < Size(e2e); i++) {
widths[i + 1] = e2e[i] - widths[i];
barSum += widths[i + 1];
}
widths.back() = mods - barSum;
OddEven<int> min = {widths[0], widths[1]};
for (int i = 2; i < Size(widths); i++)
min[i] = std::min(min[i], widths[i]);
if (minOddIsOne && min[0] > 1) {
for (int i = 0; i < Size(widths); i += 2) {
widths[i] -= min[0] - 1;
widths[i + 1] += min[0] - 1;
}
} else if (!minOddIsOne && min[1] > 1) {
for (int i = 0; i < Size(widths); i += 2) {
widths[i] += min[1] - 1;
widths[i + 1] -= min[1] - 1;
}
}
return widths;
}
bool ReadDataCharacterRaw(const PatternView& view, int numModules, bool reversed, Array4I& oddPattern,
Array4I& evnPattern);
int GetValue(ArrayView<int> widths, int maxWidth, bool noNarrow);
Position EstimatePosition(const Pair& first, const Pair& last);
int EstimateLineCount(const Pair& first, const Pair& last);
}