Passed
Push — v5 ( 6b9eea...33c1e2 )
by smiley
09:46
created

PerspectiveTransform::set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
c 1
b 0
f 0
nc 1
nop 9
dl 0
loc 16
rs 9.9332

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
 * <p>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.</p>
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
	private function set(
36
		float $a11, float $a21, float $a31,
37
		float $a12, float $a22, float $a32,
38
		float $a13, float $a23, float $a33
39
	):PerspectiveTransform{
40
		$this->a11 = $a11;
41
		$this->a12 = $a12;
42
		$this->a13 = $a13;
43
		$this->a21 = $a21;
44
		$this->a22 = $a22;
45
		$this->a23 = $a23;
46
		$this->a31 = $a31;
47
		$this->a32 = $a32;
48
		$this->a33 = $a33;
49
50
		return $this;
51
	}
52
53
	public function quadrilateralToQuadrilateral(
54
		float $x0, float $y0, float $x1, float $y1, float $x2, float $y2, float $x3, float $y3,
55
		float $x0p, float $y0p, float $x1p, float $y1p, float $x2p, float $y2p, float $x3p, float $y3p
56
	):PerspectiveTransform{
57
		return (new self)
58
			->squareToQuadrilateral($x0p, $y0p, $x1p, $y1p, $x2p, $y2p, $x3p, $y3p)
59
			->times($this->quadrilateralToSquare($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3));
60
	}
61
62
	private function quadrilateralToSquare(
63
		float $x0, float $y0, float $x1, float $y1,
64
		float $x2, float $y2, float $x3, float $y3
65
	):PerspectiveTransform{
66
		// Here, the adjoint serves as the inverse:
67
		return $this
68
			->squareToQuadrilateral($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)
69
			->buildAdjoint();
70
	}
71
72
	private function buildAdjoint():PerspectiveTransform{
73
		// Adjoint is the transpose of the cofactor matrix:
74
		return $this->set(
75
			$this->a22 * $this->a33 - $this->a23 * $this->a32,
76
			$this->a23 * $this->a31 - $this->a21 * $this->a33,
77
			$this->a21 * $this->a32 - $this->a22 * $this->a31,
78
			$this->a13 * $this->a32 - $this->a12 * $this->a33,
79
			$this->a11 * $this->a33 - $this->a13 * $this->a31,
80
			$this->a12 * $this->a31 - $this->a11 * $this->a32,
81
			$this->a12 * $this->a23 - $this->a13 * $this->a22,
82
			$this->a13 * $this->a21 - $this->a11 * $this->a23,
83
			$this->a11 * $this->a22 - $this->a12 * $this->a21
84
		);
85
	}
86
87
	private function squareToQuadrilateral(
88
		float $x0, float $y0, float $x1, float $y1,
89
		float $x2, float $y2, float $x3, float $y3
90
	):PerspectiveTransform{
91
		$dx3 = $x0 - $x1 + $x2 - $x3;
92
		$dy3 = $y0 - $y1 + $y2 - $y3;
93
94
		if($dx3 === 0.0 && $dy3 === 0.0){
0 ignored issues
show
introduced by
The condition $dx3 === 0.0 is always false.
Loading history...
95
			// Affine
96
			return $this->set($x1 - $x0, $x2 - $x1, $x0, $y1 - $y0, $y2 - $y1, $y0, 0.0, 0.0, 1.0);
97
		}
98
99
		$dx1         = $x1 - $x2;
100
		$dx2         = $x3 - $x2;
101
		$dy1         = $y1 - $y2;
102
		$dy2         = $y3 - $y2;
103
		$denominator = $dx1 * $dy2 - $dx2 * $dy1;
104
		$a13         = ($dx3 * $dy2 - $dx2 * $dy3) / $denominator;
105
		$a23         = ($dx1 * $dy3 - $dx3 * $dy1) / $denominator;
106
107
		return $this->set(
108
			$x1 - $x0 + $a13 * $x1, $x3 - $x0 + $a23 * $x3, $x0,
109
			$y1 - $y0 + $a13 * $y1, $y3 - $y0 + $a23 * $y3, $y0,
110
			$a13, $a23, 1.0
111
		);
112
	}
113
114
	private function times(PerspectiveTransform $other):PerspectiveTransform{
115
		return $this->set(
116
			$this->a11 * $other->a11 + $this->a21 * $other->a12 + $this->a31 * $other->a13,
117
			$this->a11 * $other->a21 + $this->a21 * $other->a22 + $this->a31 * $other->a23,
118
			$this->a11 * $other->a31 + $this->a21 * $other->a32 + $this->a31 * $other->a33,
119
			$this->a12 * $other->a11 + $this->a22 * $other->a12 + $this->a32 * $other->a13,
120
			$this->a12 * $other->a21 + $this->a22 * $other->a22 + $this->a32 * $other->a23,
121
			$this->a12 * $other->a31 + $this->a22 * $other->a32 + $this->a32 * $other->a33,
122
			$this->a13 * $other->a11 + $this->a23 * $other->a12 + $this->a33 * $other->a13,
123
			$this->a13 * $other->a21 + $this->a23 * $other->a22 + $this->a33 * $other->a23,
124
			$this->a13 * $other->a31 + $this->a23 * $other->a32 + $this->a33 * $other->a33
125
		);
126
	}
127
128
	public function transformPoints(array &$xValues, array &$yValues = null):void{
129
		$max = count($xValues);
130
131
		if($yValues !== null){
132
133
			for($i = 0; $i < $max; $i++){
134
				$x           = $xValues[$i];
135
				$y           = $yValues[$i];
136
				$denominator = $this->a13 * $x + $this->a23 * $y + $this->a33;
137
				$xValues[$i] = ($this->a11 * $x + $this->a21 * $y + $this->a31) / $denominator;
138
				$yValues[$i] = ($this->a12 * $x + $this->a22 * $y + $this->a32) / $denominator;
139
			}
140
141
			return;
142
		}
143
144
		for($i = 0; $i < $max; $i += 2){
145
			$x               = $xValues[$i];
146
			$y               = $xValues[$i + 1];
147
			$denominator     = $this->a13 * $x + $this->a23 * $y + $this->a33;
148
			$xValues[$i]     = ($this->a11 * $x + $this->a21 * $y + $this->a31) / $denominator;
149
			$xValues[$i + 1] = ($this->a12 * $x + $this->a22 * $y + $this->a32) / $denominator;
150
		}
151
	}
152
153
}
154