Passed
Push — master ( fefee4...ec3bb4 )
by Doug
39:04
created

GTXGrid::getRecord()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
nc 1
nop 2
dl 0
loc 17
ccs 13
cts 13
cp 1
crap 1
rs 9.8666
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 PHPCoord\UnitOfMeasure\Length\Metre;
12
use SplFileObject;
13
14
use function in_array;
15
use function substr;
16
use function unpack;
17
18
/**
19
 * @see https://vdatum.noaa.gov/docs/gtx_info.html for documentation
20
 */
21
class GTXGrid extends GeographicGeoidHeightGrid
22
{
23
    use BilinearInterpolation;
24
25
    private int $headerLength;
26
    private string $shiftDataType;
27
28 10
    public function __construct($filename)
29
    {
30 10
        $this->gridFile = new SplFileObject($filename);
31 10
        $this->storageOrder = self::STORAGE_ORDER_INCREASING_LONGITUDE_INCREASING_LATIITUDE;
32
33 10
        $header = $this->getHeader();
34 10
        $this->startX = $header['xlonsw'];
35 10
        $this->startY = $header['xlatsw'];
36 10
        $this->numberOfColumns = $header['nlon'];
37 10
        $this->numberOfRows = $header['nlat'];
38 10
        $this->columnGridInterval = $header['dlon'];
39 10
        $this->rowGridInterval = $header['dlat'];
40
41 10
        if ($this->startX > 180) { // normalise if necessary
42 2
            $this->startX -= 360;
43
        }
44
    }
45
46
    /**
47
     * @return Metre[]
48
     */
49 10
    public function getValues($x, $y): array
50
    {
51 10
        $shift = $this->interpolate($x, $y)[0];
52
53
        // These are in millimeters for some reason... :/
54 10
        if (in_array($this->gridFile->getBasename(), ['vertconc.gtx', 'vertcone.gtx', 'vertconw.gtx'], true)) {
55 1
            $shift /= 1000;
56
        }
57
58 10
        return [new Metre($shift)];
59
    }
60
61 10
    private function getRecord(int $longitudeIndex, int $latitudeIndex): GridValues
0 ignored issues
show
Unused Code introduced by
The method getRecord() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
62
    {
63 10
        $recordId = match ($this->storageOrder) {
64 10
            self::STORAGE_ORDER_INCREASING_LATITUDE_INCREASING_LONGITUDE => $longitudeIndex * $this->numberOfRows + $latitudeIndex,
65 10
            self::STORAGE_ORDER_INCREASING_LONGITUDE_DECREASING_LATIITUDE => ($this->numberOfRows - $latitudeIndex - 1) * $this->numberOfColumns + $longitudeIndex,
66 10
            self::STORAGE_ORDER_INCREASING_LONGITUDE_INCREASING_LATIITUDE => $latitudeIndex * $this->numberOfColumns + $longitudeIndex,
67
        };
68
69 10
        $offset = $this->headerLength + $recordId * 4;
70 10
        $this->gridFile->fseek($offset);
71 10
        $rawRow = $this->gridFile->fread(4);
72 10
        $data = unpack("{$this->shiftDataType}shift", $rawRow);
73
74 10
        return new GridValues(
75 10
            $longitudeIndex * $this->columnGridInterval + $this->startX,
76 10
            $latitudeIndex * $this->rowGridInterval + $this->startY,
77 10
            [$data['shift']]
78
        );
79
    }
80
81 10
    private function getHeader(): array
82
    {
83 10
        $this->gridFile->fseek(0);
84 10
        $rawHeader = $this->gridFile->fread(44);
85 10
        $ikind = substr($rawHeader, 40, 4);
86 10
        if (unpack('Nikind', $ikind)['ikind'] === 1) { // big endian
87
            $this->headerLength = 44;
88
            $this->shiftDataType = 'G';
89
            $data = unpack('Exlatsw/Exlonsw/Edlat/Edlon/Nnlat/Nnlon', $rawHeader);
90 10
        } elseif (unpack('Vikind', $ikind)['ikind'] === 1) { // little endian
91 1
            $this->headerLength = 44;
92 1
            $this->shiftDataType = 'g';
93 1
            $data = unpack('exlatsw/exlonsw/edlat/edlon/Vnlat/Vnlon', $rawHeader);
94
        } else { // not all files (e.g. NZ) have this endian check column, assume big endian
95 9
            $this->headerLength = 40;
96 9
            $this->shiftDataType = 'G';
97 9
            $data = unpack('Exlatsw/Exlonsw/Edlat/Edlon/Nnlat/Nnlon', $rawHeader);
98
        }
99
100 10
        return $data;
101
    }
102
}
103