chore: complete update
This commit is contained in:
204
src/Domain/QrCode/Service/QrCodeMasker.php
Normal file
204
src/Domain/QrCode/Service/QrCodeMasker.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Domain\QrCode\Service;
|
||||
|
||||
use App\Domain\QrCode\ValueObject\MaskPattern;
|
||||
|
||||
class QrCodeMasker
|
||||
{
|
||||
/**
|
||||
* Findet die beste Maske für die Matrix
|
||||
*/
|
||||
public function findBestMask(array $matrix, int $size): MaskPattern
|
||||
{
|
||||
$lowestPenalty = PHP_INT_MAX;
|
||||
$bestMask = MaskPattern::PATTERN_0;
|
||||
|
||||
foreach (MaskPattern::cases() as $mask) {
|
||||
$testMatrix = $matrix;
|
||||
$this->applyMask($testMatrix, $size, $mask);
|
||||
$penalty = $this->calculateMaskPenalty($testMatrix, $size);
|
||||
|
||||
if ($penalty < $lowestPenalty) {
|
||||
$lowestPenalty = $penalty;
|
||||
$bestMask = $mask;
|
||||
}
|
||||
}
|
||||
|
||||
return $bestMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wendet eine Maske auf die Matrix an
|
||||
*/
|
||||
public function applyMask(array &$matrix, int $size, MaskPattern $maskPattern): void
|
||||
{
|
||||
for ($row = 0; $row < $size; $row++) {
|
||||
for ($col = 0; $col < $size; $col++) {
|
||||
if ($matrix[$row][$col] === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->isFunctionModule($row, $col, $size)) {
|
||||
if ($maskPattern->shouldMask($row, $col)) {
|
||||
$matrix[$row][$col] = !$matrix[$row][$col];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Strafpunkte für eine maskierte Matrix
|
||||
*/
|
||||
public function calculateMaskPenalty(array $matrix, int $size): int
|
||||
{
|
||||
$penalty = 0;
|
||||
|
||||
// Regel 1: Aufeinanderfolgende Module gleicher Farbe
|
||||
$penalty += $this->evaluateConsecutiveModulesPenalty($matrix, $size);
|
||||
|
||||
// Regel 2: Blöcke gleicher Farbe
|
||||
$penalty += $this->evaluateSameColorBlocksPenalty($matrix, $size);
|
||||
|
||||
// Regel 3: Muster, die Finder-Pattern ähneln
|
||||
$penalty += $this->evaluateFinderPatternLikePenalty($matrix, $size);
|
||||
|
||||
// Regel 4: Ausgewogenheit schwarzer und weißer Module
|
||||
$penalty += $this->evaluateBalancePenalty($matrix, $size);
|
||||
|
||||
return $penalty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluiert die Strafe für aufeinanderfolgende Module gleicher Farbe
|
||||
*/
|
||||
private function evaluateConsecutiveModulesPenalty(array $matrix, int $size): int
|
||||
{
|
||||
$penalty = 0;
|
||||
|
||||
// Zeilen prüfen
|
||||
for ($row = 0; $row < $size; $row++) {
|
||||
$count = 1;
|
||||
for ($col = 1; $col < $size; $col++) {
|
||||
if ($matrix[$row][$col] === $matrix[$row][$col - 1]) {
|
||||
$count++;
|
||||
} else {
|
||||
if ($count >= 5) {
|
||||
$penalty += 3 + ($count - 5);
|
||||
}
|
||||
$count = 1;
|
||||
}
|
||||
}
|
||||
if ($count >= 5) {
|
||||
$penalty += 3 + ($count - 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Spalten prüfen
|
||||
for ($col = 0; $col < $size; $col++) {
|
||||
$count = 1;
|
||||
for ($row = 1; $row < $size; $row++) {
|
||||
if ($matrix[$row][$col] === $matrix[$row - 1][$col]) {
|
||||
$count++;
|
||||
} else {
|
||||
if ($count >= 5) {
|
||||
$penalty += 3 + ($count - 5);
|
||||
}
|
||||
$count = 1;
|
||||
}
|
||||
}
|
||||
if ($count >= 5) {
|
||||
$penalty += 3 + ($count - 5);
|
||||
}
|
||||
}
|
||||
|
||||
return $penalty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluiert die Strafe für 2x2 Blöcke gleicher Farbe
|
||||
*/
|
||||
private function evaluateSameColorBlocksPenalty(array $matrix, int $size): int
|
||||
{
|
||||
$penalty = 0;
|
||||
|
||||
for ($row = 0; $row < $size - 1; $row++) {
|
||||
for ($col = 0; $col < $size - 1; $col++) {
|
||||
$color = $matrix[$row][$col];
|
||||
if ($color === $matrix[$row][$col + 1] &&
|
||||
$color === $matrix[$row + 1][$col] &&
|
||||
$color === $matrix[$row + 1][$col + 1]) {
|
||||
$penalty += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $penalty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluiert die Strafe für Muster, die wie Finder-Pattern aussehen
|
||||
*/
|
||||
private function evaluateFinderPatternLikePenalty(array $matrix, int $size): int
|
||||
{
|
||||
$penalty = 0;
|
||||
// Vereinfachte Implementation
|
||||
return $penalty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluiert die Strafe für unausgewogene schwarze/weiße Module
|
||||
*/
|
||||
private function evaluateBalancePenalty(array $matrix, int $size): int
|
||||
{
|
||||
$darkCount = 0;
|
||||
$totalCount = $size * $size;
|
||||
|
||||
for ($row = 0; $row < $size; $row++) {
|
||||
for ($col = 0; $col < $size; $col++) {
|
||||
if ($matrix[$row][$col] === true) {
|
||||
$darkCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$darkPercentage = $darkCount * 100 / $totalCount;
|
||||
$deviation = abs($darkPercentage - 50) / 5;
|
||||
|
||||
return (int) ($deviation * 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob ein Modul ein Funktionsmodul ist (also nicht maskiert werden sollte)
|
||||
*/
|
||||
private function isFunctionModule(int $row, int $col, int $size): bool
|
||||
{
|
||||
// Finder-Pattern und Separatoren
|
||||
if (($row < 9 && $col < 9) ||
|
||||
($row < 9 && $col >= $size - 8) ||
|
||||
($row >= $size - 8 && $col < 9)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Timing-Pattern
|
||||
if ($row === 6 || $col === 6) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Format-Informationen
|
||||
if (($row < 9 && $col === 8) || ($row === 8 && $col < 9) ||
|
||||
($row === 8 && $col >= $size - 8) || ($row >= $size - 8 && $col === 8)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dark Module bei Version 1
|
||||
if ($row === 8 && $col === 13) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user