Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 119 |
|
0.00% |
0 / 13 |
CRAP | |
0.00% |
0 / 1 |
MapSourcesTransform | |
0.00% |
0 / 119 |
|
0.00% |
0 / 13 |
2450 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getValues | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
deg2rad | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
rad2deg | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getCentralMeridian | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getUTMZone | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
182 | |||
getMeridianDistance | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
getTM | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
72 | |||
getUTM | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getUTM33 | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getOSGB36 | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
42 | |||
getCH1903 | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
getNZTM | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | /* |
3 | * Convert latitude and longitude geographical coordinates to |
4 | * Transverse Mercator coordinates. |
5 | * |
6 | * @package MediaWiki |
7 | * @subpackage Extensions |
8 | * |
9 | * @author Egil Kvaleberg <egil@kvaleberg.no> |
10 | * @copyright Copyright © 2005, Egil Kvaleberg <egil@kvaleberg.no> |
11 | * @author Roger W Haworth |
12 | * @copyright Copyright © 2005, Roger W Haworth |
13 | * @author wikipedia:de:Benutzer:Meleager |
14 | * @copyright Copyright © 2005, wikipedia:de:Benutzer:Meleager |
15 | * |
16 | * @author Roland Unger |
17 | * |
18 | * @copyright Copyright © 2007, Roland Unger |
19 | * |
20 | * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License |
21 | * 2.0 or later |
22 | * |
23 | * ---------------------------------------------------------------------- |
24 | * |
25 | * See also: |
26 | * http://www.posc.org/Epicentre.2_2/DataModel/ExamplesofUsage/eu_cs34h.html |
27 | * http://kanadier.gps-info.de/d-utm-gitter.htm |
28 | * http://www.gpsy.com/gpsinfo/geotoutm/ |
29 | * http://www.colorado.edu/geography/gcraft/notes/gps/gps_f.html |
30 | * http://search.cpan.org/src/GRAHAMC/Geo-Coordinates-UTM-0.05/ |
31 | * UK Ordnance Survey grid (OSBG36): http://www.gps.gov.uk/guidecontents.asp |
32 | * Swiss CH1903: http://www.gps.gov.uk/guidecontents.asp |
33 | * |
34 | * ---------------------------------------------------------------------- |
35 | * |
36 | * This program is free software; you can redistribute it and/or modify |
37 | * it under the terms of the GNU General Public License as published by |
38 | * the Free Software Foundation; either version 2 of the License, or |
39 | * (at your option) any later version. |
40 | * |
41 | * This program is distributed in the hope that it will be useful, |
42 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
43 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
44 | * GNU General Public License for more details. |
45 | * |
46 | * You should have received a copy of the GNU General Public License |
47 | * along with this program; if not, write to the Free Software |
48 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
49 | */ |
50 | |
51 | namespace MediaWiki\Extension\MapSources; |
52 | |
53 | class MapSourcesTransform { |
54 | public $lat = 0; |
55 | public $long = 0; |
56 | |
57 | public $ellWGS84 = [ |
58 | 'maxAxis' => 6378137.0, |
59 | 'minAxis' => 6356752.315, |
60 | 'ecc' => 0.081819190843, |
61 | 'eccSquared' => 0.006694379990, |
62 | 'flattening' => 0.003352810665, |
63 | 'invFlattening' => 298.257223563 |
64 | ]; |
65 | public $ellAiry1830 = [ |
66 | 'maxAxis' => 6377563.396, |
67 | 'minAxis' => 6356256.909, |
68 | 'ecc' => 0.081673374328, |
69 | 'eccSquared' => 0.006670540074, |
70 | 'flattening' => 0.003340850640, |
71 | 'invFlattening' => 299.3249647 |
72 | ]; |
73 | public $ellBessel1841 = [ |
74 | 'maxAxis' => 6377397.155, |
75 | 'minAxis' => 6356078.965, |
76 | 'ecc' => 0.081696829804, |
77 | 'eccSquared' => 0.006674372, |
78 | 'flattening' => 0.003342773182, |
79 | 'invFlattening' => 299.1528128 |
80 | ]; |
81 | |
82 | public $utm = [ |
83 | 'easting' => 0, |
84 | 'northing' => 0, |
85 | 'error' => -1, |
86 | 'zone' => 0, |
87 | 'zoneLetter' => '', |
88 | 'centralMeridian' => 0, |
89 | 'scale' => 0.9996, |
90 | 'eastingOffset' => 500000.0, |
91 | 'northingOffset' => 0.0, |
92 | 'northingOffsetSouth' => 10000000.0 |
93 | ]; |
94 | public $utm33; |
95 | public $osgb36 = [ |
96 | 'easting' => 0, |
97 | 'northing' => 0, |
98 | 'ref' => '', |
99 | 'error' => -1, |
100 | 'scale' => 0.9996013, |
101 | 'eastingOffset' => 400000.0, |
102 | 'northingOffset' => -100000.0, |
103 | 'northingOffsetSouth' => 0.0 |
104 | ]; |
105 | public $ch1903 = [ |
106 | 'easting' => 0, |
107 | 'northing' => 0, |
108 | 'error' => -1 |
109 | ]; |
110 | public $nztm = [ |
111 | 'easting' => 0, |
112 | 'northing' => 0, |
113 | 'error' => -1, |
114 | 'scale' => 0.9996, |
115 | 'eastingOffset' => 1600000.0, |
116 | 'northingOffset' => 0.0, |
117 | 'northingOffsetSouth' => 10000000.0 |
118 | ]; |
119 | |
120 | public function __construct( $lat, $long ) { |
121 | $this->getValues( $lat, $long ); |
122 | } |
123 | |
124 | protected function getValues( $lat, $long ) { |
125 | if ( $lat < -90 || $lat > 90 || $long <= -180 || $long > 180 ) { |
126 | return false; |
127 | } |
128 | |
129 | $this->lat = $lat; |
130 | $this->long = $long; |
131 | |
132 | $this->utm33 = $this->utm; |
133 | $this->utm33['zone'] = 33; |
134 | |
135 | $this->getUTM( $this->utm ); |
136 | $this->getUTM33( $this->utm33 ); |
137 | $this->getOSGB36( $this->osgb36 ); |
138 | $this->getCH1903( $this->ch1903 ); |
139 | $this->getNZTM( $this->nztm ); |
140 | |
141 | return true; |
142 | } |
143 | |
144 | protected function deg2rad( $deg ) { |
145 | return $deg * M_PI / 180; |
146 | } |
147 | |
148 | protected function rad2deg( $rad ) { |
149 | return $rad * 180 / M_PI; |
150 | } |
151 | |
152 | protected function getCentralMeridian( $zone ) { |
153 | return ( $zone * 6.0 ) - 183.0; |
154 | } |
155 | |
156 | # Code by Egil Kvaleberg <egil@kvaleberg.no> |
157 | protected function getUTMZone( &$utmArray ) { |
158 | if ( $this->long >= 180 ) { |
159 | $long = $this->long - 360; |
160 | } else { |
161 | $long = $this->long; |
162 | } |
163 | |
164 | if ( $this->lat >= 56.0 && $this->lat < 64.0 && $long >= 3.0 && $long < 12.0 ) { |
165 | $utmArray['zone'] = 32; |
166 | } elseif ( $this->lat >= 72.0 && $this->lat < 84.0 && $long >= 0.0 && $long < 42.0 ) { |
167 | if ( $long < 9.0 ) { |
168 | $utmArray['zone'] = 31; |
169 | } elseif ( $long < 21.0 ) { |
170 | $utmArray['zone'] = 33; |
171 | } elseif ( $long < 33.0 ) { |
172 | $utmArray['zone'] = 35; |
173 | } else { |
174 | $utmArray['zone'] = 37; |
175 | } |
176 | } else { |
177 | $utmArray['zone'] = floor( ( $long + 180.0 ) / 6 ) + 1; |
178 | } |
179 | |
180 | $c = (int)( ( $this->lat + 96 ) / 8 ); |
181 | /* 000000000011111111112222 */ |
182 | /* 012345678901234567890134 */ |
183 | $utmArray['zoneLetter'] = substr( 'CCCDEFGHJKLMNPQRSTUVWXXX', $c, 1 ); |
184 | |
185 | $utmArray['centralMeridian'] = $this->getCentralMeridian( $utmArray['zone'] ); |
186 | } |
187 | |
188 | # Code by Egil Kvaleberg <egil@kvaleberg.no> |
189 | protected function getMeridianDistance( $radius, $lat, $e2 ) { |
190 | $e4 = $e2 * $e2; |
191 | $e6 = $e4 * $e2; |
192 | |
193 | return $radius * ( |
194 | ( 1 - $e2 / 4 - 3 * $e4 / 64 - 5 * $e6 / 256 ) * $lat |
195 | - ( 3 * $e2 / 8 + 3 * $e4 / 32 + 45 * $e6 / 1024 ) * sin( 2 * $lat ) |
196 | + ( 15 * $e4 / 256 + 45 * $e6 / 1024 ) * sin( 4 * $lat ) |
197 | - ( 35 * $e6 / 3072 ) * sin( 6 * $lat ) |
198 | ); |
199 | } |
200 | |
201 | # Code by Egil Kvaleberg <egil@kvaleberg.no> |
202 | protected function getTM( $latOrigin, $longOrigin, &$utmArray, &$model ) { |
203 | if ( $this->lat < -80 || $this->lat > 84 || $this->long < -180 || $this->long > 180 ) { |
204 | $utmArray['error'] = -1; |
205 | return false; |
206 | } |
207 | |
208 | if ( $this->long >= 180 ) { |
209 | $long = $this->long - 360; |
210 | } else { |
211 | $long = $this->long; |
212 | } |
213 | |
214 | $lat = $this->deg2rad( $this->lat ); |
215 | $long = $this->deg2rad( $long ); |
216 | $latOrig = $this->deg2rad( $latOrigin ); |
217 | $longOrig = $this->deg2rad( $longOrigin ); |
218 | |
219 | $sinLat = sin( $lat ); |
220 | $sin2Lat = $sinLat * $sinLat; |
221 | $cosLat = cos( $lat ); |
222 | $cos2Lat = $cosLat * $cosLat; |
223 | $tanLat = $sinLat / $cosLat; |
224 | $tan2Lat = $tanLat * $tanLat; |
225 | |
226 | $e2 = $model['eccSquared']; |
227 | $e2pr = $e2 / ( 1 - $e2 ); |
228 | $radius = $model['maxAxis']; |
229 | |
230 | $v = $radius / sqrt( 1 - $e2 * $sin2Lat ); |
231 | $t = $tan2Lat; |
232 | $c = $e2pr * $cos2Lat; |
233 | $a = ( $long - $longOrig ) * $cosLat; |
234 | $m = $this->getMeridianDistance( $radius, $lat, $e2 ); |
235 | |
236 | if ( $latOrigin != 0 ) { |
237 | $m0 = $this->getMeridianDistance( $radius, $latOrig, $e2 ); |
238 | } else { |
239 | $m0 = 0.0; |
240 | } |
241 | |
242 | $utmArray['northing'] = $utmArray['northingOffset'] + |
243 | $utmArray['scale'] * ( ( $m - $m0 ) + $v * $tanLat * ( |
244 | $a * $a / 2 + ( 5 - $t + 9 * $c + 4 * $c * $c ) * pow( $a, 4 ) / 24 |
245 | + ( 61 - 58 * $t + $t * $t + 600 * $c - 330 * $e2pr ) * pow( $a, 6 ) / 720 |
246 | ) ); |
247 | |
248 | if ( $this->lat < 0 ) { |
249 | $utmArray['northing'] += $utmArray['northingOffsetSouth']; |
250 | } |
251 | |
252 | $utmArray['easting'] = $utmArray['eastingOffset'] + |
253 | $utmArray['scale'] * $v * ( |
254 | $a + ( 1 - $t + $c ) * pow( $a, 3 ) / 6 |
255 | + ( 5 - 18 * $t + pow( $t, 2 ) + 72 * $c - 58 * $e2pr ) * pow( $a, 5 ) / 120 |
256 | ); |
257 | |
258 | $utmArray['error'] = 0; |
259 | |
260 | return true; |
261 | } |
262 | |
263 | protected function getUTM( &$utmArray ) { |
264 | $this->getUTMZone( $utmArray ); |
265 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset |
266 | return $this->getTM( 0.0, $utmArray['centralMeridian'], $utmArray, $this->ellWGS84 ); |
267 | } |
268 | |
269 | protected function getUTM33( &$utmArray ) { |
270 | $utmArray['zone'] = 33; |
271 | $utmArray['zoneLetter'] = 'V'; |
272 | $utmArray['centralMeridian'] = $this->getCentralMeridian( 33 ); |
273 | return $this->getTM( 0.0, $utmArray['centralMeridian'], $utmArray, $this->ellWGS84 ); |
274 | } |
275 | |
276 | # Code by Egil Kvaleberg <egil@kvaleberg.no> |
277 | # Fix by Roger W Haworth |
278 | |
279 | protected function getOSGB36( &$utmArray ) { |
280 | $this->getUTMZone( $utmArray ); |
281 | if ( !$this->getTM( 49.0, -2.0, $utmArray, $this->ellAiry1830 ) ) { |
282 | return false; |
283 | } |
284 | |
285 | # fix by Roger W Haworth |
286 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset |
287 | $gridX = floor( $utmArray['easting'] / 100000 ); |
288 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset |
289 | $gridY = floor( $utmArray['northing'] / 100000 ); |
290 | |
291 | # outside area for OSGB36 |
292 | if ( $gridX < 0 || $gridX > 6 || $gridY < 0 || $gridY > 12 ) { |
293 | $utmArray['error'] = -1; |
294 | return false; |
295 | } |
296 | |
297 | /* 0000000000111111111122222 */ |
298 | /* 0123456789012345678901234 */ |
299 | $letters = 'ABCDEFGHJKLMNOPQRSTUVWXYZ'; |
300 | |
301 | $c1 = substr( $letters, ( 17 - intval( $gridY / 5 ) * 5 ) + intval( $gridX / 5 ), 1 ); |
302 | $c2 = substr( $letters, ( 20 - ( $gridY % 5 ) * 5 ) + $gridX % 5, 1 ); |
303 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset |
304 | $e = sprintf( "%05d", $utmArray['easting'] % 100000 ); |
305 | // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset |
306 | $n = sprintf( "%05d", $utmArray['northing'] % 100000 ); |
307 | |
308 | $utmArray['error'] = 0; |
309 | $utmArray['ref'] = $c1 . $c2 . $e . $n; |
310 | |
311 | return true; |
312 | } |
313 | |
314 | # Code by [[wikipedia:de:Benutzer:Meleager]] |
315 | protected function getCH1903( &$ch1903Array ) { |
316 | # outside reasonable range |
317 | if ( $this->lat < 45.5 || $this->lat > 48 || $this->long < 5.0 || $this->long > 11 ) { |
318 | return false; |
319 | } |
320 | |
321 | # Approximation formula according to |
322 | # http://www.swisstopo.ch/pub/down/basics/geo/system/swiss_projection_de.pdf |
323 | # chapter 4.1, page 11. |
324 | $pp = ( $this->lat * 3600 - 169028.66 ) / 10000; |
325 | $pp2 = $pp * $pp; |
326 | $lp = ( $this->long * 3600 - 26782.5 ) / 10000; |
327 | $lp2 = $lp * $lp; |
328 | |
329 | $ch1903Array['northing'] = 200147.07 + 308807.95 * $pp + 3745.25 * $lp2 + |
330 | 76.63 * $pp2 - 194.56 * $lp2 * $pp + 119.79 * $pp2 * $pp; |
331 | $ch1903Array['easting'] = 600072.37 + 211455.93 * $lp - 10938.51 * $lp * $pp - |
332 | 0.36 * $lp * $pp2 - 44.54 * $lp2 * $lp; |
333 | $ch1903Array['error'] = 0; |
334 | |
335 | return true; |
336 | } |
337 | |
338 | # New Zealand Geodetic Datum 2000 (NZGD2000) |
339 | # See also http://www.linz.govt.nz/core/surveysystem/geodeticinfo/geodeticdatums/ |
340 | # Northernmost point - Nugent Island, in the Kermadec Islands: -29° S |
341 | # Southernmost point - Jacquemart Island (off the south coast of Campbell Island) |
342 | # in the Campbell Island group: -53° S |
343 | # Westernmost point - Cape Lovitt, Auckland Islands: 165° E |
344 | # Easternmost point - Kahuitara Point, Pitt Island, in the Chatham Islands: 178° E |
345 | protected function getNZTM( &$utmArray ) { |
346 | # outside reasonable range |
347 | if ( $this->lat > -29.0 || $this->lat < -53.0 || $this->long > 178.0 || $this->long < 165.0 ) { |
348 | return false; |
349 | } |
350 | return $this->getTM( 0.0, 173.0, $utmArray, $this->ellWGS84 ); |
351 | } |
352 | } |