Passed
Push — master ( 8bd5c3...1e8670 )
by Doug
62:22
created

Angle::getSupportedSRIDsWithHelp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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