Extension:Coorconv
From MediaWiki.org
|
Release status: beta |
|
|---|---|
| Implementation | Parser function |
| Description | conversion of WGS84 coordinates to various national coordinate systems |
| Last version | 0.5.1 |
| License | No license specified |
| Download | No link |
| Example | Scoutpedia.nl - nl.scoutwiki.org |
|
Check usage (experimental) |
|
|
|
This extension stores its code inside a wiki page. Please be aware that MediaWiki developers do not review or keep track of extensions that put their code on the wiki.
|
Contents |
[edit] What can this extension do?
Conversion of WGS84 coordinates to the national coordinate systems of:
- the Netherlands - Rijksdriehoekscoördinaten, RD
- France - Lambert93
- Belgium - Lambert2008
- Suisse - CH1903
- Finland - TM35FIN, extended UTM zone 35N
- Canada - MTM, SCOPQ
- Great Britain - OSGB36
- Republic Ireland and North Ireland - Irish Transverse Mercator
- Luxembourg - LUREF
Conversion of (WGS84) geographical coordinates to Universal Transverse Mercator (UTM)
Internal functions for
- transverse Mercator projection (WGS84)
- transverse Mercator projection (other mapdata)
- Lambert projection
- Datumtransformation
[edit] Usage
- {{#lat_deg2dms: latitude }} geographic coordinates in decimal degree notation to degrees-minutes-seconds notation
- {{#long_deg2dms: longitude }}
- {{#lat_dms2deg: degrees | minutes | seconds | hemisphere }} geographic coordinates in degrees-minutes-seconds notation to decimal degree notation
- {{#long_dms2deg: degrees | minutes | seconds | hemisphere }}
- {{#lat_long2utm: latitude | longitude | zone (optional) }} - WGS84 Latitude/Longitude to UTM
- {{#wgs84_2rd: latitude | longitude }} - WGS84 Latitude/Longitude to RD - the Netherlands
- {{#wgs84_2lb93: latitude | longitude }} - WGS84 Latitude/Longitude to Lambert93 - France
- {{#wgs84_2lb08: latitude | longitude }} - WGS84 Latitude/Longitude to Lambert2008 - Belgium
- {{#wgs84_2ch03: latitude | longitude }} - WGS84 Latitude/Longitude to CH1903 - Suisse
- {{#wgs84_2tm35fin: latitude | longitude }} - WGS84 Latitude/Longitude to TM35FIN = extended UTM zone 35N - Finland
- {{#wgs84_2mtm: latitude | longitude | zone (optional) }} - WGS84 Latitude/Longitude to MTM - Canada (SCOPQ in Quebec)
- {{#wgs84_2osgb: latitude | longitude }} - WGS84 Latitude/Longitude to OSGB36 - Great Britain
- {{#wgs84_2itm: latitude | longitude }} - WGS84 Latitude/Longitude to Irish Transverse Mercator- Republic Ireland and North Ireland
- {{#wgs84_2luref: latitude | longitude }} - WGS84 Latitude/Longitude to LUREF - Luxembourg
[edit] Installation
To install this extension, add the following to LocalSettings.php:
require_once("$IP/extensions/Coorconv/Coorconv.php");
[edit] Code
<?php # Alert the user that this is not a valid entry point to MediaWiki if they try to access the special pages file directly. if (!defined('MEDIAWIKI')) { echo <<<EOT To install this extension, put the following line in LocalSettings.php: require_once( "\$IP/extensions/Coorconv/Coorconv.php" ); EOT; exit( 1 ); } $wgExtensionCredits['parserhook'][] = array( 'name' => 'Coorconv', 'author' => 'Wouter Rademaker', 'url' => 'http://www.mediawiki.org/Extension:Coorconv', 'description' => 'Some functions for conversion of geographical coordinates', // 'descriptionmsg' => 'myextension-desc', 'version' => '0.5.1', ); # Define a setup function $wgExtensionFunctions[] = 'efCoorconv_ParserFunction_Init'; # Add a hook to initialise the magic word $wgHooks['LanguageGetMagic'][] = 'efCoorconv_ParserFunction_Magic'; function efCoorconv_ParserFunction_Init() { global $wgParser; $wgParser->setFunctionHook( 'lat_deg2dms', 'latDegToDMS' ); $wgParser->setFunctionHook( 'lat_dms2deg', 'latDMSToDeg' ); $wgParser->setFunctionHook( 'long_deg2dms', 'longDegToDMS' ); $wgParser->setFunctionHook( 'long_dms2deg', 'longDMSToDeg' ); $wgParser->setFunctionHook( 'wgs84_2rd', 'WGS84ToRD' ); $wgParser->setFunctionHook( 'wgs84_2lb93', 'WGS84ToLAM93' ); $wgParser->setFunctionHook( 'wgs84_2lb08', 'WGS84ToLAM08' ); $wgParser->setFunctionHook( 'wgs84_2ch03', 'WGS84ToCH1903' ); $wgParser->setFunctionHook( 'lat_long2utm', 'WGS84ToUTM' ); $wgParser->setFunctionHook( 'wgs84_2itm', 'WGS84ToITM' ); $wgParser->setFunctionHook( 'wgs84_2tm35fin', 'WGS84ToTM35FIN' ); $wgParser->setFunctionHook( 'wgs84_2mtm', 'WGS84ToMTM' ); $wgParser->setFunctionHook( 'wgs84_2osgb', 'WGS84ToOSGB36' ); $wgParser->setFunctionHook( 'wgs84_2ig', 'WGS84ToIG' ); $wgParser->setFunctionHook( 'wgs84_2luref', 'WGS84ToLUREF' ); return true; } function efCoorconv_ParserFunction_Magic( &$magicWords, $langCode ) { $magicWords['lat_deg2dms'] = array( 0, 'lat_deg2dms' ); $magicWords['lat_dms2deg'] = array( 0, 'lat_dms2deg' ); $magicWords['long_deg2dms'] = array( 0, 'long_deg2dms' ); $magicWords['long_dms2deg'] = array( 0, 'long_dms2deg' ); $magicWords['wgs84_2rd'] = array( 0, 'wgs84_2rd' ); $magicWords['wgs84_2lb93'] = array( 0, 'wgs84_2lb93' ); $magicWords['wgs84_2lb08'] = array( 0, 'wgs84_2lb08' ); $magicWords['wgs84_2ch03'] = array( 0, 'wgs84_2ch03' ); $magicWords['lat_long2utm'] = array( 0, 'lat_long2utm' ); $magicWords['wgs84_2itm'] = array( 0, 'wgs84_2itm' ); $magicWords['wgs84_2tm35fin'] = array( 0, 'wgs84_2tm35fin' ); $magicWords['wgs84_2mtm'] = array( 0, 'wgs84_2mtm' ); $magicWords['wgs84_2osgb'] = array( 0, 'wgs84_2osgb' ); $magicWords['wgs84_2ig'] = array( 0, 'wgs84_2ig' ); $magicWords['wgs84_2luref'] = array( 0, 'wgs84_2luref' ); return true; } function latDegToDMS( &$parser, $degrees ) { $h = $degrees < 0 ? 'S' : 'N'; $degrees = round( abs($degrees) * 360000, 0 ) % 32400000; $d = $degrees / 360000; $degrees %= 360000; $m = $degrees / 6000; $degrees %= 6000; $s = $degrees / 100; return DMS( $d, $m, $s, $h ); } function latDMSToDeg( &$parser, $d, $m, $s, $h ) { $degrees = ($d * 3600 + $m * 60 + $s) / 3600.0 * ($h == 'N' ? 1 : -1); return $degrees; } function longDegToDMS( &$parser, $degrees ) { $h = $degrees < 0 ? 'W' : 'E'; $degrees = round( abs($degrees) * 360000, 0 ) % 64800000; $d = $degrees / 360000; $degrees %= 360000; $m = $degrees / 6000; $degrees %= 6000; $s = $degrees / 100; return DMS( $d, $m, $s, $h ); } function longDMSToDeg( &$parser, $d, $m, $s, $h ) { $degrees = ($d * 3600 + $m * 60 + $s) / 3600.0 * ($h == 'W' ? -1 : 1); return $degrees; } function DMS( $d, $m, $s, $h ) { // prime (minutes, feet) = U+2032, ′, ′ // double prime (seconds, inches) = U+2033, ″, ″ return sprintf( "%d° %02d′ %04.1f″ %s", $d, $m, $s, $h ); } function WGS84ToLAM93( &$parser, $x, $y ) { // WGS84 Latitude/Longitude to Lambert93 - France // based on http://professionnels.ign.fr/DISPLAY/000/526/695/5266956/Geodesie__projections.pdf $LB93['a'] = 6378137; //demi grand axe de l'ellipsoide (m) $LB93['e'] = 0.08181919106 ; //premire excentricit de l'ellipsoide $LB93['phi_1'] = deg2rad(44); //1er parallele automcoque $LB93['phi_2'] = deg2rad(49); //2eme parallele automcoque $LB93['phi_0'] = deg2rad(46.5); //latitude d'origine en radian $LB93['lambda_0']= deg2rad(3); //longitude de rfrence $LB93['x_0'] = 700000; //coordonnes l'origine $LB93['y_0'] = 6600000; //coordonnes l'origine return WGS84ToLAM($LB93, $x, $y ); } function WGS84ToLAM08( &$parser, $x, $y ) { // WGS84 Latitude/Longitude to Lambert2008 - Belgium // based on http://www.ngi.be/Common/Lambert2008/Transformation_Geographic_Lambert_NL.pdf $LB08['a'] = 6378137; //demi grand axe de l'ellipsoide (m) $LB08['e'] = 0.08181919106 ; //premire excentricit de l'ellipsoide $LB08['phi_1'] = deg2rad(49.833333333);//1er parallele automcoque (49° 50' N) $LB08['phi_2'] = deg2rad(51.166666667);//2eme parallele automcoque ( 51° 10' N) $LB08['phi_0'] = deg2rad(50.797815); //latitude d'origine en radian (50°47’52”134 N) $LB08['lambda_0']= deg2rad(4.359215833);//longitude de rfrence (4°21’33”177 E) $LB08['x_0'] = 649328; //coordonnes l'origine $LB08['y_0'] = 665262; //coordonnes l'origine return WGS84ToLAM($LB08, $x, $y ); } function WGS84ToLAM($LAM,$x, $y ) { // Lambert projection // based on http://www.ngi.be/Common/Lambert2008/Transformation_Geographic_Lambert_NL.pdf extract($LAM); $m_1 = cos($phi_1) / sqrt(1 - pow($e * sin($phi_1),2)); $m_2 = cos($phi_2) / sqrt(1 - pow($e * sin($phi_2),2)); $t_1 = tan(M_PI / 4 - $phi_1 / 2) / pow((1 - $e * sin($phi_1)) / (1 + $e * sin($phi_1)), $e / 2); $t_2 = tan(M_PI / 4 - $phi_2 / 2) / pow((1 - $e * sin($phi_2)) / (1 + $e * sin($phi_2)), $e / 2); $t_0 = tan(M_PI / 4 - $phi_0 / 2) / pow((1 - $e * sin($phi_0)) / (1 + $e * sin($phi_0)), $e / 2); $n = (log($m_1) - log($m_2)) / (log($t_1) - log($t_2)); $g = $m_1 / ($n * pow($t_1, $n)); $r_0 = $a * $g * pow($t_0, $n); $phi = $x / 180 * M_PI; $lambda = $y / 180 * M_PI; $t = tan(M_PI / 4 - $phi / 2) / pow((1 - $e * sin($phi)) / (1 + $e * sin($phi)), $e / 2); $r = $a * $g * pow($t, $n); $theta = $n * ($lambda - $lambda_0); $x_LAM = $x_0 + $r * sin($theta); $y_LAM = $y_0 + $r_0 - $r * cos($theta); return sprintf("%d/%d", $x_LAM, $y_LAM); } function WGS84ToCH1903( &$parser, $x, $y ) { // WGS84 Latitude/Longitude to CH1903 - Suisse // based on http://www.swisstopo.admin.ch/internet/swisstopo/en/home/topics/survey/sys/refsys/switzerland.parsysrelated1.37696.downloadList.12749.DownloadFile.tmp/ch1903wgs84en.pdf // http://www.swisstopo.admin.ch/internet/swisstopo/en/home/apps/calc/navref.html $phi=(($x*3600)-169028.66)/10000; $lambda=(($y*3600)-26782.5)/10000; $y_ch03 = 600072.37 + 211455.93 * $lambda - 10938.51 * $lambda * $phi - 0.36 * $lambda * $phi * $phi - 44.54 * $lambda * $lambda * $lambda; $x_ch03 = 200147.07 + 308807.95 * $phi + 3745.25 * $lambda * $lambda + 76.63 * $phi * $phi - 194.56 * $phi * $lambda * $lambda + 119.79 * $phi * $phi * $phi; return number_format($x_ch03, 0, '.', '/') ."//" .number_format($y_ch03, 0, '.', '/'); } function WGS84ToRD( &$parser, $x, $y ) { // WGS84 Latitude/Longitude to RD - the Netherlands // based on http://www.dekoepel.nl/pdf/Transformatieformules.pdf $phi = 0.36 * ($x - 52.15517440); $lambda = 0.36 * ($y - 5.38720621); $x_rd = 155000 + 190094.945 * $lambda - 11832.228 * $lambda * $phi - 114.221 * $lambda * $phi * $phi - 32.391 * $lambda * $lambda * $lambda - 0.705 * $phi - 2.340 * $phi * $phi * $phi * $lambda - 0.608 * $phi * $lambda * $lambda * $lambda - 0.008 * $lambda * $lambda + 0.148 * $phi * $phi * $lambda * $lambda * $lambda; $y_rd = 463000 + 309056.544 * $phi + 3638.893 * $lambda * $lambda + 73.077 * $phi * $phi - 157.984 * $phi * $lambda * $lambda + 59.788 * $phi *$phi * $phi + 0.433 * $lambda - 6.439 * $phi * $phi * $lambda * $lambda - 0.032 * $phi * $lambda + 0.092 * $lambda * $lambda * $lambda * $lambda - 0.054 * $phi * $lambda * $lambda * $lambda * $lambda; // return sprintf("%06d%06d",$x_rd, $y_rd); return number_format($x_rd/1000, 2) ."-" .number_format($y_rd/1000, 2); } function WGS84ToUTM( &$parser, $phi_d, $lambda_d, $zone='') { // WGS84 Latitude/Longitude to UTM // Based on http://www.igorexchange.com/node/927 and http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html $bandletter = array ("C","D","E","F","G","H","J","K","L","N","P","Q","R","S","T","U","V","W","X","X"); $TMScaleFactor = 0.9996; if ( $phi_d >= 84 || $phi_d <= -80) return "Polar area, use Universal Polar Stereographic (UPS)"; // Special zone for Norway if(!$zone && $phi_d >= 56.0 && $phi_d < 64.0 && $lambda_d >= 3.0 && $lambda_d < 12.0 ) $zone = 32; // Special zones for Svalbard if(!$zone && $phi_d >= 72.0 && $phi_d < 84.0) if ( $lambda_d >= 0.0 && $lambda_d < 9.0 ) $zone = 31; elseif( $lambda_d >= 9.0 && $lambda_d < 21.0 ) $zone = 33; elseif($lambda_d >= 21.0 && $lambda_d < 33.0 ) $zone = 35; elseif($lambda_d >= 33.0 && $lambda_d < 42.0 ) $zone = 37; if (!$zone) $zone = floor($lambda_d/6) + 31; $band = $bandletter[floor(($phi_d+72)/8)]; $lambda0 = deg2rad(-183.0 + ($zone * 6.0)); $lambda=deg2rad($lambda_d); $l = $lambda - $lambda0; $phi=deg2rad($phi_d); $xy = TM($phi, $l); $x_tm = $xy[0]*$TMScaleFactor + 500000; $y_tm = $xy[1]*$TMScaleFactor; if($phi_d < 0) $y_tm += 10000000; //10000000 meter offset for southern hemisphere return sprintf("%d%s %dm E %dm N",$zone,$band, $x_tm, $y_tm); } function WGS84ToTM35FIN( &$parser, $phi_d, $lambda_d) { // WGS84 Latitude/Longitude to TM35FIN = extended UTM zone 35N - Finland // Based on http://www.samenland.nl/pdf/the_change_of_coordinate_system_in_finland.pdf $TMScaleFactor = 0.9996; $lambda0 = deg2rad(27); //UTM 35N $lambda=deg2rad($lambda_d); $l = $lambda - $lambda0; $phi=deg2rad($phi_d); $xy = TM($phi, $l); $x_tm = $xy[0]*$TMScaleFactor + 500000; $y_tm = $xy[1]*$TMScaleFactor; if ($x_tm < 0) return sprintf(" %dE, %dN",$x_tm + 8000000, $y_tm); else return sprintf("(8)%dm E %dm N",$x_tm, $y_tm); } function WGS84ToMTM( &$parser, $phi_d, $lambda_d, $zone='') { // WGS84 Latitude/Longitude to MTM Canada // Based on http://pages.globetrotter.net/roule/utmgoogle.htm // MTM zone to reference meridian $mtmSmers = array (0, -53, -56, -58.5, -61.5, -64.5, -67.5, -70.5, -73.5, -76.5, -79.5, -82.5, -81, -84, -87, -90, -93, -96, -99, -102, -105, -108, -111, -114, -117, -120, -123, -126, -129, -132, -135, -138, -141); // last was 142 ?!! I think it should be 141. // ? matches http://www.posc.org/Epicentre.2_2/DataModel/LogicalDictionary/StandardValues/coordinate_transformation.html if (!$zone) // determine zone from lat/lon { if ($lambda_d < -51.5 && $lambda_d >= -54.5) $zone=1; if ($lambda_d < -54.5 && $lambda_d >= -57.5) $zone=2; if ($lambda_d < -57.5 && $lambda_d >= -59.5 && $phi_d <= 46.5 || $lambda_d < -57.5 && $lambda_d >= -60 && $phi_d > 46.5 ) $zone=3; if ($lambda_d < -59.5 && $lambda_d >= -63. && $phi_d < 46.5 || $lambda_d < -60 && $lambda_d >= -63 && $phi_d >= 46.5 ) $zone=4; if ($lambda_d < -63 && $lambda_d >= -66.5 && $phi_d <= 44.75 || $lambda_d < -63 && $lambda_d >= -66 && $phi_d > 44.75 ) $zone=5; if ($lambda_d < -66 && $lambda_d >= -69 && $phi_d > 44.75 || $lambda_d < -66.5 && $lambda_d >= -69 && $phi_d <= 44.75 ) $zone=6; if ($lambda_d < -69 && $lambda_d >= -72) $zone=7; if ($lambda_d < -72 && $lambda_d >= -75) $zone=8; if ($lambda_d < -75 && $lambda_d >= -78) $zone=9; if ($lambda_d < -78 && $lambda_d >= -79.5 && $phi_d > 47 || $lambda_d < -78. && $lambda_d >= -80.25 && $phi_d <= 47 && $phi_d > 46 || $lambda_d < -78 && $lambda_d >= -81 && $phi_d <= 46) $zone=10; if ($lambda_d < -81 && $lambda_d >= -84 && $phi_d <= 46) $zone=11; if ($lambda_d < -79.5 && $lambda_d >= -82.5 && $phi_d > 47 || $lambda_d < -80.25&& $lambda_d >= -82.5 && $phi_d <= 47 && $phi_d > 46) $zone=12; if ($lambda_d < -82.5 && $lambda_d >= -85.5 && $phi_d > 46) $zone=13; // still not found, try regular Western Canada if (!$zone) $zone = floor(($lambda_d + 85.5)/-3) + 14; } if ($zone < 1 || $zone > 32) return "Outside Canada"; else $lambda0 = $mtmSmers[$zone]; $l = deg2rad($lambda_d - $lambda0); $phi=deg2rad($phi_d); $xy = TM($phi, $l); $TMScaleFactor = 0.9999; $x_tm = $xy[0]*$TMScaleFactor + 304800; $y_tm = $xy[1]*$TMScaleFactor; return sprintf("%d %dm E %dm N",$zone, $x_tm, $y_tm); } function TM($phi, $l) { // transverse Mercator projection // Based on http://www.igorexchange.com/node/927 and http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html $sm_a = 6378137.0; $sm_b = 6356752.314; // $ep2 = ($sm_a * $sm_a - $sm_b * $sm_b) / ($sm_b * $sm_b); $ep2 = 0.00673949681993606; $nu2 = $ep2 * pow(cos($phi), 2.0); $N = pow ($sm_a, 2.0) / ($sm_b * sqrt(1 + $nu2)); $t = tan ($phi); $t2= $t * $t; $l3coef = 1.0 - $t2 + $nu2; $l4coef = 5.0 - $t2 + 9 * $nu2 + 4.0 * ($nu2 * $nu2); $l5coef = 5.0 - 18.0 * $t2 + ($t2 * $t2) + 14.0 * $nu2 - 58.0 * $t2 * $nu2; $l6coef = 61.0 - 58.0 * $t2 + ($t2 * $t2) + 270.0 * $nu2 - 330.0 * $t2 * $nu2; $l7coef = 61.0 - 479.0 * $t2 + 179.0 * ($t2 * $t2) - ($t2 * $t2 * $t2); $l8coef = 1385.0 - 3111.0 * $t2 + 543.0 * ($t2 * $t2) - ($t2 * $t2 * $t2); $x = $N * cos($phi) * $l + ($N / 6.0 * pow(cos($phi), 3.0) * $l3coef * pow($l, 3.0)) + ($N / 120.0 * pow(cos($phi), 5.0) * $l5coef * pow($l, 5.0)) + ($N / 5040.0 * pow(cos($phi), 7.0) * $l7coef * pow($l, 7.0)); /* $nn = ($sm_a - $sm_b) / ($sm_a + $sm_b); $alpha = (($sm_a + $sm_b) / 2.0) * (1.0 + (pow($nn, 2.0) / 4.0) + (pow($nn, 4.0) / 64.0)); $beta = (-3.0 * $nn / 2.0) + (9.0 * pow($nn, 3.0) / 16.0) + (-3.0 * pow($nn, 5.0) / 32.0); $gamma = (15.0 * pow($nn, 2.0) / 16.0) + (-15.0 * pow($nn, 4.0) / 32.0); $delta = (-35.0 * pow($nn, 3.0) / 48.0) + (105.0 * pow($nn, 5.0) / 256.0); $epsilon = (315.0 * pow($nn, 4.0) / 512.0); $length = $alpha * ($phi + ($beta * sin(2.0 * $phi)) + ($gamma * sin(4.0 * $phi)) + ($delta * sin(6.0 * $phi)) + ($epsilon * sin(8.0 * $phi))); */ $length = 6367449.14570093 * ($phi - 2.51882794504748e-3 * sin(2.0 * $phi) + 2.64354112052895e-6 * sin(4.0 * $phi) - 3.45262354148954e-9 * sin(6.0 * $phi) + 4.89183055303118E-12 * sin(8.0 * $phi)); $y = $length + ($t / 2.0 * $N * pow(cos($phi), 2.0) * pow($l, 2.0)) + ($t / 24.0 * $N * pow(cos($phi), 4.0) * $l4coef * pow($l, 4.0)) + ($t / 720.0 * $N * pow(cos($phi), 6.0) * $l6coef * pow($l, 6.0)) + ($t / 40320.0 * $N * pow(cos($phi), 8.0) * $l8coef * pow($l, 8.0)); $ret = array($x,$y); return($ret); } function WGS84ToOSGB36( &$parser, $phi_d, $lambda_d, $height = 0) { // WGS84 Latitude/Longitude to OSGB36 - Great Britain // Based on http://www.movable-type.co.uk/scripts/latlong-convert-coords.html $WGS84['a'] = 6378137; $WGS84['b'] = 6356752.3142; // $WGS84['f'] = 1/298.257223563; $Airy1830['a'] = 6377563.396; $Airy1830['b'] = 6356256.910; // $Airy1830['f'] = 1/299.3249646; $WGS84toOSGB36['tx']= -446.448; $WGS84toOSGB36['ty']= 125.157; $WGS84toOSGB36['tz']= -542.060; $WGS84toOSGB36['rx']= -0.1502; $WGS84toOSGB36['ry']= -0.2470; $WGS84toOSGB36['rz']= -0.8421; $WGS84toOSGB36['s']= 20.4894; $originOSGB36['F0'] = 0.9996012717; // NatGrid scale factor on central meridian $originOSGB36['phi0'] = deg2rad(49); $originOSGB36['lambda0'] = deg2rad(-2); // NatGrid true origin $originOSGB36['N0'] = -100000; $originOSGB36['E0'] = 400000; // northing & easting of true origin, metres $point['phi'] = deg2rad($phi_d); $point['lambda'] = deg2rad($lambda_d); $point['height'] = $height; $point = datumtransformation($point, $WGS84, $WGS84toOSGB36, $Airy1830); $grid = LatLongToOSGrid($point,$Airy1830,$originOSGB36); // level 1 transformation // $grid = LatLongToOSGrid($point,$WGS84,$originOSGB36); // $grid['E'] += 49; // $grid['N'] -= 23.4; return gridrefNumToLetGB($grid, 8); } function WGS84ToIG( &$parser, $phi_d, $lambda_d, $height = 0) { // WGS84 Latitude/Longitude to Irish Grid - Republic Ireland and North Ireland // Based on http://www.movable-type.co.uk/scripts/latlong-convert-coords.html // Based on http://www.osni.gov.uk/2.1_the_irish_grid.pdf $WGS84['a'] = 6378137; $WGS84['b'] = 6356752.3142; // $WGS84['f'] = 1/298.257223563; $Airy1830_m['a']= 6377340.189; $Airy1830_m['b']= 6356034.447; // $Airy1830_m['f']= ; $WGS84toOSI['tx']= -482.53; $WGS84toOSI['ty']= 130.596; $WGS84toOSI['tz']= -564.557; $WGS84toOSI['rx']= -1.042; $WGS84toOSI['ry']= -0.214; $WGS84toOSI['rz']= -0.631; $WGS84toOSI['s']= -8.15; $originOSI['F0'] = 1.000035; // NatGrid scale factor on central meridian $originOSI['phi0'] = deg2rad(53.5); $originOSI['lambda0'] = deg2rad(-8); // NatGrid true origin $originOSI['N0'] = 250000; $originOSI['E0'] = 200000; // northing & easting of true origin, metres $point['phi'] = deg2rad($phi_d); $point['lambda'] = deg2rad($lambda_d); $point['height'] = $height; // $point = datumtransformation($point, $WGS84, $WGS84toOSI, $Airy1830_m); // $grid = LatLongToOSGrid($point,$Airy1830_m,$originOSI); // level 1 transformation $grid = LatLongToOSGrid($point,$WGS84,$originOSI); $grid['E'] += 49; $grid['N'] -= 23.4; return gridrefNumToLetIG($grid, 8); } function WGS84ToITM( &$parser, $phi_d, $lambda_d) { // WGS84 Latitude/Longitude to ITM Ireland (doesn't work yet !!!!!!!!!!!!!!) $WGS84['a'] = 6378137; $WGS84['b'] = 6356752.3142; $originITM['F0'] = 0.999820; // NatGrid scale factor on central meridian $originITM['phi0'] = deg2rad(53.5); $originITM['lambda0'] = deg2rad(-8); // NatGrid true origin $originITM['N0'] = 750000; $originITM['E0'] = 600000; // northing & easting of true origin, metres $point['phi'] = deg2rad($phi_d); $point['lambda'] = deg2rad($lambda_d); $grid = LatLongToOSGrid($point,$WGS84,$originITM); return sprintf("%dm E %dm N",$grid['E'], $grid['N']); } function WGS84ToLUREF( &$parser, $phi_d, $lambda_d) { // WGS84 Latitude/Longitude to LUREF - Luxembourg // Based on http://www.act.etat.lu/datum.html $HAYFORD24['a'] = 6378388; $HAYFORD24['b'] = 6356911.946; $originLUREF['F0'] = 1; // scale factor on central meridian $originLUREF['phi0'] = deg2rad(49 + 50/60); $originLUREF['lambda0'] = deg2rad(6 + 10/60); // NatGrid true origin $originLUREF['N0'] = 100000; $originLUREF['E0'] = 80000; // northing & easting of true origin, metres // no datumtransformation needed, Luxembourg is small enough $point['phi'] = deg2rad($phi_d); $point['lambda'] = deg2rad($lambda_d); $grid = LatLongToOSGrid($point,$HAYFORD24,$originLUREF); extract($grid); return sprintf("%dm E %dm N",$E, $N); } function datumtransformation($point, $e1, $t, $e2) { // Based on http://www.movable-type.co.uk/scripts/latlong-convert-coords.html // -- convert polar to cartesian coordinates (using ellipse 1) extract($point); $sinPhi = sin($phi); $cosPhi = cos($phi); $sinLambda = sin($lambda); $cosLambda = cos($lambda); extract($e1); $eSq = ($a*$a - $b*$b) / ($a*$a); $nu = $a / sqrt(1 - $eSq*$sinPhi*$sinPhi); $x1 = ($nu+$height) * $cosPhi * $cosLambda; $y1 = ($nu+$height) * $cosPhi * $sinLambda; $z1 = ((1-$eSq)*$nu + $height) * $sinPhi; // -- apply helmert transform using appropriate params extract($t); // normalise seconds to radians $rx = deg2rad($rx/3600); $ry = deg2rad($ry/3600); $rz = deg2rad($rz/3600); $s1 = $s/1e6 + 1; // normalise ppm to (s+1) // apply transform $x2 = $tx + $x1*$s1 - $y1*$rz + $z1*$ry; $y2 = $ty + $x1*$rz + $y1*$s1 - $z1*$rx; $z2 = $tz - $x1*$ry + $y1*$rx + $z1*$s1; // -- convert cartesian to polar coordinates (using ellipse 2) extract($e2); $precision = 4 / $a; // results accurate to around 4 metres $eSq = ($a*$a - $b*$b) / ($a*$a); $p = sqrt($x2*$x2 + $y2*$y2); $phi = atan2($z2, $p*(1-$eSq)); $phiP = 2*M_PI; while (abs($phi-$phiP) > $precision) { $nu = $a / sqrt(1 - $eSq*sin($phi)*sin($phi)); $phiP = $phi; $phi = atan2($z2 + $eSq*$nu*sin($phi), $p); } $point['phi'] = $phi; $point['lambda'] = atan2($y2, $x2); $point['height'] = $p/cos($phi) - $nu; return $point; } /* * convert geodesic co-ordinates to OS grid reference (transverse Mercator projection) */ function LatLongToOSGrid($point,$ellipse,$origin) { // Based on http://www.movable-type.co.uk/scripts/latlong-gridref.html extract($point); extract($ellipse); extract($origin); $e2 = 1 - ($b*$b)/($a*$a); // eccentricity squared $n = ($a-$b)/($a+$b); $n2 = $n*$n; $n3 = $n*$n*$n; $cosLat = cos($phi); $sinLat = sin($phi); $nu = $a*$F0/sqrt(1-$e2*$sinLat*$sinLat); // transverse radius of curvature $rho = $a*$F0*(1-$e2)/pow(1-$e2*$sinLat*$sinLat, 1.5); // meridional radius of curvature $eta2 = $nu/$rho-1; $Ma = (1 + $n + (5/4)*$n2 + (5/4)*$n3) * ($phi-$phi0); $Mb = (3*$n + 3*$n*$n + (21/8)*$n3) * sin($phi-$phi0) * cos($phi+$phi0); $Mc = ((15/8)*$n2 + (15/8)*$n3) * sin(2*($phi-$phi0)) * cos(2*($phi+$phi0)); $Md = (35/24)*$n3 * sin(3*($phi-$phi0)) * cos(3*($phi+$phi0)); $M = $b * $F0 * ($Ma - $Mb + $Mc - $Md); // meridional arc $cos3lat = $cosLat*$cosLat*$cosLat; $cos5lat = $cos3lat*$cosLat*$cosLat; $tan2lat = tan($phi)*tan($phi); $tan4lat = $tan2lat*$tan2lat; $I = $M + $N0; $II = ($nu/2)*$sinLat*$cosLat; $III = ($nu/24)*$sinLat*$cos3lat*(5-$tan2lat+9*$eta2); $IIIA = ($nu/720)*$sinLat*$cos5lat*(61-58*$tan2lat+$tan4lat); $IV = $nu*$cosLat; $V = ($nu/6)*$cos3lat*($nu/$rho-$tan2lat); $VI = ($nu/120) * $cos5lat * (5 - 18*$tan2lat + $tan4lat + 14*$eta2 - 58*$tan2lat*$eta2); $dLon = $lambda-$lambda0; $dLon2 = $dLon*$dLon; $dLon3 = $dLon2*$dLon; $dLon4 = $dLon3*$dLon; $dLon5 = $dLon4*$dLon; $dLon6 = $dLon5*$dLon; $Grid['N'] = $I + $II*$dLon2 + $III*$dLon4 + $IIIA*$dLon6; $Grid['E'] = $E0 + $IV*$dLon + $V*$dLon3 + $VI*$dLon5; return $Grid; } /* * convert numeric grid reference (in metres) to standard-form grid ref */ function gridrefNumToLetGB($Grid, $digits) { // Based on http://www.movable-type.co.uk/scripts/latlong-gridref.html extract($Grid); // get the 100km-grid indices $e100k = floor($E/100000); $n100k = floor($N/100000); if ($e100k<0 || $e100k>6 || $n100k<0 || $n100k>12) return ''; // translate those into numeric equivalents of the grid letters $l1 = (19-$n100k) - (19-$n100k)%5 + floor(($e100k+10)/5); $l2 = (19-$n100k)*5%25 + $e100k%5; // compensate for skipped 'I' and build grid letter-pairs if ($l1 > 7) $l1++; if ($l2 > 7) $l2++; $letPair = chr($l1+ord('A')).chr($l2+ord('A')); // strip 100km-grid indices from easting & northing, and reduce precision $e = floor(($E%100000)/pow(10,5-$digits/2)); $n = floor(($N%100000)/pow(10,5-$digits/2)); switch ($digits) { case 2: return sprintf("%s %'01d %'01d",$letPair, $e, $n); break; case 4: return sprintf("%s %'02d %'02d",$letPair, $e, $n); break; case 6: return sprintf("%s %'03d %'03d",$letPair, $e, $n); break; case 10: return sprintf("%s %'05d %'05d",$letPair, $e, $n); break; default: return sprintf("%s %'04d %'04d",$letPair, $e, $n); } } function gridrefNumToLetIG($Grid, $digits) { // Based on http://www.movable-type.co.uk/scripts/latlong-gridref.html extract($Grid); // get the 100km-grid indices $e100k = floor($E/100000); $n100k = floor($N/100000); if ($e100k<0 || $e100k>5 || $n100k<0 || $n100k>5) return ''; // translate those into numeric equivalents of the grid letter $l = (4-$n100k)*5 + $e100k; // compensate for skipped 'I' if ($l > 7) $l++; $let = chr($l+ord('A')); // strip 100km-grid indices from easting & northing, and reduce precision $e = floor(($E%100000)/pow(10,5-$digits/2)); $n = floor(($N%100000)/pow(10,5-$digits/2)); switch ($digits) { case 2: return sprintf("%s %'01d %'01d",$let, $e, $n); break; case 4: return sprintf("%s %'02d %'02d",$let, $e, $n); break; case 6: return sprintf("%s %'03d %'03d",$let, $e, $n); break; case 10: return sprintf("%s %'05d %'05d",$let, $e, $n); break; default: return sprintf("%s %'04d %'04d",$let, $e, $n); } }
