Passed
Push — master ( bbeaaa...9ed6c0 )
by Doug
25:29
created

Length   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 294
Duplicated Lines 0 %

Test Coverage

Coverage 85.19%

Importance

Changes 0
Metric Value
eloc 110
dl 0
loc 294
ccs 46
cts 54
cp 0.8519
rs 10
c 0
b 0
f 0
wmc 14

9 Methods

Rating   Name   Duplication   Size   Complexity  
A convert() 0 5 1
A __toString() 0 3 1
A makeUnit() 0 28 2
A divide() 0 3 1
A registerCustomUnit() 0 5 1
A add() 0 9 2
A multiply() 0 3 1
A subtract() 0 9 2
A getSupportedSRIDs() 0 9 3
1
<?php
2
/**
3
 * PHPCoord.
4
 *
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
9
namespace PHPCoord\UnitOfMeasure\Length;
10
11
use PHPCoord\Exception\UnknownUnitOfMeasureException;
12
use PHPCoord\UnitOfMeasure\UnitOfMeasure;
13
14
abstract class Length implements UnitOfMeasure
15
{
16
    /**
17
     * British chain (Benoit 1895 B)
18
     * Uses Benoit's 1895 British yard-metre ratio as given by Bomford as 39.370113 inches per metre.  Used in West
19
     * Malaysian mapping.
20
     */
21
    public const EPSG_BRITISH_CHAIN_BENOIT_1895_B = 'urn:ogc:def:uom:EPSG::9062';
22
23
    /**
24
     * British chain (Sears 1922 truncated)
25
     * Uses Sear's 1922 British yard-metre ratio (UoM code 9040) truncated to 6 significant figures; this truncated
26
     * ratio (0.914398, UoM code 9099) then converted to other imperial units. 1 chSe(T) = 22 ydSe(T). Used in
27
     * metrication of Malaya RSO grid.
28
     */
29
    public const EPSG_BRITISH_CHAIN_SEARS_1922_TRUNCATED = 'urn:ogc:def:uom:EPSG::9301';
30
31
    /**
32
     * British chain (Sears 1922)
33
     * Uses Sear's 1922 British yard-metre ratio as given by Bomford as 39.370147 inches per metre.  Used in East
34
     * Malaysian and older New Zealand mapping.
35
     */
36
    public const EPSG_BRITISH_CHAIN_SEARS_1922 = 'urn:ogc:def:uom:EPSG::9042';
37
38
    /**
39
     * British foot (1936)
40
     * For the 1936 retriangulation OSGB defines the relationship of 10 feet of 1796 to the International metre through
41
     * the logarithmic relationship (10^0.48401603 exactly). 1 ft = 0.3048007491…m. Also used for metric conversions
42
     * in Ireland.
43
     */
44
    public const EPSG_BRITISH_FOOT_1936 = 'urn:ogc:def:uom:EPSG::9095';
45
46
    /**
47
     * British foot (Sears 1922)
48
     * Uses Sear's 1922 British yard-metre ratio as given by Bomford as 39.370147 inches per metre.  Used in East
49
     * Malaysian and older New Zealand mapping.
50
     */
51
    public const EPSG_BRITISH_FOOT_SEARS_1922 = 'urn:ogc:def:uom:EPSG::9041';
52
53
    /**
54
     * British yard (Sears 1922)
55
     * Uses Sear's 1922 British yard-metre ratio as given by Bomford as 39.370147 inches per metre.  Used in East
56
     * Malaysian and older New Zealand mapping.
57
     */
58
    public const EPSG_BRITISH_YARD_SEARS_1922 = 'urn:ogc:def:uom:EPSG::9040';
59
60
    /**
61
     * Clarke's foot
62
     * Assumes Clarke's 1865 ratio of 1 British foot = 0.3047972654 French legal metres applies to the international
63
     * metre.   Used in older Australian, southern African & British West Indian mapping.
64
     */
65
    public const EPSG_CLARKES_FOOT = 'urn:ogc:def:uom:EPSG::9005';
66
67
    /**
68
     * Clarke's link
69
     * =1/100 Clarke's chain. Assumes Clarke's 1865 ratio of 1 British foot = 0.3047972654 French legal metres applies
70
     * to the international metre.   Used in older Australian, southern African & British West Indian mapping.
71
     */
72
    public const EPSG_CLARKES_LINK = 'urn:ogc:def:uom:EPSG::9039';
73
74
    /**
75
     * Clarke's yard
76
     * =3 Clarke's feet.  Assumes Clarke's 1865 ratio of 1 British foot = 0.3047972654 French legal metres applies to
77
     * the international metre.   Used in older Australian, southern African & British West Indian mapping.
78
     */
79
    public const EPSG_CLARKES_YARD = 'urn:ogc:def:uom:EPSG::9037';
80
81
    /**
82
     * German legal metre
83
     * Used in Namibia.
84
     */
85
    public const EPSG_GERMAN_LEGAL_METRE = 'urn:ogc:def:uom:EPSG::9031';
86
87
    /**
88
     * Gold Coast foot
89
     * Used in Ghana and some adjacent parts of British west Africa prior to metrication, except for the metrication of
90
     * projection defining parameters when British foot (Sears 1922) used.
91
     */
92
    public const EPSG_GOLD_COAST_FOOT = 'urn:ogc:def:uom:EPSG::9094';
93
94
    /**
95
     * Indian foot
96
     * Indian Foot = 0.99999566 British feet (A.R.Clarke 1865).  British yard (= 3 British feet) taken to be
97
     * J.S.Clark's 1865 value of 0.9144025 metres.
98
     */
99
    public const EPSG_INDIAN_FOOT = 'urn:ogc:def:uom:EPSG::9080';
100
101
    /**
102
     * Indian yard
103
     * Indian Foot = 0.99999566 British feet (A.R.Clarke 1865).  British yard (= 3 British feet) taken to be
104
     * J.S.Clark's 1865 value of 0.9144025 metres.
105
     */
106
    public const EPSG_INDIAN_YARD = 'urn:ogc:def:uom:EPSG::9084';
107
108
    /**
109
     * US survey foot
110
     * Used in USA.
111
     */
112
    public const EPSG_US_SURVEY_FOOT = 'urn:ogc:def:uom:EPSG::9003';
113
114
    /**
115
     * Centimetre.
116
     */
117
    public const EPSG_CENTIMETRE = 'urn:ogc:def:uom:EPSG::1033';
118
119
    /**
120
     * Foot.
121
     */
122
    public const EPSG_FOOT = 'urn:ogc:def:uom:EPSG::9002';
123
124
    /**
125
     * Kilometre.
126
     */
127
    public const EPSG_KILOMETRE = 'urn:ogc:def:uom:EPSG::9036';
128
129
    /**
130
     * Link
131
     * =1/100 international chain.
132
     */
133
    public const EPSG_LINK = 'urn:ogc:def:uom:EPSG::9098';
134
135
    /**
136
     * Metre
137
     * SI base unit for length.
138
     */
139
    public const EPSG_METRE = 'urn:ogc:def:uom:EPSG::9001';
140
141
    /**
142
     * Millimetre.
143
     */
144
    public const EPSG_MILLIMETRE = 'urn:ogc:def:uom:EPSG::1025';
145
146
    protected static array $sridData = [
147
        'urn:ogc:def:uom:EPSG::1025' => [
148
            'name' => 'millimetre',
149
        ],
150
        'urn:ogc:def:uom:EPSG::1033' => [
151
            'name' => 'centimetre',
152
        ],
153
        'urn:ogc:def:uom:EPSG::9001' => [
154
            'name' => 'metre',
155
        ],
156
        'urn:ogc:def:uom:EPSG::9002' => [
157
            'name' => 'foot',
158
        ],
159
        'urn:ogc:def:uom:EPSG::9003' => [
160
            'name' => 'US survey foot',
161
        ],
162
        'urn:ogc:def:uom:EPSG::9005' => [
163
            'name' => 'Clarke\'s foot',
164
        ],
165
        'urn:ogc:def:uom:EPSG::9031' => [
166
            'name' => 'German legal metre',
167
        ],
168
        'urn:ogc:def:uom:EPSG::9036' => [
169
            'name' => 'kilometre',
170
        ],
171
        'urn:ogc:def:uom:EPSG::9037' => [
172
            'name' => 'Clarke\'s yard',
173
        ],
174
        'urn:ogc:def:uom:EPSG::9039' => [
175
            'name' => 'Clarke\'s link',
176
        ],
177
        'urn:ogc:def:uom:EPSG::9040' => [
178
            'name' => 'British yard (Sears 1922)',
179
        ],
180
        'urn:ogc:def:uom:EPSG::9041' => [
181
            'name' => 'British foot (Sears 1922)',
182
        ],
183
        'urn:ogc:def:uom:EPSG::9042' => [
184
            'name' => 'British chain (Sears 1922)',
185
        ],
186
        'urn:ogc:def:uom:EPSG::9062' => [
187
            'name' => 'British chain (Benoit 1895 B)',
188
        ],
189
        'urn:ogc:def:uom:EPSG::9080' => [
190
            'name' => 'Indian foot',
191
        ],
192
        'urn:ogc:def:uom:EPSG::9084' => [
193
            'name' => 'Indian yard',
194
        ],
195
        'urn:ogc:def:uom:EPSG::9094' => [
196
            'name' => 'Gold Coast foot',
197
        ],
198
        'urn:ogc:def:uom:EPSG::9095' => [
199
            'name' => 'British foot (1936)',
200
        ],
201
        'urn:ogc:def:uom:EPSG::9098' => [
202
            'name' => 'link',
203
        ],
204
        'urn:ogc:def:uom:EPSG::9301' => [
205
            'name' => 'British chain (Sears 1922 truncated)',
206
        ],
207
    ];
208
209
    protected static array $customSridData = [];
210
211
    private static array $supportedCache = [];
212
213
    abstract public function __construct(float $length);
214
215
    abstract public function asMetres(): Metre;
216
217 347
    public function add(self $unit): self
218
    {
219 347
        if ($this::class === $unit::class) {
220 347
            return new static($this->getValue() + $unit->getValue());
221
        }
222
        $resultAsMetres = new Metre($this->asMetres()->getValue() + $unit->asMetres()->getValue());
223
        $conversionRatio = (new static(1))->asMetres()->getValue();
224
225
        return new static($resultAsMetres->getValue() / $conversionRatio);
226
    }
227
228 233
    public function subtract(self $unit): self
229
    {
230 233
        if ($this::class === $unit::class) {
231 233
            return new static($this->getValue() - $unit->getValue());
232
        }
233
        $resultAsMetres = new Metre($this->asMetres()->getValue() - $unit->asMetres()->getValue());
234
        $conversionRatio = (new static(1))->asMetres()->getValue();
235
236
        return new static($resultAsMetres->getValue() / $conversionRatio);
237
    }
238
239 5338
    public function multiply(float $multiplicand): self
240
    {
241 5338
        return new static($this->getValue() * $multiplicand);
242
    }
243
244 243
    public function divide(float $divisor): self
245
    {
246 243
        return new static($this->getValue() / $divisor);
247
    }
248
249 6520
    public static function makeUnit(float $measurement, string $srid): self
250
    {
251 6520
        if (isset(self::$customSridData[$srid])) {
252 126
            return new self::$customSridData[$srid]['fqcn']($measurement);
253
        }
254
255
        return match ($srid) {
256 6520
            self::EPSG_METRE => new Metre($measurement),
257 1009
            self::EPSG_KILOMETRE => new Kilometre($measurement),
258 964
            self::EPSG_CENTIMETRE => new Centimetre($measurement),
259 946
            self::EPSG_MILLIMETRE => new Millimetre($measurement),
260 910
            self::EPSG_FOOT => new Foot($measurement),
261 694
            self::EPSG_LINK => new Link($measurement),
262 631
            self::EPSG_BRITISH_CHAIN_BENOIT_1895_B => new BritishChain1895BenoitB($measurement),
263 613
            self::EPSG_BRITISH_FOOT_SEARS_1922 => new BritishFoot1922Sears($measurement),
264 577
            self::EPSG_BRITISH_YARD_SEARS_1922 => new BritishYard1922Sears($measurement),
265 541
            self::EPSG_BRITISH_CHAIN_SEARS_1922 => new BritishChain1922Sears($measurement),
266 505
            self::EPSG_BRITISH_CHAIN_SEARS_1922_TRUNCATED => new BritishChain1922SearsTruncated($measurement),
267 469
            self::EPSG_BRITISH_FOOT_1936 => new BritishFoot1936($measurement),
268 442
            self::EPSG_US_SURVEY_FOOT => new USSurveyFoot($measurement),
269 297
            self::EPSG_CLARKES_FOOT => new ClarkeFoot($measurement),
270 225
            self::EPSG_CLARKES_YARD => new ClarkeYard($measurement),
271 207
            self::EPSG_CLARKES_LINK => new ClarkeLink($measurement),
272 153
            self::EPSG_INDIAN_FOOT => new IndianFoot($measurement),
273 126
            self::EPSG_INDIAN_YARD => new IndianYard($measurement),
274 90
            self::EPSG_GOLD_COAST_FOOT => new GoldCoastFoot($measurement),
275 54
            self::EPSG_GERMAN_LEGAL_METRE => new GermanLegalMetre($measurement),
276 6520
            default => throw new UnknownUnitOfMeasureException($srid),
277
        };
278
    }
279
280 252
    public static function getSupportedSRIDs(): array
281
    {
282 252
        if (!self::$supportedCache) {
0 ignored issues
show
Bug Best Practice introduced by
The expression self::supportedCache of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
283
            foreach (static::$sridData as $srid => $data) {
284
                self::$supportedCache[$srid] = $data['name'];
285
            }
286
        }
287
288 252
        return self::$supportedCache;
289
    }
290
291 126
    public static function registerCustomUnit(string $srid, string $name, string $implementingClassFQCN): void
292
    {
293 126
        self::$customSridData[$srid] = ['name' => $name, 'fqcn' => $implementingClassFQCN];
294 126
        self::getSupportedSRIDs(); // init cache if not already
295 126
        self::$supportedCache[$srid] = $name; // update cache
296
    }
297
298 406
    public static function convert(self $length, string $targetSRID): self
299
    {
300 406
        $conversionRatio = static::makeUnit(1, $targetSRID)->asMetres()->getValue();
301
302 406
        return self::makeUnit($length->asMetres()->getValue() / $conversionRatio, $targetSRID);
303
    }
304
305 225
    public function __toString(): string
306
    {
307 225
        return (string) $this->getValue();
308
    }
309
}
310