Passed
Push — 4.x ( 2e43a7...18aaa8 )
by Doug
06:37
created

Angle::convert()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * PHPCoord.
5
 *
6
 * @author Doug Wright
7
 */
8
declare(strict_types=1);
9
10
namespace PHPCoord\UnitOfMeasure\Angle;
11
12
use PHPCoord\Exception\UnknownUnitOfMeasureException;
13
use PHPCoord\UnitOfMeasure\UnitOfMeasure;
14
15
use function array_map;
16
17
use const M_PI;
18
19
abstract class Angle implements UnitOfMeasure
20
{
21
    /**
22
     * Arc-second
23
     * 1/60th arc-minute = ((pi/180) / 3600) radians.
24
     */
25
    public const EPSG_ARC_SECOND = 'urn:ogc:def:uom:EPSG::9104';
26
27
    /**
28
     * Centesimal second
29
     * 1/100 of a centesimal minute or 1/10,000th of a grad and gon = ((pi/200) / 10000) radians.
30
     */
31
    public const EPSG_CENTESIMAL_SECOND = 'urn:ogc:def:uom:EPSG::9113';
32
33
    /**
34
     * Degree
35
     * = pi/180 radians.
36
     */
37
    public const EPSG_DEGREE = 'urn:ogc:def:uom:EPSG::9102';
38
39
    /**
40
     * Degree hemisphere
41
     * Degree representation. Format: degrees (real, any precision) - hemisphere abbreviation (single character N S E
42
     * or W). Convert to degrees using algorithm.
43
     */
44
    public const EPSG_DEGREE_HEMISPHERE = 'urn:ogc:def:uom:EPSG::9116';
45
46
    /**
47
     * Degree minute
48
     * Degree representation. Format: signed degrees (integer)  - arc-minutes (real, any precision). Different symbol
49
     * sets are in use as field separators, for example º '. Convert to degrees using algorithm.
50
     */
51
    public const EPSG_DEGREE_MINUTE = 'urn:ogc:def:uom:EPSG::9115';
52
53
    /**
54
     * Degree minute hemisphere
55
     * Degree representation. Format: degrees (integer) - arc-minutes (real, any precision) - hemisphere abbreviation
56
     * (single character N S E or W). Different symbol sets are in use as field separators, for example º '. Convert
57
     * to degrees using algorithm.
58
     */
59
    public const EPSG_DEGREE_MINUTE_HEMISPHERE = 'urn:ogc:def:uom:EPSG::9118';
60
61
    /**
62
     * Degree minute second
63
     * Degree representation. Format: signed degrees (integer) - arc-minutes (integer) - arc-seconds (real, any
64
     * precision). Different symbol sets are in use as field separators, for example º ' ". Convert to degrees using
65
     * algorithm.
66
     */
67
    public const EPSG_DEGREE_MINUTE_SECOND = 'urn:ogc:def:uom:EPSG::9107';
68
69
    /**
70
     * Degree minute second hemisphere
71
     * Degree representation. Format: degrees (integer) - arc-minutes (integer) - arc-seconds (real) - hemisphere
72
     * abbreviation (single character N S E or W). Different symbol sets are in use as field separators for example º
73
     * ' ". Convert to deg using algorithm.
74
     */
75
    public const EPSG_DEGREE_MINUTE_SECOND_HEMISPHERE = 'urn:ogc:def:uom:EPSG::9108';
76
77
    /**
78
     * Grad
79
     * =pi/200 radians.
80
     */
81
    public const EPSG_GRAD = 'urn:ogc:def:uom:EPSG::9105';
82
83
    /**
84
     * Hemisphere degree
85
     * Degree representation. Format: hemisphere abbreviation (single character N S E or W) - degrees (real, any
86
     * precision). Convert to degrees using algorithm.
87
     */
88
    public const EPSG_HEMISPHERE_DEGREE = 'urn:ogc:def:uom:EPSG::9117';
89
90
    /**
91
     * Hemisphere degree minute
92
     * Degree representation. Format:  hemisphere abbreviation (single character N S E or W) - degrees (integer) -
93
     * arc-minutes (real, any precision). Different symbol sets are in use as field separators, for example º '.
94
     * Convert to degrees using algorithm.
95
     */
96
    public const EPSG_HEMISPHERE_DEGREE_MINUTE = 'urn:ogc:def:uom:EPSG::9119';
97
98
    /**
99
     * Hemisphere degree minute second
100
     * Degree representation. Format: hemisphere abbreviation (single character N S E or W) - degrees (integer) -
101
     * arc-minutes (integer) - arc-seconds (real). Different symbol sets are in use as field separators for example º
102
     * ' ". Convert to deg using algorithm.
103
     */
104
    public const EPSG_HEMISPHERE_DEGREE_MINUTE_SECOND = 'urn:ogc:def:uom:EPSG::9120';
105
106
    /**
107
     * Microradian
108
     * rad * 10E-6.
109
     */
110
    public const EPSG_MICRORADIAN = 'urn:ogc:def:uom:EPSG::9109';
111
112
    /**
113
     * Milliarc-second
114
     * = ((pi/180) / 3600 / 1000) radians.
115
     */
116
    public const EPSG_MILLIARC_SECOND = 'urn:ogc:def:uom:EPSG::1031';
117
118
    /**
119
     * Radian
120
     * SI coherent derived unit (standard unit) for plane angle.
121
     */
122
    public const EPSG_RADIAN = 'urn:ogc:def:uom:EPSG::9101';
123
124
    /**
125
     * Sexagesimal DMS
126
     * Pseudo unit. Format: signed degrees - period - minutes (2 digits) - integer seconds (2 digits) - fraction of
127
     * seconds (any precision). Must include leading zero in minutes and seconds and exclude decimal point for seconds.
128
     * Convert to deg using algorithm.
129
     */
130
    public const EPSG_SEXAGESIMAL_DMS = 'urn:ogc:def:uom:EPSG::9110';
131
132
    /**
133
     * @var array<string, array{name: string, fqcn?: class-string<self>, help: string}>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, array{name...g<self>, help: string}> at position 12 could not be parsed: Unknown type name 'class-string' at position 12 in array<string, array{name: string, fqcn?: class-string<self>, help: string}>.
Loading history...
134
     */
135
    protected static array $sridData = [
136
        'urn:ogc:def:uom:EPSG::1031' => [
137
            'name' => 'milliarc-second',
138
            'help' => '= ((pi/180) / 3600 / 1000) radians',
139
        ],
140
        'urn:ogc:def:uom:EPSG::9101' => [
141
            'name' => 'radian',
142
            'help' => 'SI coherent derived unit (standard unit) for plane angle.',
143
        ],
144
        'urn:ogc:def:uom:EPSG::9102' => [
145
            'name' => 'degree',
146
            'help' => '= pi/180 radians',
147
        ],
148
        'urn:ogc:def:uom:EPSG::9104' => [
149
            'name' => 'arc-second',
150
            'help' => '1/60th arc-minute = ((pi/180) / 3600) radians',
151
        ],
152
        'urn:ogc:def:uom:EPSG::9105' => [
153
            'name' => 'grad',
154
            'help' => '=pi/200 radians.',
155
        ],
156
        'urn:ogc:def:uom:EPSG::9107' => [
157
            'name' => 'degree minute second',
158
            'help' => 'Degree representation. Format: signed degrees (integer) - arc-minutes (integer) - arc-seconds (real, any precision). Different symbol sets are in use as field separators, for example º \' ". Convert to degrees using algorithm.',
159
        ],
160
        'urn:ogc:def:uom:EPSG::9108' => [
161
            'name' => 'degree minute second hemisphere',
162
            'help' => 'Degree representation. Format: degrees (integer) - arc-minutes (integer) - arc-seconds (real) - hemisphere abbreviation (single character N S E or W). Different symbol sets are in use as field separators for example º \' ". Convert to deg using algorithm.',
163
        ],
164
        'urn:ogc:def:uom:EPSG::9109' => [
165
            'name' => 'microradian',
166
            'help' => 'rad * 10E-6',
167
        ],
168
        'urn:ogc:def:uom:EPSG::9110' => [
169
            'name' => 'sexagesimal DMS',
170
            'help' => 'Pseudo unit. Format: signed degrees - period - minutes (2 digits) - integer seconds (2 digits) - fraction of seconds (any precision). Must include leading zero in minutes and seconds and exclude decimal point for seconds. Convert to deg using algorithm.',
171
        ],
172
        'urn:ogc:def:uom:EPSG::9113' => [
173
            'name' => 'centesimal second',
174
            'help' => '1/100 of a centesimal minute or 1/10,000th of a grad and gon = ((pi/200) / 10000) radians',
175
        ],
176
        'urn:ogc:def:uom:EPSG::9115' => [
177
            'name' => 'degree minute',
178
            'help' => 'Degree representation. Format: signed degrees (integer)  - arc-minutes (real, any precision). Different symbol sets are in use as field separators, for example º \'. Convert to degrees using algorithm.',
179
        ],
180
        'urn:ogc:def:uom:EPSG::9116' => [
181
            'name' => 'degree hemisphere',
182
            'help' => 'Degree representation. Format: degrees (real, any precision) - hemisphere abbreviation (single character N S E or W). Convert to degrees using algorithm.',
183
        ],
184
        'urn:ogc:def:uom:EPSG::9117' => [
185
            'name' => 'hemisphere degree',
186
            'help' => 'Degree representation. Format: hemisphere abbreviation (single character N S E or W) - degrees (real, any precision). Convert to degrees using algorithm.',
187
        ],
188
        'urn:ogc:def:uom:EPSG::9118' => [
189
            'name' => 'degree minute hemisphere',
190
            'help' => 'Degree representation. Format: degrees (integer) - arc-minutes (real, any precision) - hemisphere abbreviation (single character N S E or W). Different symbol sets are in use as field separators, for example º \'. Convert to degrees using algorithm.',
191
        ],
192
        'urn:ogc:def:uom:EPSG::9119' => [
193
            'name' => 'hemisphere degree minute',
194
            'help' => 'Degree representation. Format:  hemisphere abbreviation (single character N S E or W) - degrees (integer) - arc-minutes (real, any precision). Different symbol sets are in use as field separators, for example º \'. Convert to degrees using algorithm.',
195
        ],
196
        'urn:ogc:def:uom:EPSG::9120' => [
197
            'name' => 'hemisphere degree minute second',
198
            'help' => 'Degree representation. Format: hemisphere abbreviation (single character N S E or W) - degrees (integer) - arc-minutes (integer) - arc-seconds (real). Different symbol sets are in use as field separators for example º \' ". Convert to deg using algorithm.',
199
        ],
200
    ];
201
202
    abstract public function __construct(float $angle);
203
204
    abstract public function asRadians(): Radian;
205
206 1054
    public function asDegrees(): Degree
207
    {
208 1054
        return new Degree($this->asRadians()->getValue() * 180 / M_PI);
209
    }
210
211 260
    public function add(self $unit): self
212
    {
213 260
        if ($this::class === $unit::class) {
214 189
            return new static($this->getValue() + $unit->getValue());
215
        }
216 80
        $resultAsRadians = new Radian($this->asRadians()->getValue() + $unit->asRadians()->getValue());
217 80
        $conversionRatio = (new static(1))->asRadians()->getValue();
218
219 80
        return new static($resultAsRadians->getValue() / $conversionRatio);
220
    }
221
222 639
    public function subtract(self $unit): self
223
    {
224 639
        if ($this::class === $unit::class) {
225 531
            return new static($this->getValue() - $unit->getValue());
226
        }
227 113
        $resultAsRadians = new Radian($this->asRadians()->getValue() - $unit->asRadians()->getValue());
228 113
        $conversionRatio = (new static(1))->asRadians()->getValue();
229
230 113
        return new static($resultAsRadians->getValue() / $conversionRatio);
231
    }
232
233 42
    public function multiply(float $multiplicand): self
234
    {
235 42
        return new static($this->getValue() * $multiplicand);
236
    }
237
238 36
    public function divide(float $divisor): self
239
    {
240 36
        return new static($this->getValue() / $divisor);
241
    }
242
243
    /**
244
     * @param float|string $measurement
245
     */
246 1067
    public static function makeUnit($measurement, string $srid): self
247
    {
248
        switch ($srid) {
249 1067
            case self::EPSG_RADIAN:
250
                return new Radian($measurement);
0 ignored issues
show
Bug introduced by
It seems like $measurement can also be of type string; however, parameter $angle of PHPCoord\UnitOfMeasure\Angle\Radian::__construct() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

250
                return new Radian(/** @scrutinizer ignore-type */ $measurement);
Loading history...
251 1067
            case self::EPSG_MICRORADIAN:
252 18
                return new Radian($measurement / 1000000);
253 1067
            case self::EPSG_DEGREE:
254 991
                return new Degree($measurement);
0 ignored issues
show
Bug introduced by
It seems like $measurement can also be of type string; however, parameter $angle of PHPCoord\UnitOfMeasure\Angle\Degree::__construct() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
                return new Degree(/** @scrutinizer ignore-type */ $measurement);
Loading history...
255 255
            case self::EPSG_ARC_SECOND:
256 175
                return new ArcSecond($measurement);
0 ignored issues
show
Bug introduced by
It seems like $measurement can also be of type string; however, parameter $angle of PHPCoord\UnitOfMeasure\A...rcSecond::__construct() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

256
                return new ArcSecond(/** @scrutinizer ignore-type */ $measurement);
Loading history...
257 108
            case self::EPSG_MILLIARC_SECOND:
258 9
                return new ArcSecond($measurement / 1000);
259 99
            case self::EPSG_GRAD:
260 18
                return new Grad($measurement);
0 ignored issues
show
Bug introduced by
It seems like $measurement can also be of type string; however, parameter $angle of PHPCoord\UnitOfMeasure\Angle\Grad::__construct() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

260
                return new Grad(/** @scrutinizer ignore-type */ $measurement);
Loading history...
261 81
            case self::EPSG_CENTESIMAL_SECOND:
262
                return new Radian($measurement * M_PI / 2000000);
263 81
            case self::EPSG_DEGREE_MINUTE_SECOND:
264
                return Degree::fromDegreeMinuteSecond((string) $measurement);
265 81
            case self::EPSG_DEGREE_MINUTE_SECOND_HEMISPHERE:
266
                return Degree::fromDegreeMinuteSecondHemisphere((string) $measurement);
267 81
            case self::EPSG_HEMISPHERE_DEGREE_MINUTE_SECOND:
268
                return Degree::fromHemisphereDegreeMinuteSecond((string) $measurement);
269 81
            case self::EPSG_DEGREE_MINUTE:
270
                return Degree::fromDegreeMinute((string) $measurement);
271 81
            case self::EPSG_DEGREE_MINUTE_HEMISPHERE:
272
                return Degree::fromDegreeMinuteHemisphere((string) $measurement);
273 81
            case self::EPSG_HEMISPHERE_DEGREE_MINUTE:
274
                return Degree::fromHemisphereDegreeMinute((string) $measurement);
275 81
            case self::EPSG_DEGREE_HEMISPHERE:
276
                return Degree::fromDegreeHemisphere((string) $measurement);
277 81
            case self::EPSG_HEMISPHERE_DEGREE:
278
                return Degree::fromHemisphereDegree((string) $measurement);
279 81
            case self::EPSG_SEXAGESIMAL_DMS:
280 72
                return Degree::fromSexagesimalDMS((string) $measurement);
281
        }
282
283 9
        throw new UnknownUnitOfMeasureException($srid);
284
    }
285
286 986
    public static function convert(self $angle, string $targetSRID): self
287
    {
288 986
        $conversionRatio = static::makeUnit(1, $targetSRID)->asRadians()->getValue();
289
290 986
        return self::makeUnit($angle->asRadians()->getValue() / $conversionRatio, $targetSRID);
291
    }
292
293
    /**
294
     * @return array<string, string>
295
     */
296 27
    public static function getSupportedSRIDs(): array
297
    {
298 27
        return array_map(fn ($supportedSrid) => $supportedSrid['name'], self::$sridData);
299
    }
300
301
    /**
302
     * @return array<string, array{name: string, help: string}>
303
     */
304 9
    public static function getSupportedSRIDsWithHelp(): array
305
    {
306 9
        return array_map(fn (array $data) => [
307 9
            'name' => $data['name'],
308 9
            'help' => $data['help'],
309 9
        ], static::$sridData);
310
    }
311
312 36
    public function __toString(): string
313
    {
314 36
        return (string) $this->getValue();
315
    }
316
}
317