Completed
Branch master (32b148)
by Edgar
03:11
created

Bezier   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 0

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 127
rs 10
wmc 19
lcom 0
cbo 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
C quadraticBBox() 0 40 7
B cubicBBox() 0 38 1
C getRoots() 0 25 8
A getCubicValue() 0 16 3
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
    public static function quadraticBBox($p0x, $p0y, $p1x, $p1y, $p2x, $p2y)
15
    {
16
        $devx = $p0x + $p2x - 2 * $p1x;
17
        $devy = $p0y + $p2y - 2 * $p1y;
18
        if ($devy === 0) {
19
            $devy = self::EPSILON;
20
        }
21
        if ($devx === 0) {
22
            $devx = self::EPSILON;
23
        }
24
        $tx = ($p0x - $p1x) / $devx;
25
        $ty = ($p0y - $p1y) / $devy;
26
27
        if ($tx > 1 || $tx < 0) {
28
            $tx = 0;
29
        }
30
        if ($ty > 1 || $ty < 0) {
31
            $ty = 0;
32
        }
33
        $txByTX = $p0x * pow(1 - $tx, 2) + 2 * $tx * $p1x * (1 - $tx) + $p2x * $tx * $tx;
34
        $tyByTX = $p0y * pow(1 - $tx, 2) + 2 * $tx * $p1y * (1 - $tx) + $p2y * $tx * $tx;
35
36
        $txByTY = $p0x * pow(1 - $ty, 2) + 2 * $ty * $p1x * (1 - $ty) + $p2x * $ty * $ty;
37
        $tyByTY = $p0y * pow(1 - $ty, 2) + 2 * $ty * $p1y * (1 - $ty) + $p2y * $ty * $ty;
38
39
        $x1 = min($txByTX, $p0x, $p2x, $txByTY);
40
        $y1 = min($tyByTX, $p0y, $p2y, $tyByTY);
41
42
43
        $x2 = max($txByTX, $p0x, $p2x, $txByTY);
44
        $y2 = max($tyByTX, $p0y, $p2y, $tyByTY);
45
46
47
        return [
48
            'width'  => $x2 - min($x2, $x1),
49
            'height' => max($y2, $y1) - min($y2, $y1),
50
            'x'      => min($x2, $x1),
51
            'y'      => min($y2, $y1),
52
        ];
53
    }
54
55
    public static function cubicBBox($p0x, $p0y, $p1x, $p1y, $p2x, $p2y, $p3x, $p3y)
56
    {
57
        $ax = $p3x - $p0x + 3 * ($p1x - $p2x);
58
        $bx = 2 * ($p0x - 2 * $p1x + $p2x);
59
        $cx = $p1x - $p0x;
60
61
        $ay = $p3y - $p0y + 3 * ($p1y - $p2y);
62
        $by = 2 * ($p0y - 2 * $p1y + $p2y);
63
        $cy = $p1y - $p0y;
64
65
        $txRoots = self::getRoots($ax, $bx, $cx);
66
        $tyRoots = self::getRoots($ay, $by, $cy);
67
68
        $tv0x = self::getCubicValue(0, $p0x, $p1x, $p2x, $p3x);
69
        $tv1x = self::getCubicValue($txRoots[0], $p0x, $p1x, $p2x, $p3x);
70
        $tv2x = self::getCubicValue($txRoots[1], $p0x, $p1x, $p2x, $p3x);
71
        $tv3x = self::getCubicValue(1, $p0x, $p1x, $p2x, $p3x);
72
73
        $tv0y = self::getCubicValue(0, $p0y, $p1y, $p2y, $p3y);
74
        $tv1y = self::getCubicValue($tyRoots[0], $p0y, $p1y, $p2y, $p3y);
75
        $tv2y = self::getCubicValue($tyRoots[1], $p0y, $p1y, $p2y, $p3y);
76
        $tv3y = self::getCubicValue(1, $p0y, $p1y, $p2y, $p3y);
77
78
79
        $x1 = min($tv0x, $tv1x, $tv2x, $tv3x, $p0x, $p3x);
80
        $y1 = min($tv0y, $tv1y, $tv2y, $tv3y, $p0y, $p3y);
81
82
        $x2 = max($tv0x, $tv1x, $tv2x, $tv3x, $p0x, $p3x);
83
        $y2 = max($tv0y, $tv1y, $tv2y, $tv3y, $p0y, $p3y);
84
85
        return [
86
            'width'  => $x2 - min($x2, $x1),
87
            'height' => max($y2, $y1) - min($y2, $y1),
88
            'x'      => min($x2, $x1),
89
            'y'      => min($y2, $y1),
90
        ];
91
92
    }
93
94
    public static function getRoots($a, $b, $c)
95
    {
96
        $dis = $b * $b - 4 * $a * $c;
97
        if ($dis < 0) {
98
            return null;
99
        }
100
        if ($a === 0) {
101
            $a = self::EPSILON;
102
        }
103
        $disSqrt = sqrt($dis);
104
        if ($disSqrt === 0) {
105
            $root1 = $root2 = -$b / (2 * $a);
106
        } else {
107
            $root1 = (-$b + $disSqrt) / (2 * $a);
108
            $root2 = (-$b - $disSqrt) / (2 * $a);
109
        }
110
        if ($root1 > 1 || $root1 < 0) {
111
            $root1 = 0;
112
        }
113
        if ($root2 > 1 || $root2 < 0) {
114
            $root2 = 0;
115
        }
116
117
        return [$root1, $root2];
118
    }
119
120
    private static function getCubicValue($t, $p0, $p1, $p2, $p3)
121
    {
122
        if ($t === 1) {
123
            return $p3;
124
        }
125
        if ($t === 0) {
126
            return $p0;
127
        }
128
        $omt = 1 - $t;
129
        $value = $p0 * $omt * $omt *$omt +
130
            3 * $p1 * $t * $omt * $omt +
131
            3 * $p2 * $t * $t * $omt +
132
            $p3 * $t * $t * $t;
133
134
        return $value;
135
    }
136
}