Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
LinearInterpolation
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
2 / 2
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
3
 interpolate
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
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 */
13declare(strict_types=1);
14
15namespace phpOMS\Math\Numerics\Interpolation;
16
17use 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 */
27final 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}