Bezier::quadraticBBox()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 22
cts 22
cp 1
rs 9.36
c 0
b 0
f 0
cc 1
nc 1
nop 6
crap 1
1
<?php
2
namespace nstdio\svg\util;
3
4
/**
5
 * Class Bezier
6
 *
7
 * @package nstdio\svg\util
8
 * @author  Edgar Asatryan <[email protected]>
9
 */
10
class Bezier
11
{
12
    const EPSILON = 0.00001;
13
14 5
    public static function quadraticBBox($p0x, $p0y, $p1x, $p1y, $p2x, $p2y)
15
    {
16 5
        $devx = $p0x + $p2x - 2 * $p1x;
17 5
        $devy = $p0y + $p2y - 2 * $p1y;
18
19 5
        self::avoidDivisionByZero($devy);
20 5
        self::avoidDivisionByZero($devx);
21
22 5
        $tx = ($p0x - $p1x) / $devx;
23 5
        $ty = ($p0y - $p1y) / $devy;
24
25 5
        self::checkBezierInterval($tx);
26 5
        self::checkBezierInterval($ty);
27
28 5
        $txByTX = self::getQuadraticValue($tx, $p0x, $p1x, $p2x);
29 5
        $tyByTX = self::getQuadraticValue($tx, $p0y, $p1y, $p2y);
30
31 5
        $txByTY = self::getQuadraticValue($ty, $p0x, $p1x, $p2x);
32 5
        $tyByTY = self::getQuadraticValue($ty, $p0y, $p1y, $p2y);
33
34 5
        $x1 = min($txByTX, $p0x, $p2x, $txByTY);
35 5
        $y1 = min($tyByTX, $p0y, $p2y, $tyByTY);
36
37
38 5
        $x2 = max($txByTX, $p0x, $p2x, $txByTY);
39 5
        $y2 = max($tyByTX, $p0y, $p2y, $tyByTY);
40
41
42
        return [
43 5
            min($x2, $x1),
44 5
            min($y2, $y1),
45 5
            max($x2, $x1),
46 5
            max($y2, $y1),
47 5
        ];
48
    }
49
50 7
    public static function cubicBBox($p0x, $p0y, $p1x, $p1y, $p2x, $p2y, $p3x, $p3y)
51
    {
52 7
        if (abs($p3y - $p0y) === 0) {
53 1
            $p3y += self::EPSILON;
54 1
        }
55
56 7
        $ax = $p3x - $p0x + 3 * ($p1x - $p2x);
57 7
        $bx = 2 * ($p0x - 2 * $p1x + $p2x);
58 7
        $cx = $p1x - $p0x;
59
60 7
        $ay = $p3y - $p0y + 3 * ($p1y - $p2y);
61 7
        $by = 2 * ($p0y - 2 * $p1y + $p2y);
62 7
        $cy = $p1y - $p0y;
63
64 7
        $txRoots = self::getRoots($ax, $bx, $cx);
65 7
        $tyRoots = self::getRoots($ay, $by, $cy);
66
67 7
        $tv0x = self::getCubicValue(0, $p0x, $p1x, $p2x, $p3x);
68 7
        $tv1x = self::getCubicValue($txRoots[0], $p0x, $p1x, $p2x, $p3x);
69 7
        $tv2x = self::getCubicValue($txRoots[1], $p0x, $p1x, $p2x, $p3x);
70 7
        $tv3x = self::getCubicValue(1, $p0x, $p1x, $p2x, $p3x);
71 7
        $tv4x = self::getCubicValue($tyRoots[0], $p0x, $p1x, $p2x, $p3x);
72 7
        $tv5x = self::getCubicValue($tyRoots[1], $p0x, $p1x, $p2x, $p3x);
73
74 7
        $tv0y = self::getCubicValue(0, $p0y, $p1y, $p2y, $p3y);
75 7
        $tv1y = self::getCubicValue($tyRoots[0], $p0y, $p1y, $p2y, $p3y);
76 7
        $tv2y = self::getCubicValue($tyRoots[1], $p0y, $p1y, $p2y, $p3y);
77 7
        $tv3y = self::getCubicValue(1, $p0y, $p1y, $p2y, $p3y);
78 7
        $tv4y = self::getCubicValue($txRoots[0], $p0y, $p1y, $p2y, $p3y);
79 7
        $tv5y = self::getCubicValue($txRoots[1], $p0y, $p1y, $p2y, $p3y);
80
81
82 7
        $x1 = min($tv0x, $tv1x, $tv2x, $tv3x, $p0x, $p3x, $tv4x, $tv5x);
83 7
        $y1 = min($tv0y, $tv1y, $tv2y, $tv3y, $p0y, $p3y, $tv4y, $tv5y);
84
85 7
        $x2 = max($tv0x, $tv1x, $tv2x, $tv3x, $p0x, $p3x, $tv4x, $tv5x);
86 7
        $y2 = max($tv0y, $tv1y, $tv2y, $tv3y, $p0y, $p3y, $tv4y, $tv5y);
87
88
89
        return [
90 7
            min($x2, $x1),
91 7
            min($y2, $y1),
92 7
            max($x2, $x1),
93 7
            max($y2, $y1),
94 7
        ];
95
96
    }
97
98 7
    public static function getRoots($a, $b, $c)
99
    {
100 7
        $dis = $b * $b - 4 * $a * $c;
101 7
        if ($dis < 0) {
102 2
            return null;
103
        }
104 7
        self::avoidDivisionByZero($a);
105
106 7
        $disSqrt = sqrt($dis);
107 7
        $root1 = (-$b + $disSqrt) / (2 * $a);
108 7
        $root2 = (-$b - $disSqrt) / (2 * $a);
109
110 7
        self::checkBezierInterval($root1);
111 7
        self::checkBezierInterval($root2);
112
113 7
        return [$root1, $root2];
114
    }
115
116 7
    private static function getCubicValue($t, $p0, $p1, $p2, $p3)
117
    {
118 7
        $omt = 1 - $t;
119 7
        $value = $p0 * $omt * $omt * $omt +
120 7
            3 * $p1 * $t * $omt * $omt +
121 7
            3 * $p2 * $t * $t * $omt +
122 7
            $p3 * $t * $t * $t;
123
124 7
        return $value;
125
    }
126
127
    /**
128
     * @param $value
129
     */
130 11
    private static function avoidDivisionByZero(&$value)
131
    {
132 11
        if ($value === 0) {
133
            $value = self::EPSILON;
134
        }
135 11
    }
136
137
    /**
138
     * @param $t
139
     */
140 11
    private static function checkBezierInterval(&$t)
141
    {
142 11
        if ($t > 1 || $t < 0) {
143 9
            $t = 0;
144 9
        }
145 11
    }
146
147
    /**
148
     * @param $t
149
     * @param $p0x
150
     * @param $p1x
151
     * @param $p2x
152
     *
153
     * @return mixed
154
     */
155 5
    private static function getQuadraticValue($t, $p0x, $p1x, $p2x)
156
    {
157 5
        $omt = 1 - $t;
158
159 5
        return $p0x * $omt * $omt + 2 * $t * $p1x * $omt + $p2x * $t * $t;
160
    }
161
}
162