PerspectiveTransform::quadrilateralToSquare()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 8
dl 0
loc 8
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * Class PerspectiveTransform
4
 *
5
 * @created      17.01.2021
6
 * @author       ZXing Authors
7
 * @author       Smiley <[email protected]>
8
 * @copyright    2021 Smiley
9
 * @license      Apache-2.0
10
 */
11
12
namespace chillerlan\QRCode\Detector;
13
14
use function count;
15
16
/**
17
 * This class implements a perspective transform in two dimensions. Given four source and four
18
 * destination points, it will compute the transformation implied between them. The code is based
19
 * directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.
20
 *
21
 * @author Sean Owen
22
 */
23
final class PerspectiveTransform{
24
25
	private float $a11;
26
	private float $a12;
27
	private float $a13;
28
	private float $a21;
29
	private float $a22;
30
	private float $a23;
31
	private float $a31;
32
	private float $a32;
33
	private float $a33;
34
35
	/**
36
	 *
37
	 */
38
	private function set(
39
		float $a11, float $a21, float $a31,
40
		float $a12, float $a22, float $a32,
41
		float $a13, float $a23, float $a33
42
	):self{
43
		$this->a11 = $a11;
44
		$this->a12 = $a12;
45
		$this->a13 = $a13;
46
		$this->a21 = $a21;
47
		$this->a22 = $a22;
48
		$this->a23 = $a23;
49
		$this->a31 = $a31;
50
		$this->a32 = $a32;
51
		$this->a33 = $a33;
52
53
		return $this;
54
	}
55
56
	/**
57
	 * @SuppressWarnings(PHPMD.ExcessiveParameterList)
58
	 */
59
	public function quadrilateralToQuadrilateral(
60
		float $x0, float $y0, float $x1, float $y1, float $x2, float $y2, float $x3, float $y3,
61
		float $x0p, float $y0p, float $x1p, float $y1p, float $x2p, float $y2p, float $x3p, float $y3p
62
	):self{
63
		return (new self)
64
			->squareToQuadrilateral($x0p, $y0p, $x1p, $y1p, $x2p, $y2p, $x3p, $y3p)
65
			->times($this->quadrilateralToSquare($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3));
66
	}
67
68
	/**
69
	 *
70
	 */
71
	private function quadrilateralToSquare(
72
		float $x0, float $y0, float $x1, float $y1,
73
		float $x2, float $y2, float $x3, float $y3
74
	):self{
75
		// Here, the adjoint serves as the inverse:
76
		return $this
77
			->squareToQuadrilateral($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)
78
			->buildAdjoint();
79
	}
80
81
	/**
82
	 *
83
	 */
84
	private function buildAdjoint():self{
85
		// Adjoint is the transpose of the cofactor matrix:
86
		return $this->set(
87
			($this->a22 * $this->a33 - $this->a23 * $this->a32),
88
			($this->a23 * $this->a31 - $this->a21 * $this->a33),
89
			($this->a21 * $this->a32 - $this->a22 * $this->a31),
90
			($this->a13 * $this->a32 - $this->a12 * $this->a33),
91
			($this->a11 * $this->a33 - $this->a13 * $this->a31),
92
			($this->a12 * $this->a31 - $this->a11 * $this->a32),
93
			($this->a12 * $this->a23 - $this->a13 * $this->a22),
94
			($this->a13 * $this->a21 - $this->a11 * $this->a23),
95
			($this->a11 * $this->a22 - $this->a12 * $this->a21)
96
		);
97
	}
98
99
	/**
100
	 *
101
	 */
102
	private function squareToQuadrilateral(
103
		float $x0, float $y0, float $x1, float $y1,
104
		float $x2, float $y2, float $x3, float $y3
105
	):self{
106
		$dx3 = ($x0 - $x1 + $x2 - $x3);
107
		$dy3 = ($y0 - $y1 + $y2 - $y3);
108
109
		if($dx3 === 0.0 && $dy3 === 0.0){
0 ignored issues
show
introduced by
The condition $dx3 === 0.0 is always false.
Loading history...
110
			// Affine
111
			return $this->set(($x1 - $x0), ($x2 - $x1), $x0, ($y1 - $y0), ($y2 - $y1), $y0, 0.0, 0.0, 1.0);
112
		}
113
114
		$dx1         = ($x1 - $x2);
115
		$dx2         = ($x3 - $x2);
116
		$dy1         = ($y1 - $y2);
117
		$dy2         = ($y3 - $y2);
118
		$denominator = ($dx1 * $dy2 - $dx2 * $dy1);
119
		$a13         = (($dx3 * $dy2 - $dx2 * $dy3) / $denominator);
120
		$a23         = (($dx1 * $dy3 - $dx3 * $dy1) / $denominator);
121
122
		return $this->set(
123
			($x1 - $x0 + $a13 * $x1),
124
			($x3 - $x0 + $a23 * $x3),
125
			$x0,
126
			($y1 - $y0 + $a13 * $y1),
127
			($y3 - $y0 + $a23 * $y3),
128
			$y0,
129
			$a13,
130
			$a23,
131
			1.0
132
		);
133
	}
134
135
	/**
136
	 *
137
	 */
138
	private function times(PerspectiveTransform $other):self{
139
		return $this->set(
140
			($this->a11 * $other->a11 + $this->a21 * $other->a12 + $this->a31 * $other->a13),
141
			($this->a11 * $other->a21 + $this->a21 * $other->a22 + $this->a31 * $other->a23),
142
			($this->a11 * $other->a31 + $this->a21 * $other->a32 + $this->a31 * $other->a33),
143
			($this->a12 * $other->a11 + $this->a22 * $other->a12 + $this->a32 * $other->a13),
144
			($this->a12 * $other->a21 + $this->a22 * $other->a22 + $this->a32 * $other->a23),
145
			($this->a12 * $other->a31 + $this->a22 * $other->a32 + $this->a32 * $other->a33),
146
			($this->a13 * $other->a11 + $this->a23 * $other->a12 + $this->a33 * $other->a13),
147
			($this->a13 * $other->a21 + $this->a23 * $other->a22 + $this->a33 * $other->a23),
148
			($this->a13 * $other->a31 + $this->a23 * $other->a32 + $this->a33 * $other->a33)
149
		);
150
	}
151
152
	/**
153
	 *
154
	 */
155
	public function transformPoints(array &$xValues, array &$yValues = null):void{
156
		$max = count($xValues);
157
158
		if($yValues !== null){
159
160
			for($i = 0; $i < $max; $i++){
161
				$x           = $xValues[$i];
162
				$y           = $yValues[$i];
163
				$denominator = ($this->a13 * $x + $this->a23 * $y + $this->a33);
164
				$xValues[$i] = (($this->a11 * $x + $this->a21 * $y + $this->a31) / $denominator);
165
				$yValues[$i] = (($this->a12 * $x + $this->a22 * $y + $this->a32) / $denominator);
166
			}
167
168
			return;
169
		}
170
171
		for($i = 0; $i < $max; $i += 2){
172
			$x                 = $xValues[$i];
173
			$y                 = $xValues[($i + 1)];
174
			$denominator       = ($this->a13 * $x + $this->a23 * $y + $this->a33);
175
			$xValues[$i]       = (($this->a11 * $x + $this->a21 * $y + $this->a31) / $denominator);
176
			$xValues[($i + 1)] = (($this->a12 * $x + $this->a22 * $y + $this->a32) / $denominator);
177
		}
178
	}
179
180
}
181