Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 157 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
MapSourcesMath | |
0.00% |
0 / 157 |
|
0.00% |
0 / 6 |
5700 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
newCoord | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 | |||
setCoord | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
210 | |||
getDMSString | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
210 | |||
getErrorMsg | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
toDec | |
0.00% |
0 / 70 |
|
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 | |
14 | namespace MediaWiki\Extension\MapSources; |
15 | |
16 | class 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'] . '"'; |
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 | } |