Completed
Push — master ( 1d678e...613697 )
by Doug
02:45
created

OSRef   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 44
dl 0
loc 159
ccs 55
cts 55
cp 1
rs 10
c 0
b 0
f 0
wmc 13

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getOriginLatitude() 0 3 1
A __construct() 0 3 1
A getOriginLongitude() 0 3 1
A getReferenceEllipsoid() 0 3 1
A getOriginEasting() 0 3 1
A getOriginNorthing() 0 3 1
A getScaleFactor() 0 3 1
A toLatLng() 0 10 1
A __toString() 0 3 1
A fromGridReference() 0 23 2
A toGridReference() 0 25 2
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 22
    public function __construct($x, $y, $z = 0)
79
    {
80 22
        parent::__construct($x, $y, $z, RefEll::airy1830());
81 22
    }
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 7
    public static function fromGridReference(string $ref): self
93
    {
94 7
        if (strlen($ref) % 2 !== 0) {
95 1
            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
     * Convert this grid reference into a grid reference string of a
119
     * given length (2, 4, 6, 8 or 10) including the two-character
120
     * designation for the 100km square. e.g. TG514131.
121
     *
122
     * @param int $length
123
     *
124
     * @return string
125
     */
126 8
    public function toGridReference(int $length): string
127
    {
128 8
        if ($length % 2 !== 0) {
129 1
            throw new LengthException('Chosen length must be an even number');
130
        }
131
132 7
        $halfLength = $length / 2;
133
134 7
        $easting = str_pad((string) $this->x, 6, '0', STR_PAD_LEFT);
135 7
        $northing = str_pad((string) $this->y, 6, '0', STR_PAD_LEFT);
136
137 7
        $adjustedX = $this->x + 1000000;
138 7
        $adjustedY = $this->y + 500000;
139 7
        $majorSquaresEast = floor($adjustedX / 500000);
140 7
        $majorSquaresNorth = floor($adjustedY / 500000);
141 7
        $majorLetterIndex = (int) (5 * $majorSquaresNorth + $majorSquaresEast);
142 7
        $majorLetter = substr(self::GRID_LETTERS, $majorLetterIndex, 1);
143
144
        //second (minor) letter is 100km grid sq, origin at 0,0 of this square
145 7
        $minorSquaresEast = $easting[0] % 5;
146 7
        $minorSquaresNorth = $northing[0] % 5;
147 7
        $minorLetterIndex = (5 * $minorSquaresNorth + $minorSquaresEast);
148 7
        $minorLetter = substr(self::GRID_LETTERS, $minorLetterIndex, 1);
149
150 7
        return $majorLetter . $minorLetter . substr($easting, 1, $halfLength) . substr($northing, 1, $halfLength);
151
    }
152
153
    /**
154
     * Convert this grid reference into a latitude and longitude.
155
     *
156
     * @return LatLng
157
     */
158 3
    public function toLatLng(): LatLng
159
    {
160 3
        $N = $this->y;
161 3
        $E = $this->x;
162 3
        $N0 = $this->getOriginNorthing();
163 3
        $E0 = $this->getOriginEasting();
164 3
        $phi0 = $this->getOriginLatitude();
165 3
        $lambda0 = $this->getOriginLongitude();
166
167 3
        return $this->convertToLatitudeLongitude($N, $E, $N0, $E0, $phi0, $lambda0);
168
    }
169
170
    /**
171
     * String version of coordinate.
172
     *
173
     * @return string
174
     */
175 9
    public function __toString(): string
176
    {
177 9
        return "({$this->x}, {$this->y})";
178
    }
179
}
180