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

IrishGridPoint::gridReference()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 2.0009

Importance

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