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

Path::arcTo()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.2
cc 4
eloc 3
nc 1
nop 8

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
namespace nstdio\svg\shape;
3
4
use nstdio\svg\container\ContainerInterface;
5
use nstdio\svg\ElementInterface;
6
use nstdio\svg\traits\ElementTrait;
7
8
/**
9
 * Class Path
10
 *
11
 * @property string $d This attribute defines a path to follow. {@link
12
 *           https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d}
13
 * @package shape
14
 * @author  Edgar Asatryan <[email protected]>
15
 */
16
class Path extends Shape implements ContainerInterface
17
{
18
    use ElementTrait;
19
20
    /**
21
     * @var  PathBounds
22
     */
23
    private $boundingBox;
24
25
    /**
26
     * Path constructor.
27
     *
28
     * @param ElementInterface $parent
29
     * @param float            $x
30
     * @param float            $y
31
     * @param bool             $absolute
32
     */
33
    public function __construct(ElementInterface $parent, $x, $y, $absolute = true)
34
    {
35
        parent::__construct($parent);
36
37
        $this->boundingBox = new PathBounds();
38
        $this->moveTo($x, $y, $absolute);
39
    }
40
41
    /**
42
     * Start a new sub-path at the given (x,y) coordinate. M (uppercase) indicates that absolute coordinates will
43
     * follow; m (lowercase) indicates that relative coordinates will follow. If a moveto is followed by multiple pairs
44
     * of coordinates, the subsequent pairs are treated as implicit lineto commands. Hence, implicit lineto commands
45
     * will be relative if the moveto is relative, and absolute if the moveto is absolute. If a relative moveto (m)
46
     * appears as the first element of the path, then it is treated as a pair of absolute coordinates. In this case,
47
     * subsequent pairs of coordinates are treated as relative even though the initial moveto is interpreted as an
48
     * absolute moveto.
49
     *
50
     * @link https://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
51
     *
52
     * @param float $x The absolute (relative) X coordinate for the end point of this path segment.
53
     * @param float $y The absolute (relative) Y coordinate for the end point of this path segment.
54
     * @param bool  $absolute
55
     *
56
     * @return $this
57
     */
58
    public function moveTo($x, $y, $absolute = true)
59
    {
60
        $this->checkFirstModifier();
61
62
        $modifier = $absolute ? 'M' : 'm';
63
        $this->d = "$modifier $x, $y";
64
65
        $this->boundingBox->addData($modifier, [$x, $y]);
66
67
        return $this;
68
    }
69
70
    /**
71
     * @param string $type
72
     */
73
    private function buildPath($type)
74
    {
75
        $params = array_slice(func_get_args(), 1);
76
        $this->boundingBox->addData($type, $params);
77
78
        $this->d .= " $type";
79
        foreach ($params as $key => $value) {
80
            if (is_array($value)) {
81
                $this->addArrayToPath($value);
82
            } else {
83
                if ($key % 2 !== 0 && !is_array($params[$key - 1])) {
84
                    $this->d .= ", $value";
85
                } else {
86
                    $this->d .= " $value";
87
                }
88
            }
89
        }
90
    }
91
92
    /**
93
     * Draw a line from the current point to the given (x,y) coordinate which becomes the new current point. L
94
     * (uppercase) indicates that absolute coordinates will follow; l (lowercase) indicates that relative coordinates
95
     * will follow. A number of coordinates pairs may be specified to draw a polyline. At the end of the command, the
96
     * new current point is set to the final set of coordinates provided.
97
     *
98
     * @link https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
99
     *
100
     * @param float $x The absolute (relative) X coordinate for the end point of this path segment.
101
     * @param float $y The absolute (relative) Y coordinate for the end point of this path segment.
102
     * @param bool  $absolute
103
     *
104
     * @return $this
105
     */
106
    public function lineTo($x, $y, $absolute = true)
107
    {
108
        $this->buildPath($absolute ? 'L' : 'l', $x, $y);
109
110
        return $this;
111
    }
112
113
    /**
114
     * Draws a horizontal line from the current point (cpx, cpy) to (x, cpy). H (uppercase) indicates that absolute
115
     * coordinates will follow; h (lowercase) indicates that relative coordinates will follow. Multiple x values can be
116
     * provided (although usually this doesn't make sense). At the end of the command, the new current point becomes
117
     * (x, cpy) for the final value of x.
118
     *
119
     * @link https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
120
     *
121
     * @param float $x The absolute (relative) X coordinate for the end point of this path segment.
122
     *
123
     * @param bool  $absolute
124
     *
125
     * @return $this
126
     */
127
    public function hLineTo($x, $absolute = true)
128
    {
129
        $this->buildPath($absolute ? 'H' : 'h', $x);
130
131
        return $this;
132
    }
133
134
    /**
135
     * Draws a vertical line from the current point (cpx, cpy) to (cpx, y). V (uppercase) indicates that absolute
136
     * coordinates will follow; v (lowercase) indicates that relative coordinates will follow. Multiple y values can be
137
     * provided (although usually this doesn't make sense). At the end of the command, the new current point becomes
138
     * (cpx, y) for the final value of y.
139
     *
140
     * @link https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
141
     *
142
     * @param float $y The absolute (relative) Y coordinate for the end point of this path segment.
143
     *
144
     * @param bool  $absolute
145
     *
146
     * @return $this
147
     */
148
    public function vLineTo($y, $absolute = true)
149
    {
150
        $this->buildPath($absolute ? 'V' : 'v', $y);
151
152
        return $this;
153
    }
154
155
    /**
156
     * Draws a cubic Bézier curve from the current point to (x,y) using (x1,y1) as the control point at the beginning
157
     * of the curve and (x2,y2) as the control point at the end of the curve.
158
     *
159
     * @link https://www.w3.org/TR/SVG11/paths.html#PathDataCurveCommands
160
     *
161
     * @param float $x1 The absolute (relative) X coordinate for the first control point.
162
     * @param float $y1 The absolute (relative) Y coordinate for the first control point.
163
     * @param float $x2 The absolute (relative) X coordinate for the second control point.
164
     * @param float $y2 The absolute (relative) Y coordinate for the second control point.
165
     * @param float $x  The absolute (relative) X coordinate for the end point of this path segment.
166
     * @param float $y  The absolute (relative) Y coordinate for the end point of this path segment.
167
     *
168
     * @param bool  $absolute
169
     *
170
     * @return $this
171
     */
172
    public function curveTo($x1, $y1, $x2, $y2, $x, $y, $absolute = true)
173
    {
174
        $this->buildPath($absolute ? 'C' : 'c', $x1, $y1, $x2, $y2, $x, $y);
175
176
        return $this;
177
    }
178
179
    /**
180
     * Draws a cubic Bézier curve from the current point to (x,y). The first control point is assumed to be the
181
     * reflection of the second control point on the previous command relative to the current point. (If there is no
182
     * previous command or if the previous command was not an C, c, S or s, assume the first control point is
183
     * coincident with the current point.) (x2,y2) is the second control point (i.e., the control point at the end of
184
     * the curve). S (uppercase) indicates that absolute coordinates will follow; s (lowercase) indicates that relative
185
     * coordinates will follow. Multiple sets of coordinates may be specified to draw a polybézier. At the end of the
186
     * command, the new current point becomes the final (x,y) coordinate pair used in the polybézier.
187
     *
188
     * @link https://www.w3.org/TR/SVG11/paths.html#PathDataCurveCommands
189
     *
190
     * @param float $x2 The absolute (relative) X coordinate for the second control point.
191
     * @param float $y2 The absolute (relative) Y coordinate for the second control point.
192
     * @param float $x  The absolute (relative) X coordinate for the end point of this path segment.
193
     * @param float $y  The absolute (relative) Y coordinate for the end point of this path segment.
194
     *
195
     * @param bool  $absolute
196
     *
197
     * @return $this
198
     */
199
    public function smoothCurveTo($x2, $y2, $x, $y, $absolute = true)
200
    {
201
        $this->buildPath($absolute ? 'S' : 's', $x2, $y2, $x, $y);
202
203
        return $this;
204
    }
205
206
    /**
207
     * Draws a quadratic Bézier curve from the current point to (x,y) using (x1,y1) as the control point. Q (uppercase)
208
     * indicates that absolute coordinates will follow; q (lowercase) indicates that relative coordinates will follow.
209
     * Multiple sets of coordinates may be specified to draw a polybézier. At the end of the command, the new current
210
     * point becomes the final (x,y) coordinate pair used in the polybézier.
211
     *
212
     * @link https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
213
     *
214
     * @param float $x1 The absolute (relative) X coordinate for the first control point.
215
     * @param float $y1 The absolute (relative) Y coordinate for the first control point.
216
     * @param float $x  The absolute (relative) X coordinate for the end point of this path segment.
217
     * @param float $y  The absolute (relative) Y coordinate for the end point of this path segment.
218
     *
219
     * @param bool  $absolute
220
     *
221
     * @return $this
222
     */
223
    public function quadraticCurveTo($x1, $y1, $x, $y, $absolute = true)
224
    {
225
        $this->buildPath($absolute ? 'Q' : 'q', $x1, $y1, $x, $y);
226
227
        return $this;
228
    }
229
230
    /**
231
     * Draws a quadratic Bézier curve from the current point to (x,y). The control point is assumed to be the
232
     * reflection of the control point on the previous command relative to the current point. (If there is no previous
233
     * command or if the previous command was not a Q, q, T or t, assume the control point is coincident with the
234
     * current point.) T (uppercase) indicates that absolute coordinates will follow; t (lowercase) indicates that
235
     * relative coordinates will follow. At the end of the command, the new current point becomes the final (x,y)
236
     * coordinate pair used in the polybézier.
237
     *
238
     * @link https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
239
     *
240
     * @param float $x The absolute (relative) X coordinate for the end point of this path segment.
241
     * @param float $y The absolute (relative) Y coordinate for the end point of this path segment.
242
     *
243
     * @param bool  $absolute
244
     *
245
     * @return $this
246
     */
247
    public function smoothQuadraticCurveTo($x, $y, $absolute = true)
248
    {
249
        $this->buildPath($absolute ? 'T' : 't', $x, $y);
250
251
        return $this;
252
    }
253
254
    /**
255
     * Draws an elliptical arc from the current point to (x, y). The size and orientation of the ellipse are defined by
256
     * two radii (rx, ry) and an x-axis-rotation, which indicates how the ellipse as a whole is rotated relative to the
257
     * current coordinate system. The center (cx, cy) of the ellipse is calculated automatically to satisfy the
258
     * constraints imposed by the other parameters. large-arc-flag and sweep-flag contribute to the automatic
259
     * calculations and help determine how the arc is drawn.
260
     *
261
     * @link https://www.w3.org/TR/SVG11/paths.html#PathDataEllipticalArcCommands
262
     *
263
     * @param float   $rx           The x-axis radius for the ellipse (i.e., r1).
264
     * @param float   $ry           The y-axis radius for the ellipse
265
     * @param float   $xRotation    The rotation angle in degrees for the ellipse's x-axis relative to the x-axis of
266
     *                              the user coordinate system.
267
     * @param boolean $largeArcFlag The value of the large-arc-flag parameter.
268
     * @param boolean $sweepFlag    The value of the sweep-flag parameter.
269
     * @param float   $x            The absolute (relative) X coordinate for the end point of this path segment.
270
     * @param float   $y            The absolute (relative) Y coordinate for the end point of this path segment.
271
     * @param bool    $absolute
272
     *
273
     * @return $this
274
     */
275
    public function arcTo($rx, $ry, $xRotation, $largeArcFlag, $sweepFlag, $x, $y, $absolute = true)
276
    {
277
        $this->buildPath($absolute ? 'A' : 'a', [$rx, $ry], $xRotation, [$largeArcFlag ? 1 : 0, $sweepFlag ? 1 : 0], [$x, $y]);
278
279
        return $this;
280
    }
281
282
    /**
283
     * Close the current subpath by drawing a straight line from the current point to current subpath's initial point.
284
     * Since the Z and z commands take no parameters, they have an identical effect.
285
     *
286
     * @link https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
287
     *
288
     * @param bool $absolute
289
     */
290
    public function closePath($absolute = true)
291
    {
292
        $this->buildPath($absolute ? 'Z' : 'z');
293
    }
294
295
    public function getName()
296
    {
297
        return 'path';
298
    }
299
300
    public function getBoundingBox()
301
    {
302
        return $this->boundingBox->getBox();
303
    }
304
305
    protected function getCenterX()
306
    {
307
        // TODO: Implement getCenterX() method.
308
    }
309
310
    protected function getCenterY()
311
    {
312
        // TODO: Implement getCenterY() method.
313
    }
314
315
    /**
316
     * @param $value
317
     */
318
    private function addArrayToPath(array $value)
319
    {
320
        foreach ($value as $item) {
321
            $this->d .= " $item,";
322
        }
323
        $this->d = rtrim($this->d, ',');
324
    }
325
326
    /**
327
     *
328
     */
329
    private function checkFirstModifier()
330
    {
331
        if ($this->d !== null) {
332
            throw new \BadMethodCallException("First modifier for path must be: M or m. Youb");
333
        }
334
    }
335
}