Completed
Push — master ( b8d8de...2f6d07 )
by smiley
05:15
created

MaskPatternTester::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Class MaskPatternTester
4
 *
5
 * @filesource   MaskPatternTester.php
6
 * @created      22.11.2017
7
 * @package      chillerlan\QRCode\Data
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\QRCode\Data;
14
15
/**
16
 * The sole purpose of this class is to receive a QRMatrix object and run the pattern tests on it.
17
 *
18
 * @link http://www.thonky.com/qr-code-tutorial/data-masking
19
 */
20
class MaskPatternTester{
21
22
	/**
23
	 * @var \chillerlan\QRCode\Data\QRMatrix
24
	 */
25
	protected $matrix;
26
27
	/**
28
	 * @var int
29
	 */
30
	protected $moduleCount;
31
32
	/**
33
	 * Receives the matrix an sets the module count
34
	 *
35
	 * @see \chillerlan\QRCode\QROptions::$maskPattern
36
	 * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern
37
	 * @see \chillerlan\QRCode\QRCode::getBestMaskPattern()
38
	 *
39
	 * @param \chillerlan\QRCode\Data\QRMatrix $matrix
40
	 */
41
	public function __construct(QRMatrix $matrix){
42
		$this->matrix      = $matrix;
43
		$this->moduleCount = $this->matrix->size();
44
	}
45
46
	/**
47
	 * Returns the penalty for the given mask pattern
48
	 *
49
	 * @see \chillerlan\QRCode\QROptions::$maskPattern
50
	 * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern
51
	 * @see \chillerlan\QRCode\QRCode::getBestMaskPattern()
52
	 *
53
	 * @return int
54
	 */
55
	public function testPattern():int{
56
		$penalty  = 0;
57
58
		for($level = 1; $level <= 4; $level++){
59
			$penalty += call_user_func([$this, 'testLevel'.$level]);
60
		}
61
62
		return (int)$penalty;
63
	}
64
65
	/**
66
	 * Checks for each group of five or more same-colored modules in a row (or column)
67
	 *
68
	 * @return float
69
	 */
70
	protected function testLevel1():float{
71
		$penalty = 0;
72
73
		foreach($this->matrix->matrix() as $y => $row){
74
			foreach($row as $x => $val){
75
				$count = 0;
76
77
				for($ry = -1; $ry <= 1; $ry++){
78
79
					if($y + $ry < 0 || $this->moduleCount <= $y + $ry){
80
						continue;
81
					}
82
83
					for($rx = -1; $rx <= 1; $rx++){
84
85
						if(($ry === 0 && $rx === 0) || ($x + $rx < 0 || $this->moduleCount <= $x + $rx)){
86
							continue;
87
						}
88
89
						if($this->matrix->check($x + $rx, $y + $ry) === ($val >> 8 > 0)){
90
							$count++;
91
						}
92
93
					}
94
				}
95
96
				if($count > 5){
97
					$penalty += (3 + $count - 5);
98
				}
99
100
			}
101
		}
102
103
		return $penalty;
104
	}
105
106
	/**
107
	 * Checks for each 2x2 area of same-colored modules in the matrix
108
	 *
109
	 * @return float
110
	 */
111
	protected function testLevel2():float{
112
		$penalty = 0;
113
114
		foreach($this->matrix->matrix() as $y => $row){
115
116
			if($y > $this->moduleCount - 2){
117
				break;
118
			}
119
120
			foreach($row as $x => $val){
121
122
				if($x > $this->moduleCount - 2){
123
					break;
124
				}
125
126
				$count = 0;
127
128
				if($val >> 8 > 0){
129
					$count++;
130
				}
131
132
				if($this->matrix->check($y, $x + 1)){
133
					$count++;
134
				}
135
136
				if($this->matrix->check($y + 1, $x)){
137
					$count++;
138
				}
139
140
				if($this->matrix->check($y + 1, $x + 1)){
141
					$count++;
142
				}
143
144
				if($count === 0 || $count === 4){
145
					$penalty += 3;
146
				}
147
148
			}
149
		}
150
151
		return $penalty;
152
	}
153
154
	/**
155
	 * Checks if there are patterns that look similar to the finder patterns
156
	 *
157
	 * @return float
158
	 */
159
	protected function testLevel3():float{
160
		$penalty = 0;
161
162
		foreach($this->matrix->matrix() as $y => $row){
163
			foreach($row as $x => $val){
164
165 View Code Duplication
				if($x <= $this->moduleCount - 7){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
					if(
167
						    $this->matrix->check($x    , $y)
168
						&& !$this->matrix->check($x + 1, $y)
169
						&&  $this->matrix->check($x + 2, $y)
170
						&&  $this->matrix->check($x + 3, $y)
171
						&&  $this->matrix->check($x + 4, $y)
172
						&& !$this->matrix->check($x + 5, $y)
173
						&&  $this->matrix->check($x + 6, $y)
174
					){
175
						$penalty += 40;
176
					}
177
				}
178
179 View Code Duplication
				if($y <= $this->moduleCount - 7){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
					if(
181
						    $this->matrix->check($x, $y)
182
						&& !$this->matrix->check($x, $y + 1)
183
						&&  $this->matrix->check($x, $y + 2)
184
						&&  $this->matrix->check($x, $y + 3)
185
						&&  $this->matrix->check($x, $y + 4)
186
						&& !$this->matrix->check($x, $y + 5)
187
						&&  $this->matrix->check($x, $y + 6)
188
					){
189
						$penalty += 40;
190
					}
191
				}
192
193
			}
194
		}
195
196
		return $penalty;
197
	}
198
199
	/**
200
	 * Checks if more than half of the modules are dark or light, with a larger penalty for a larger difference
201
	 *
202
	 * @return float
203
	 */
204
	protected function testLevel4():float {
205
		$count = 0;
206
207
		foreach($this->matrix->matrix() as $y => $row){
208
			foreach($row as $x => $val){
209
				if($val >> 8 > 0){
210
					$count++;
211
				}
212
			}
213
		}
214
215
		return (abs(100 * $count / $this->moduleCount / $this->moduleCount - 50) / 5) * 10;
216
	}
217
218
}
219