Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
MapSourcesMath
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 6
5700
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 newCoord
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
 setCoord
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 getDMSString
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
210
 getErrorMsg
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 toDec
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
1260
1<?php
2/*
3 * Adds new math parser functions
4 *
5 * @package MediaWiki
6 * @subpackage Extensions
7 *
8 * @author Roland Unger
9 * @copyright Copyright © 2007 – 2012 Roland Unger
10 *
11 * @license https://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
12 */
13
14namespace MediaWiki\Extension\MapSources;
15
16class MapSourcesMath {
17
18    /** @var int */
19    public $dec;
20
21    /** @var string 'long' (E-W), 'lat' */
22    public $dir;
23
24    /** @var int */
25    public $prec;
26
27    /** @var int */
28    public $step;
29
30    /** @var int */
31    public $error;
32
33    /** @var array */
34    public $coord = [];
35
36    public function __construct( $input, $precision = 4, $dir = '', $untilStep = 1 ) {
37        $this->newCoord( $input, $precision, $dir );
38        if ( $untilStep > 1 && $this->error == 0 ) {
39            $this->setCoord();
40        }
41    }
42
43    protected function newCoord( $input, $precision = 4, $dir = '' ) {
44        if ( $dir == 'lat' || $dir == 'long' ) {
45            $this->dir = $dir;
46        } else {
47            $this->dir = '';
48        }
49
50        $p = intval( $precision );
51        if ( $p >= -1 && $p < 10 ) {
52            $this->prec = $p;
53        } else {
54            $this->prec = 4;
55        }
56        if ( $precision == -1 ) {
57            $this->prec = 9;
58        }
59
60        $this->dec = 0;
61        $this->step = 0;
62        $this->error = $this->toDec( $input );
63    }
64
65    protected function setCoord() {
66        if ( $this->step > 1 ) {
67            return true;
68        }
69        if ( $this->prec < 9 ) {
70            $this->coord['dec'] = round( $this->dec, $this->prec );
71        } else {
72            $this->coord['dec'] = $this->dec;
73        }
74
75        if ( $this->dec < 0 ) {
76            $sign = -1;
77        } else {
78            $sign = 1;
79        }
80        $angle = abs( $this->dec );
81        $deg = floor( $angle );
82        $min = ( $angle - $deg ) * 60;
83
84        if ( $this->prec > 4 ) {
85            $sec = round( ( $min - floor( $min ) ) * 60, $this->prec - 4 );
86        } else {
87            $sec = round( ( $min - floor( $min ) ) * 60 );
88        }
89        $min = floor( $min );
90        if ( $sec >= 60 ) {
91            $sec -= 60;
92            $min++;
93        }
94        if ( $this->prec < 3 && $sec >= 30 ) {
95            $min++;
96        }
97        if ( $this->prec < 3 ) {
98            $sec = 0;
99        }
100        if ( $min >= 60 ) {
101            $min -= 60;
102            $deg++;
103        }
104        if ( $this->prec < 1 && $min >= 30 ) {
105            $deg++;
106        }
107        if ( $this->prec < 1 ) {
108            $min = 0;
109        }
110
111        $this->coord['dec'] = round( $this->dec, $this->prec );
112        $this->coord['deg'] = $deg * $sign;
113        $this->coord['min'] = $min;
114        $this->coord['sec'] = $sec;
115
116        if ( $sign > 0 ) {
117            $this->coord['NS'] = 'N';
118            $this->coord['EW'] = 'E';
119        } else {
120            $this->coord['NS'] = 'S';
121            $this->coord['EW'] = 'W';
122        }
123
124        $this->step = 2;
125
126        return true;
127    }
128
129    public function getDMSString( $plus = '', $minus = '' ) {
130        if ( $this->step < 2 ) {
131            $this->setCoord();
132        }
133
134        $deg = $this->coord['deg'];
135        if ( $this->dec < 0 && ( $this->dir != '' || $minus != '' ) ) {
136            $deg = abs( $deg );
137        }
138
139        $result = $deg . '°';
140        if ( $this->prec > 0 ) {
141            $result .= ' ' . $this->coord['min'] . "'";
142        }
143        if ( $this->prec > 2 ) {
144            $result .= ' ' . $this->coord['sec'] . '&quot;';
145        }
146
147        $letter = '';
148        if ( $this->dir == 'lat' ) {
149            $letter = $this->coord['NS'];
150        }
151        if ( $this->dir == 'long' ) {
152            $letter = $this->coord['EW'];
153        }
154        if ( $this->dec > 0 && $plus <> '' ) {
155            $letter = $plus;
156        }
157        if ( $this->dec < 0 && $minus <> '' ) {
158            $letter = $minus;
159        }
160        if ( $letter != '' ) {
161            $result .= ' ' . $letter;
162        }
163
164        return $result;
165    }
166
167    protected function getErrorMsg() {
168        $msg = [ 'no error', 'no parameter(s)', 'to many parameters', 'illegal characters',
169            'to many numeric parameters', 'degree out of range', 'minute out of range',
170            'degree no integer', 'second out of range', 'minute no integer',
171            'direction not last parameter', 'invalid negative value', 'wrong direction',
172            'latitude out of range', 'unknown error' ];
173
174        $e = -$this->error;
175        $c = count( $msg );
176
177        if ( $e >= 0 && $e < ( $c - 1 ) ) {
178            return $msg[$e];
179        } else {
180            return $msg[$c - 1] . ': ' . $this->error;
181        }
182    }
183
184    protected function toDec( $input = '' ) {
185        $units = [ '°', "'", '"', ' ' ];
186
187        if ( $input == '' ) {
188            return -1;
189        }
190
191        $w = str_replace( [ '‘', '’', '′' ], "'", $input );
192        $w = str_replace( [ "''", '“', '”', '″' ], '"', $w );
193        $w = str_replace( '−', '-', $w );
194        $w = strtoupper( str_replace( [ '_', '/', "\t", "\n", "\r" ], ' ', $w ) );
195        $w = str_replace( [ '°', "'", '"' ], [ '° ', "' ", '" ' ], $w );
196        $w = trim( str_replace( [ 'N', 'S', 'E', 'W' ], [ ' N', ' S', ' E', ' W' ], $w ) );
197        $w = preg_split( "/[\s]+/", $w, 5, PREG_SPLIT_NO_EMPTY );
198
199        $c = count( $w );
200        if ( $c < 1 || $c > 4 ) {
201            return -2;
202        }
203        $res = [ 0, 0, 0, 1 ];
204
205        for ( $i = 0; $i < $c; $i++ ) {
206            $v = $w[$i];
207            $pos = strpos( $v, $units[$i] );
208            if ( $pos > 0 ) {
209                $v = substr( $v, 0, $pos );
210            }
211            if ( is_numeric( $v ) ) {
212                if ( $i > 2 ) {
213                    return -4;
214                }
215
216                switch ( $i ) {
217                    case 0:
218                        if ( $v <= -180 || $v > 180 ) {
219                            return -5;
220                        }
221
222                        $res[0] = $v;
223                        break;
224                    case 1:
225                        if ( $v < 0 || $v >= 60 ) {
226                            return -6;
227                        }
228                        if ( $res[0] != intval( $res[0] ) ) {
229                            return -7;
230                        }
231
232                        $res[1] = $v;
233                        break;
234                    case 2:
235                        if ( $v < 0 || $v >= 60 ) {
236                            return -8;
237                        }
238                        if ( $res[1] != intval( $res[1] ) ) {
239                            return -9;
240                        }
241
242                        $res[2] = $v;
243                        break;
244                }
245            } else {
246                if ( $i != $c - 1 ) {
247                    return -10;
248                }
249                if ( $res[0] < 0 ) {
250                    return -11;
251                }
252
253                /** @phan-suppress-next-line PhanParamSuspiciousOrder */
254                $pos = strpos( 'NSEW', $v );
255                if ( strlen( $v ) != 1 || $pos === false ) {
256                    return -3;
257                }
258
259                switch ( $this->dir ) {
260                    case 'long':
261                        if ( $pos < 2 ) {
262                            return -12;
263                        }
264                        break;
265                    case 'lat':
266                        if ( $pos > 1 ) {
267                            return -12;
268                        }
269                        break;
270                    default:
271                        if ( $pos < 2 ) {
272                            $this->dir = 'lat';
273                        } else {
274                            $this->dir = 'long';
275                        }
276                }
277
278                if ( $this->dir == 'lat' && ( $res[0] < -90 || $res[0] > 90 ) ) {
279                    return -13;
280                }
281
282                if ( $v == 'S' || $v == 'W' ) {
283                    $res[3] = -1;
284                }
285            }
286        }
287
288        if ( $res[0] >= 0 ) {
289            $v = ( $res[0] + $res[1] / 60 + $res[2] / 3600 ) * $res[3];
290        } else {
291            $v = ( $res[0] - $res[1] / 60 - $res[2] / 3600 ) * $res[3];
292        }
293
294        $this->dec = $v;
295        $this->step = 1;
296
297        return 0;
298    }
299}