Passed
Push — master ( 344e29...cbaf3e )
by Doug
38:02
created

KMSGrid::__construct()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 65
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 41
CRAP Score 7.0629

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 46
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 65
ccs 41
cts 46
cp 0.8913
crap 7.0629
rs 8.2448

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
use SplFixedArray;
14
15
use function assert;
16
use function explode;
17
use function intdiv;
18
use function preg_replace;
19
use function preg_split;
20
use function trim;
21
use function unpack;
22
23
/**
24
 * @see https://github.com/Kortforsyningen/kmsgrid/blob/master/kmsgrid.py for documentation
25
 */
26
class KMSGrid extends GeographicGeoidHeightGrid
27
{
28
    use BilinearInterpolation;
29
30
    private int $binaryHeaderLength = 64;
31
    private bool $isBinary;
32
    private string $integerFormatChar = 'V';
33
    private string $doubleFormatChar = 'e';
34
    private string $floatFormatChar = 'g';
35
    private SplFixedArray $textData;
36
37 3
    public function __construct($filename)
38
    {
39 3
        $this->gridFile = new SplFileObject($filename);
40 3
        $this->storageOrder = self::STORAGE_ORDER_INCREASING_LONGITUDE_DECREASING_LATIITUDE;
41
42 3
        $firstChar = $this->gridFile->fread(1);
43
44 3
        if ($firstChar === ' ') {
45 1
            $this->isBinary = false;
46
47 1
            $header = preg_split('/\s+/', trim($this->gridFile->fgets()));
48
49 1
            $this->startX = (float) $header[2];
50 1
            $this->startY = (float) $header[0];
51 1
            $this->endX = (float) $header[3];
52 1
            $this->endY = (float) $header[1];
53 1
            $this->columnGridInterval = (float) $header[5];
54 1
            $this->rowGridInterval = (float) $header[4];
55 1
            $this->numberOfColumns = (int) (string) (($this->endX - $this->startX) / $this->columnGridInterval) + 1;
56 1
            $this->numberOfRows = (int) (string) (($this->endY - $this->startY) / $this->rowGridInterval) + 1;
57
58 1
            $this->textData = new SplFixedArray($this->numberOfColumns * $this->numberOfRows);
59 1
            $index = 0;
60 1
            while (!$this->gridFile->eof()) {
61 1
                $rawData = trim($this->gridFile->fgets());
62 1
                if ($rawData) {
63 1
                    $values = explode(' ', trim(preg_replace('/\s+/', ' ', $rawData)));
64 1
                    foreach ($values as $value) {
65 1
                        $this->textData[$index] = (float) $value;
66 1
                        ++$index;
67
                    }
68
                }
69
            }
70
        } else {
71 2
            $this->isBinary = true;
72
73 2
            $this->gridFile->fseek(0);
74 2
            $rawHeader = $this->gridFile->fread($this->binaryHeaderLength);
75 2
            $icode = unpack("{$this->integerFormatChar}ICODE", $rawHeader)['ICODE'];
76
77 2
            if ($icode !== 777) {
78
                $this->integerFormatChar = 'N';
79
                $this->doubleFormatChar = 'E';
80
                $this->floatFormatChar = 'G';
81
                $icode = unpack("{$this->integerFormatChar}ICODE", $rawHeader)['ICODE'];
82
            }
83
84 2
            assert($icode === 777);
85
86 2
            $header = unpack("{$this->integerFormatChar}ICODE/{$this->doubleFormatChar}BMIN/{$this->doubleFormatChar}BMAX/{$this->doubleFormatChar}LMIN/{$this->doubleFormatChar}LMAX/{$this->doubleFormatChar}DB/{$this->doubleFormatChar}DL/{$this->integerFormatChar}DATUM/{$this->integerFormatChar}CSTM/{$this->integerFormatChar}MODE", $rawHeader);
87 2
            $this->startX = $header['LMIN'];
88 2
            $this->startY = $header['BMIN'];
89 2
            $this->endX = $header['LMAX'];
90 2
            $this->endY = $header['BMAX'];
91 2
            $this->columnGridInterval = $header['DL'];
92 2
            $this->rowGridInterval = $header['DB'];
93 2
            $this->numberOfColumns = (int) (string) (($this->endX - $this->startX) / $this->columnGridInterval) + 1;
94 2
            $this->numberOfRows = (int) (string) (($this->endY - $this->startY) / $this->rowGridInterval) + 1;
95
96
            // there's a weird 16 records per block thing here, columns extend beyond declared boundaries
97 2
            $this->numberOfColumns = intdiv($this->numberOfColumns + 16 - 1, 16) * 16;
98
        }
99
100 3
        if ($this->startX > 180) { // normalise if necessary
101
            $this->startX -= 360;
102
        }
103
    }
104
105
    /**
106
     * @return Metre[]
107
     */
108 3
    public function getValues($x, $y): array
109
    {
110 3
        $shift = $this->interpolate($x, $y)[0];
111
112 3
        return [new Metre($shift)];
113
    }
114
115 3
    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...
116
    {
117 3
        $recordId = ($this->numberOfRows - $latitudeIndex - 1) * $this->numberOfColumns + $longitudeIndex;
118 3
        $longitude = $longitudeIndex * $this->columnGridInterval + $this->startX;
119 3
        $latitude = $latitudeIndex * $this->rowGridInterval + $this->startY;
120
121 3
        if ($this->isBinary) {
122 2
            $offset = $this->binaryHeaderLength + $recordId * 4;
123 2
            $this->gridFile->fseek($offset);
124 2
            $rawRow = $this->gridFile->fread(4);
125 2
            $data = unpack("{$this->floatFormatChar}shift", $rawRow);
126
127 2
            return new GridValues(
128 2
                $longitude,
129 2
                $latitude,
130 2
                [$data['shift']]
131 2
            );
132
        } else {
133 1
            return new GridValues(
134 1
                $longitude,
135 1
                $latitude,
136 1
                [$this->textData[$recordId]]
137 1
            );
138
        }
139
    }
140
}
141