Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
30 / 30 |
|
100.00% |
2 / 2 |
CRAP | |
100.00% |
1 / 1 |
LinearInterpolation | |
100.00% |
30 / 30 |
|
100.00% |
2 / 2 |
8 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 | |||
interpolate | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
5 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Math\Numerics\Interpolation |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Math\Numerics\Interpolation; |
16 | |
17 | use phpOMS\Math\Matrix\Vector; |
18 | |
19 | /** |
20 | * Linear spline interpolation. |
21 | * |
22 | * @package phpOMS\Math\Numerics\Interpolation |
23 | * @license OMS License 2.0 |
24 | * @link https://jingga.app |
25 | * @since 1.0.0 |
26 | */ |
27 | final class LinearInterpolation implements InterpolationInterface |
28 | { |
29 | /** |
30 | * Points for spline interpolation |
31 | * |
32 | * @var array<int, array{x:int|float, y:int|float}> |
33 | * @since 1.0.0 |
34 | */ |
35 | private array $points = []; |
36 | |
37 | /** |
38 | * Parameter a of cubic spline |
39 | * |
40 | * @var Vector |
41 | * @since 1.0.0 |
42 | */ |
43 | private Vector $solveA; |
44 | |
45 | /** |
46 | * Parameter b of cubic spline |
47 | * |
48 | * @var Vector |
49 | * @since 1.0.0 |
50 | */ |
51 | private Vector $solveB; |
52 | |
53 | /** |
54 | * Parameter c of cubic spline |
55 | * |
56 | * @var Vector |
57 | * @since 1.0.0 |
58 | */ |
59 | private Vector $solveC; |
60 | |
61 | /** |
62 | * Constructor. |
63 | * |
64 | * @param array<int, array{x:int|float, y:int|float}> $points Points to create the interpolation with |
65 | * |
66 | * @since 1.0.0 |
67 | */ |
68 | public function __construct(array $points) { |
69 | $this->points = $points; |
70 | |
71 | $n = \count($this->points); |
72 | |
73 | $this->solveA = new Vector($n); |
74 | $this->solveB = new Vector($n); |
75 | $this->solveC = new Vector($n); |
76 | |
77 | for ($i = 0; $i < $n - 1; ++$i) { |
78 | $this->solveA->setV($i, 0.0); |
79 | $this->solveB->setV($i, 0.0); |
80 | $this->solveC->setV($i, ($this->points[$i + 1]['y'] - $this->points[$i]['y']) / ($this->points[$i + 1]['x'] - $this->points[$i]['x'])); |
81 | } |
82 | |
83 | for ($i = 0; $i < $n - 1; ++$i) { |
84 | $this->solveA->setV($i, 1.0 / 3.0 * ($this->solveB->getV($i + 1) - $this->solveB->getV($i)) / ($this->points[$i + 1]['x'] - $this->points[$i]['x'])); |
85 | $this->solveC->setV($i, |
86 | ($this->points[$i + 1]['y'] - $this->points[$i]['y']) / ($this->points[$i + 1]['x'] - $this->points[$i]['x']) |
87 | - 1.0 / 3.0 * (2 * $this->solveB->getV($i) + $this->solveB->getV($i + 1)) * ($this->points[$i + 1]['x'] - $this->points[$i]['x'])); |
88 | } |
89 | |
90 | $h = $this->points[$n - 1]['x'] - $this->points[$n - 2]['x']; |
91 | |
92 | $this->solveA->setV($n - 1, 0.0); |
93 | $this->solveC->setV($n - 1, 3.0 * $this->solveA->getV($n - 2) * $h ** 2 + 2.0 * $this->solveB->getV($n - 2) * $h + $this->solveC->getV($n - 2)); |
94 | } |
95 | |
96 | /** |
97 | * {@inheritdoc} |
98 | */ |
99 | public function interpolate(int | float $x) : float |
100 | { |
101 | $n = \count($this->points); |
102 | $xPos = $n - 1; |
103 | |
104 | foreach ($this->points as $key => $point) { |
105 | if ($x <= $point['x']) { |
106 | $xPos = $key; |
107 | |
108 | break; |
109 | } |
110 | } |
111 | |
112 | $xPos = \max($xPos - 1, 0); |
113 | $h = $x - $this->points[$xPos]['x']; |
114 | |
115 | if ($x < $this->points[0]['x']) { |
116 | return ($this->solveB->getV(0) * $h + $this->solveC->getV(0)) * $h + $this->points[0]['y']; |
117 | } elseif ($x > $this->points[$n - 1]['x']) { |
118 | return ($this->solveB->getV($n - 1) * $h + $this->solveC->getV($n - 1) * $h + $this->points[$n - 1]['y']); |
119 | } |
120 | |
121 | return (($this->solveA->getV($xPos) * $h + $this->solveB->getV($xPos)) * $h + $this->solveC->getV($xPos)) * $h + $this->points[$xPos]['y']; |
122 | } |
123 | } |