Passed
Push — master ( fd93b5...48e916 )
by Doug
40:26 queued 29:39
created

BilinearInterpolation::interpolate()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 8
nop 2
dl 0
loc 21
ccs 11
cts 11
cp 1
crap 4
rs 9.9332
c 0
b 0
f 0
1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord\CoordinateOperation;
10
11
use function assert;
12
use function count;
13
use function min;
14
15
trait BilinearInterpolation
16
{
17
    protected float $startX;
18
    protected float $endX;
19
    protected float $startY;
20
    protected float $endY;
21
    protected int $numberOfColumns;
22
    protected int $numberOfRows;
23
    protected float $columnGridInterval;
24
    protected float $rowGridInterval;
25
26 20
    public function interpolate(
27
        float $x,
28
        float $y
29
    ): array {
30 20
        $corners = $this->getCorners($x, $y);
31
32 20
        $dx = $corners['lowerRight']->getX() === $corners['lowerLeft']->getX() ? 0 : (($x - $corners['lowerLeft']->getX()) / $this->columnGridInterval);
33 20
        $dy = $corners['upperLeft']->getY() === $corners['lowerLeft']->getY() ? 0 : (($y - $corners['lowerLeft']->getY()) / $this->rowGridInterval);
34
35 20
        $interpolations = [];
36 20
        for ($i = 0, $count = count($corners['lowerLeft']->getValues()); $i < $count; ++$i) {
37
            //Interpolate value at lower row
38 20
            $y0 = $this->interpolateLinear($dx, $corners['lowerLeft']->getValues()[$i], $corners['lowerRight']->getValues()[$i]);
39
            //Interpolate value at upper row
40 20
            $y1 = $this->interpolateLinear($dx, $corners['upperLeft']->getValues()[$i], $corners['upperRight']->getValues()[$i]);
41
            //Interpolate between rows
42 20
            $xy = $this->interpolateLinear($dy, $y0, $y1);
43 20
            $interpolations[] = $xy;
44
        }
45
46 20
        return $interpolations;
47
    }
48
49
    /**
50
     * Linear interpolation at point p, where p is between 0 and 1.
51
     */
52 20
    private function interpolateLinear(float $p, float $valueAt0, float $valueAt1): float
53
    {
54 20
        assert($p >= 0 && $p <= 1);
55
56 20
        return $valueAt0 * (1 - $p) + $valueAt1 * $p;
57
    }
58
59
    /**
60
     * @return GridValues[]
61
     */
62 20
    private function getCorners(float $x, float $y): array
63
    {
64 20
        $xIndex = (int) (($x - $this->startX) / $this->columnGridInterval);
65 20
        $yIndex = (int) (($y - $this->startY) / $this->rowGridInterval);
66 20
        $xIndexPlus1 = min($xIndex + 1, $this->numberOfColumns - 1);
67 20
        $yIndexPlus1 = min($yIndex + 1, $this->numberOfRows - 1);
68
69
        return [
70 20
            'lowerLeft' => $this->getRecord($xIndex, $yIndex),
0 ignored issues
show
Bug introduced by
It seems like getRecord() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

70
            'lowerLeft' => $this->/** @scrutinizer ignore-call */ getRecord($xIndex, $yIndex),
Loading history...
71 20
            'lowerRight' => $this->getRecord($xIndexPlus1, $yIndex),
72 20
            'upperLeft' => $this->getRecord($xIndex, $yIndexPlus1),
73 20
            'upperRight' => $this->getRecord($xIndexPlus1, $yIndexPlus1),
74
        ];
75
    }
76
}
77