Completed
Push — master ( 84cc98...56d3d7 )
by Edgar
03:12
created

PathBounds::getHBox()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 9
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 9
loc 9
rs 9.6666
cc 1
eloc 5
nc 1
nop 0
1
<?php
2
namespace nstdio\svg\shape;
3
4
use nstdio\svg\util\Bezier;
5
6
/**
7
 * Class PathBounds
8
 *
9
 * @package nstdio\svg\shape
10
 * @author  Edgar Asatryan <[email protected]>
11
 */
12
class PathBounds
13
{
14
    private $index;
15
    private $modifier;
16
    /**
17
     * The path points positions
18
     *
19
     * @var array
20
     */
21
    private $data = [];
22
23
    private $current;
24
25
    private $rect;
26
27
    public function __construct()
28
    {
29
        $this->rect = [
30
            'width'  => 0,
31
            'height' => 0,
32
            'x'      => null,
33
            'y'      => null,
34
        ];
35
    }
36
37
    public function addData($type, array $params)
38
    {
39
        $this->data[] = [$type => $params];
40
    }
41
42
    /**
43
     * @return array
44
     */
45
    public function getBox()
46
    {
47
48
        foreach ($this->data as $key => $value) {
49
            $this->modifier = key($value);
50
            $this->index = $key;
51
            $this->current = $value[$this->modifier];
52
53
            switch ($this->modifier) {
54
                case 'L':
55
                    $this->getLBox();
56
                    break;
57
                case 'H':
58
                    $this->getHBox();
59
                    break;
60
                case 'V':
61
                    $this->getVBox();
62
                    break;
63
                case 'Q':
64
                    $this->getQBox();
65
                    break;
66
                case 'C':
67
                    $this->getCBox();
68
                    break;
69
            }
70
        }
71
        unset($this->modifier, $this->index, $this->current);
72
73
        return $this->rect;
74
    }
75
76 View Code Duplication
    private function getLBox()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
77
    {
78
        list($x1, $y1) = $this->getStartPoint();
79
        list($x2, $y2) = $this->current;
80
81
        $this->union($this->getLineBox($x1, $y1, $x2, $y2));
82
83
    }
84
85
    private function getPreviousData()
86
    {
87
        $mod = $this->modifierAtIndex($this->index - 1);
88
89
        return $this->data[$this->index - 1][$mod];
90
    }
91
92
    private function modifierAtIndex($index)
93
    {
94
        return key($this->data[$index]);
95
    }
96
97
    private function union($box)
98
    {
99
        if ($this->rect['x'] === null) {
100
            $this->rect['x'] = $box['x'];
101
            $this->rect['y'] = $box['y'];
102
        }
103
        $this->rect = Rect::union($this->rect, $box);
104
    }
105
106
    private function getQBox()
107
    {
108
        list($p0x, $p0y) = $this->getStartPoint();
109
        list($p1x, $p1y, $p2x, $p2y) = $this->current;
110
111
        $box = Bezier::quadraticBBox($p0x, $p0y, $p1x, $p1y, $p2x, $p2y);
112
113
        $this->union($box);
114
    }
115
116
    private function getCBox()
117
    {
118
        list($p0x, $p0y) = $this->getStartPoint();
119
        list($p1x, $p1y, $p2x, $p2y, $p3x, $p3y) = $this->current;
120
121
        $box = Bezier::cubicBBox($p0x, $p0y, $p1x, $p1y, $p2x, $p2y, $p3x, $p3y);
122
123
        $this->union($box);
124
125
    }
126
127
    /**
128
     * @return array
129
     */
130
    public function getData()
131
    {
132
        return $this->data;
133
    }
134
135 View Code Duplication
    private function getHBox()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
136
    {
137
        list($x1, $y1) = $this->getStartPoint();
138
        $x2 = $this->current[0];
139
140
        $box = $this->getLineBox($x1, $y1, $x2, $y1);
141
142
        $this->union($box);
143
    }
144
145 View Code Duplication
    private function getVBox()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
146
    {
147
        list($x1, $y1) = $this->getStartPoint();
148
        $y2 = $this->current[0];
149
150
        $box = $this->getLineBox($x1, $y1, $x1, $y2);
151
152
        $this->union($box);
153
    }
154
155
    private function getLineBox($x1, $y1, $x2, $y2)
156
    {
157
        return [
158
            'width'  => max($x1, $x2) - min($x1, $x2),
159
            'height' => max($y1, $y2) - min($y1, $y2),
160
            'x'      => min($x1, $x2),
161
            'y'      => min($y1, $y2),
162
        ];
163
    }
164
165
    /**
166
     * @return array
167
     */
168
    private function getStartPoint()
169
    {
170
        $y1 = $this->getNearest('y');
171
        $x1 = $this->getNearest('x');
172
173
        if (!$y1) {
174
            throw new \RuntimeException('y cannot be null');
175
        }
176
        if (!$x1) {
177
            throw new \RuntimeException('x cannot be null');
178
        }
179
180
        return [$x1, $y1];
181
    }
182
183
    private function getNearest($axis)
184
    {
185
        $prevData = $this->getPreviousData();
186
        if ($axis === 'x') {
187
            $coordinate = $this->getStartX($prevData);
188
            $restrictedModifier = 'h';
189
        } else {
190
            $coordinate = $this->getStartY($prevData);
191
            $restrictedModifier = 'v';
192
        }
193
194
        if ($coordinate === false) {
195
            for ($i = $this->index - 2; $i >= 0; $i--) {
196
                $data = $this->data[$i];
197
                $modifier = key($data);
198
                $data = $data[$modifier];
199
                if (strtolower($modifier) !== $restrictedModifier) { // path H modifier does not have a X coordinate.
200
                    return $axis === 'x' ? $data[count($data) - 2] : $data[count($data) - 1];
201
                }
202
            }
203
        }
204
205
        return $coordinate;
206
    }
207
208
    /**
209
     * @param $data
210
     *
211
     * @return float|false
212
     */
213
    private function getStartX($data)
214
    {
215
        reset($data);
216
        end($data);
217
        $x = prev($data);
218
219
        return $x;
220
    }
221
222
    /**
223
     * @param $data
224
     *
225
     * @return float
226
     */
227
    private function getStartY($data)
228
    {
229
        reset($data);
230
        $y = end($data);
231
232
        return $y;
233
    }
234
}
235