Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 119
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
MapSourcesTransform
0.00% covered (danger)
0.00%
0 / 119
0.00% covered (danger)
0.00%
0 / 13
2450
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getValues
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 deg2rad
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 rad2deg
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCentralMeridian
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUTMZone
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
182
 getMeridianDistance
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getTM
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
72
 getUTM
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getUTM33
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getOSGB36
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 getCH1903
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 getNZTM
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
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
51namespace MediaWiki\Extension\MapSources;
52
53class 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}