Passed
Push — master ( 705a37...2b8bad )
by Doug
17:25 queued 45s
created

BYNHeightGrid::getValues()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
c 1
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 in_array;
13
use PHPCoord\UnitOfMeasure\Angle\ArcSecond;
14
use PHPCoord\UnitOfMeasure\Length\Metre;
15
use SplFileObject;
16
use function unpack;
17
18
class BYNHeightGrid extends GeographicGeoidHeightGrid
19
{
20
    use BiquadraticInterpolation;
21
22
    private string $shortFormatChar = 'v';
23
    private string $longFormatChar = 'V';
24
    private string $doubleFormatChar = 'e';
25
    private string $floatFormatChar = 'g';
26
    private int $dataSize;
27
    private float $conversionFactor;
28
29 3
    public function __construct($filename)
30
    {
31 3
        $this->storageOrder = self::STORAGE_ORDER_INCREASING_LONGITUDE_DECREASING_LATIITUDE;
32 3
        $this->gridFile = new SplFileObject($filename);
33
34 3
        $this->gridFile->fseek(0);
35 3
        $rawData = $this->gridFile->fread(80);
36 3
        if (unpack('vByteOrder', $rawData, 50)['ByteOrder'] === 1) {
37
            $this->shortFormatChar = 'n';
38
            $this->longFormatChar = 'N';
39
            $this->doubleFormatChar = 'E';
40
            $this->floatFormatChar = 'G';
41
        }
42
43 3
        $data = unpack("{$this->longFormatChar}SOUTH/{$this->longFormatChar}NORTH/{$this->longFormatChar}WEST/{$this->longFormatChar}EAST/{$this->shortFormatChar}DLAT/{$this->shortFormatChar}DLON/{$this->shortFormatChar}GLOBAL/{$this->shortFormatChar}TYPE/{$this->doubleFormatChar}FACTOR/{$this->shortFormatChar}SIZEOF/x4/{$this->shortFormatChar}DATA/{$this->shortFormatChar}SUBTYPE/{$this->shortFormatChar}DATUM/{$this->shortFormatChar}ELLIPSOID/{$this->shortFormatChar}BYTEORDER/{$this->shortFormatChar}SCALE/{$this->doubleFormatChar}WO/{$this->doubleFormatChar}GM/{$this->shortFormatChar}TIDESYSTEM/{$this->shortFormatChar}REFREALISATION/{$this->floatFormatChar}EPOCH/{$this->shortFormatChar}PTTYPE/x2", $rawData);
44
45 3
        foreach ($data as $key => $value) {
46 3
            if (in_array($key, ['SOUTH', 'EAST', 'NORTH', 'WEST']) && $value > 2147483647) {
47 3
                $data[$key] -= 4294967295;
48
            }
49
        }
50
51 3
        assert($data['DATA'] === 0); // actual values, not errors
52 3
        assert($data['TYPE'] === 1); // ellipsoid separation
53 3
        assert($data['SIZEOF'] === 2 || $data['SIZEOF'] === 4); // sensible data type
54
55 3
        $this->startX = (new ArcSecond($data['WEST']))->asDegrees()->getValue();
56 3
        $this->startY = (new ArcSecond($data['SOUTH']))->asDegrees()->getValue();
57 3
        $this->endX = (new ArcSecond($data['EAST']))->asDegrees()->getValue();
58 3
        $this->endY = (new ArcSecond($data['NORTH']))->asDegrees()->getValue();
59 3
        $this->columnGridInterval = (new ArcSecond($data['DLON']))->asDegrees()->getValue();
60 3
        $this->rowGridInterval = (new ArcSecond($data['DLAT']))->asDegrees()->getValue();
61 3
        $this->numberOfColumns = (int) (string) (($this->endX - $this->startX) / $this->columnGridInterval) + 1;
62 3
        $this->numberOfRows = (int) (string) (($this->endY - $this->startY) / $this->rowGridInterval) + 1;
63 3
        $this->dataSize = $data['SIZEOF'];
64 3
        $this->conversionFactor = $data['FACTOR'];
65
    }
66
67
    /**
68
     * @return Metre[]
69
     */
70 3
    public function getValues($x, $y): array
71
    {
72 3
        $shift = $this->interpolate($x, $y)[0];
73
74 3
        return [new Metre($shift)];
75
    }
76
77 3
    protected function getRecord(int $longitudeIndex, int $latitudeIndex): GridValues
78
    {
79 3
        $recordId = ($this->numberOfRows - $latitudeIndex - 1) * $this->numberOfColumns + $longitudeIndex;
80
81 3
        $offset = 80 + $recordId * $this->dataSize;
82 3
        $this->gridFile->fseek($offset);
83 3
        $rawRow = $this->gridFile->fread($this->dataSize);
84 3
        $dataType = $this->dataSize === 2 ? $this->shortFormatChar : $this->longFormatChar;
85 3
        $shift = unpack("{$dataType}shift", $rawRow)['shift'];
86 3
        if ($this->dataSize === 4 && $shift > 2147483647) {
87 3
            $shift -= 4294967295;
88
        } elseif ($this->dataSize === 2 && $shift > 32767) {
89
            $shift -= 65535;
90
        }
91 3
        $shift = $shift / $this->conversionFactor;
92
93 3
        return new GridValues(
94 3
            $longitudeIndex * $this->columnGridInterval + $this->startX,
95 3
            $latitudeIndex * $this->rowGridInterval + $this->startY,
96
            [$shift]
97
        );
98
    }
99
}
100