Passed
Push — v5 ( 93618e...84eb31 )
by smiley
01:52
created

PerspectiveTransform::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 9
c 1
b 0
f 0
nc 1
nop 9
dl 0
loc 14
rs 9.9666

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