Passed
Push — 4.0.x ( 414ad0...5c8c8d )
by Doug
05:04 queued 12s
created

IrishGridPoint::fromGridReference()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2.0023

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 11
c 2
b 0
f 0
nc 2
nop 2
dl 0
loc 21
ccs 11
cts 12
cp 0.9167
crap 2.0023
rs 9.9
1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord;
10
11
use DateTimeInterface;
12
use function floor;
13
use function implode;
14
use PHPCoord\CoordinateReferenceSystem\Projected;
15
use PHPCoord\Exception\InvalidCoordinateException;
16
use PHPCoord\UnitOfMeasure\Length\Length;
17
use PHPCoord\UnitOfMeasure\Length\Metre;
18
use function str_pad;
19
use const STR_PAD_LEFT;
20
use function str_replace;
21
use function strlen;
22
use function strpos;
23
use function substr;
24
25
/**
26
 * N.B. This is the older 1975 system, not the current ITM system for which @see IrishTransverseMercatorPoint.
27
 */
28
class IrishGridPoint extends ProjectedPoint
29
{
30
    private const GRID_LETTERS = 'VWXYZQRSTULMNOPFGHJKABCDE';
31
32 6
    public function __construct(Length $easting, Length $northing, ?DateTimeInterface $epoch = null)
33
    {
34 6
        parent::__construct($easting, $northing, null, null, Projected::fromSRID(Projected::EPSG_TM75_IRISH_GRID), $epoch);
35 6
    }
36
37
    /**
38
     * @param string $reference Irish grid reference (e.g. "T514131")
39
     */
40 3
    public static function fromGridReference(string $reference, ?DateTimeInterface $epoch = null): self
41
    {
42 3
        $reference = str_replace(' ', '', $reference);
43
44 3
        if (strlen($reference) % 2 === 0) {
45
            throw new InvalidCoordinateException('Grid ref must be an even number of characters');
46
        }
47
48
        //Letter is 100km grid sq, origin at 0,0 of this square
49 3
        $minorEasting = strpos(static::GRID_LETTERS, $reference[0]) % 5 * 100000;
50 3
        $minorNorthing = (floor(strpos(static::GRID_LETTERS, $reference[0]) / 5)) * 100000;
51
52
        //numbers are a division of that square into smaller and smaller pieces
53 3
        $numericPortion = substr($reference, 1);
54 3
        $numericPortionSize = strlen($numericPortion) / 2;
55 3
        $gridSizeInMetres = 1 * (10 ** (5 - $numericPortionSize));
56
57 3
        $easting = $minorEasting + (substr($numericPortion, 0, $numericPortionSize) * $gridSizeInMetres);
58 3
        $northing = $minorNorthing + (substr($numericPortion, -$numericPortionSize, $numericPortionSize) * $gridSizeInMetres);
59
60 3
        return new static(new Metre($easting), new Metre($northing), $epoch);
61
    }
62
63
    /**
64
     * Grid reference without spaces. e.g. T514131.
65
     */
66 1
    public function asGridReference(int $length): string
67
    {
68 1
        return implode('', $this->gridReference($length));
69
    }
70
71
    /**
72
     * Convert this grid reference into a grid reference string of a
73
     * given length (2, 4, 6, 8 or 10) including the character
74
     * designation for the 100km square. e.g. T514131.
75
     *
76
     * @return string
77
     */
78 1
    protected function gridReference(int $length): array
79
    {
80 1
        if ($length % 2 !== 0) {
81
            throw new InvalidCoordinateException('Chosen length must be an even number');
82
        }
83
84 1
        $halfLength = $length / 2;
85
86 1
        $x = $this->easting->asMetres()->getValue();
87 1
        $y = $this->northing->asMetres()->getValue();
88 1
        $easting = str_pad((string) $x, 6, '0', STR_PAD_LEFT);
89 1
        $northing = str_pad((string) $y, 6, '0', STR_PAD_LEFT);
90
91
        //second (minor) letter is 100km grid sq, origin at 0,0 of this square
92 1
        $minorSquaresEast = $easting[0] % 5;
93 1
        $minorSquaresNorth = $northing[0] % 5;
94 1
        $minorLetterIndex = (5 * $minorSquaresNorth + $minorSquaresEast);
95 1
        $minorLetter = substr(self::GRID_LETTERS, $minorLetterIndex, 1);
96
97
        return [
98 1
            $minorLetter,
99 1
            substr($easting, 1, $halfLength),
100 1
            substr($northing, 1, $halfLength),
101
        ];
102
    }
103
}
104