Passed
Push — master ( f0120c...e0bc5c )
by Doug
01:38
created

OSRef::toFourFigureReference()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPCoord;
6
7
use function floor;
8
use LengthException;
9
use function str_pad;
10
use function strpos;
11
12
/**
13
 * Ordnance Survey grid reference
14
 * References are accurate to 1m.
15
 *
16
 * @author Jonathan Stott
17
 * @author Doug Wright
18
 */
19
class OSRef extends TransverseMercator
20
{
21
    private const GRID_LETTERS = 'VWXYZQRSTULMNOPFGHJKABCDE';
22
23
    /**
24
     * @return RefEll
25
     */
26 4
    public function getReferenceEllipsoid(): RefEll
27
    {
28 4
        return RefEll::airy1830();
29
    }
30
31
    /**
32
     * @return float
33
     */
34 5
    public function getScaleFactor(): float
35
    {
36 5
        return 0.9996012717;
37
    }
38
39
    /**
40
     * @return int
41
     */
42 5
    public function getOriginNorthing(): int
43
    {
44 5
        return -100000;
45
    }
46
47
    /**
48
     * @return int
49
     */
50 5
    public function getOriginEasting(): int
51
    {
52 5
        return 400000;
53
    }
54
55
    /**
56
     * @return float
57
     */
58 5
    public function getOriginLatitude(): float
59
    {
60 5
        return 49;
61
    }
62
63
    /**
64
     * @return float
65
     */
66 5
    public function getOriginLongitude(): float
67
    {
68 5
        return -2;
69
    }
70
71
    /**
72
     * Create a new object representing a OSGB reference.
73
     *
74
     * @param int $x
75
     * @param int $y
76
     * @param int $z
77
     */
78 21
    public function __construct($x, $y, $z = 0)
79
    {
80 21
        parent::__construct($x, $y, $z, RefEll::airy1830());
81 21
    }
82
83
    /**
84
     * Take a string formatted as a OS grid reference (e.g.
85
     * "TG514131") and return a reference to an OSRef object that represents
86
     * that grid reference.
87
     *
88
     * @param string $ref
89
     *
90
     * @return static
91
     */
92 6
    public static function fromGridReference(string $ref): self
93
    {
94 6
        if (strlen($ref) % 2 !== 0) {
95
            throw new LengthException('Grid ref must be an even number of characters');
96
        }
97
98
        //first (major) letter is the 500km grid sq, origin at -1000000, -500000
99 6
        $majorEasting = strpos(self::GRID_LETTERS, $ref[0]) % 5 * 500000 - 1000000;
100 6
        $majorNorthing = (floor(strpos(self::GRID_LETTERS, $ref[0]) / 5)) * 500000 - 500000;
101
102
        //second (minor) letter is 100km grid sq, origin at 0,0 of this square
103 6
        $minorEasting = strpos(self::GRID_LETTERS, $ref[1]) % 5 * 100000;
104 6
        $minorNorthing = (floor(strpos(self::GRID_LETTERS, $ref[1]) / 5)) * 100000;
105
106
        //numbers are a division of that square into smaller and smaller pieces
107 6
        $numericPortion = substr($ref, 2);
108 6
        $numericPortionSize = strlen($numericPortion) / 2;
109 6
        $gridSizeInMetres = 1 * (10 ** (5 - $numericPortionSize));
110
111 6
        $easting = $majorEasting + $minorEasting + (substr($numericPortion, 0, $numericPortionSize) * $gridSizeInMetres);
112 6
        $northing = $majorNorthing + $minorNorthing + (substr($numericPortion, -$numericPortionSize, $numericPortionSize) * $gridSizeInMetres);
113
114 6
        return new static((int) $easting, (int) $northing);
115
    }
116
117
    /**
118
     * Take a string formatted as a six-figure OS grid reference (e.g.
119
     * "TG514131") and return a reference to an OSRef object that represents
120
     * that grid reference.
121
     *
122
     * @param string $ref
123
     *
124
     * @deprecated use fromGridReference() instead, which can take references of other lengths too
125
     *
126
     * @return static
127
     */
128 2
    public static function fromSixFigureReference(string $ref): self
129
    {
130 2
        return static::fromGridReference($ref);
131
    }
132
133
    /**
134
     * Convert this grid reference into a grid reference string of a
135
     * given length (2, 4, 6, 8 or 10) including the two-character
136
     * designation for the 100km square. e.g. TG514131.
137
     *
138
     * @param int $length
139
     *
140
     * @return string
141
     */
142 7
    public function toGridReference(int $length): string
143
    {
144 7
        if ($length % 2 !== 0) {
145
            throw new LengthException('Chosen length must be an even number');
146
        }
147
148 7
        $halfLength = $length / 2;
149
150 7
        $easting = str_pad((string) $this->x, 6, '0', STR_PAD_LEFT);
151 7
        $northing = str_pad((string) $this->y, 6, '0', STR_PAD_LEFT);
152
153 7
        $adjustedX = $this->x + 1000000;
154 7
        $adjustedY = $this->y + 500000;
155 7
        $majorSquaresEast = floor($adjustedX / 500000);
156 7
        $majorSquaresNorth = floor($adjustedY / 500000);
157 7
        $majorLetterIndex = (int) (5 * $majorSquaresNorth + $majorSquaresEast);
158 7
        $majorLetter = substr(self::GRID_LETTERS, $majorLetterIndex, 1);
159
160
        //second (minor) letter is 100km grid sq, origin at 0,0 of this square
161 7
        $minorSquaresEast = $easting[0] % 5;
162 7
        $minorSquaresNorth = $northing[0] % 5;
163 7
        $minorLetterIndex = (5 * $minorSquaresNorth + $minorSquaresEast);
164 7
        $minorLetter = substr(self::GRID_LETTERS, $minorLetterIndex, 1);
165
166 7
        return $majorLetter.$minorLetter.substr($easting, 1, $halfLength).substr($northing, 1, $halfLength);
167
    }
168
169
    /**
170
     * Convert this grid reference into a string using a standard two-figure
171
     * grid reference including the two-character designation for the 100km
172
     * square. e.g. TG51 (10km square).
173
     *
174
     * @deprecated use toGridReference() instead, which can produces references of varying precision
175
     *
176
     * @return string
177
     */
178 1
    public function toTwoFigureReference(): string
179
    {
180 1
        return $this->toGridReference(2);
181
    }
182
183
    /**
184
     * Convert this grid reference into a string using a standard four-figure
185
     * grid reference including the two-character designation for the 100km
186
     * square. e.g. TG5113 (1km square).
187
     *
188
     * @deprecated use toGridReference() instead, which can produces references of varying precision
189
     *
190
     * @return string
191
     */
192 1
    public function toFourFigureReference(): string
193
    {
194 1
        return $this->toGridReference(4);
195
    }
196
197
    /**
198
     * Convert this grid reference into a string using a standard six-figure
199
     * grid reference including the two-character designation for the 100km
200
     * square. e.g. TG514131 (100m square).
201
     *
202
     * @deprecated use toGridReference() instead, which can produces references of varying precision
203
     *
204
     * @return string
205
     */
206 3
    public function toSixFigureReference(): string
207
    {
208 3
        return $this->toGridReference(6);
209
    }
210
211
    /**
212
     * Convert this grid reference into a string using a standard eight-figure
213
     * grid reference including the two-character designation for the 100km
214
     * square. e.g. TG51431312 (10m square).
215
     *
216
     * @deprecated use toGridReference() instead, which can produces references of varying precision
217
     *
218
     * @return string
219
     */
220 1
    public function toEightFigureReference(): string
221
    {
222 1
        return $this->toGridReference(8);
223
    }
224
225
    /**
226
     * Convert this grid reference into a string using a standard ten-figure
227
     * grid reference including the two-character designation for the 100km
228
     * square. e.g. TG5143113121 (1m square).
229
     *
230
     * @deprecated use toGridReference() instead, which can produces references of varying precision
231
     *
232
     * @return string
233
     */
234 1
    public function toTenFigureReference(): string
235
    {
236 1
        return $this->toGridReference(10);
237
    }
238
239
    /**
240
     * Convert this grid reference into a latitude and longitude.
241
     *
242
     * @return LatLng
243
     */
244 3
    public function toLatLng(): LatLng
245
    {
246 3
        $N = $this->y;
247 3
        $E = $this->x;
248 3
        $N0 = $this->getOriginNorthing();
249 3
        $E0 = $this->getOriginEasting();
250 3
        $phi0 = $this->getOriginLatitude();
251 3
        $lambda0 = $this->getOriginLongitude();
252
253 3
        return $this->convertToLatitudeLongitude($N, $E, $N0, $E0, $phi0, $lambda0);
254
    }
255
256
    /**
257
     * String version of coordinate.
258
     *
259
     * @return string
260
     */
261 9
    public function __toString(): string
262
    {
263 9
        return "({$this->x}, {$this->y})";
264
    }
265
}
266