Passed
Push — master ( 705a37...2b8bad )
by Doug
17:25 queued 45s
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;
0 ignored issues
show
Bug introduced by
The type PHPCoord\CoordinateReferenceSystem\Projected was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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 54
    public function __construct(Length $easting, Length $northing, ?DateTimeInterface $epoch = null)
33
    {
34 54
        parent::__construct(Projected::fromSRID(Projected::EPSG_TM75_IRISH_GRID), $easting, $northing, null, null, $epoch);
35
    }
36
37
    /**
38
     * @param string $reference Irish grid reference (e.g. "T514131")
39
     */
40 27
    public static function fromGridReference(string $reference, ?DateTimeInterface $epoch = null): self
41
    {
42 27
        $reference = str_replace(' ', '', $reference);
43
44 27
        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 27
        $minorEasting = strpos(static::GRID_LETTERS, $reference[0]) % 5 * 100000;
50 27
        $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 27
        $numericPortion = substr($reference, 1);
54 27
        $numericPortionSize = strlen($numericPortion) / 2;
55 27
        $gridSizeInMetres = 1 * (10 ** (5 - $numericPortionSize));
56
57 27
        $easting = $minorEasting + (substr($numericPortion, 0, $numericPortionSize) * $gridSizeInMetres);
58 27
        $northing = $minorNorthing + (substr($numericPortion, -$numericPortionSize, $numericPortionSize) * $gridSizeInMetres);
59
60 27
        return new static(new Metre($easting), new Metre($northing), $epoch);
61
    }
62
63
    /**
64
     * Grid reference without spaces. e.g. T514131.
65
     */
66 9
    public function asGridReference(int $length): string
67
    {
68 9
        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 9
    protected function gridReference(int $length): array
79
    {
80 9
        if ($length % 2 !== 0) {
81
            throw new InvalidCoordinateException('Chosen length must be an even number');
82
        }
83
84 9
        $halfLength = $length / 2;
85
86 9
        $x = $this->easting->asMetres()->getValue();
87 9
        $y = $this->northing->asMetres()->getValue();
88 9
        $easting = str_pad((string) $x, 6, '0', STR_PAD_LEFT);
89 9
        $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 9
        $minorSquaresEast = $easting[0] % 5;
93 9
        $minorSquaresNorth = $northing[0] % 5;
94 9
        $minorLetterIndex = (5 * $minorSquaresNorth + $minorSquaresEast);
95 9
        $minorLetter = substr(self::GRID_LETTERS, $minorLetterIndex, 1);
96
97
        return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($minorLette...thing, 1, $halfLength)) returns the type array<integer,string> which is incompatible with the documented return type string.
Loading history...
98
            $minorLetter,
99 9
            substr($easting, 1, $halfLength),
100 9
            substr($northing, 1, $halfLength),
101
        ];
102
    }
103
}
104