From 63633da4997dfd9a1bf134e78bed1c11dde13db8 Mon Sep 17 00:00:00 2001
From: Jon Atkins
Date: Fri, 6 Jun 2014 21:17:00 +0100
Subject: [PATCH] phpcoord - osgb to lat/lng conversion, from
http://www.jstott.me.uk/phpcoord/
---
.../plugin-rpc/tfl/phpcoord/phpcoord-2.3.php | 773 ++++++++++++++++++
.../plugin-rpc/tfl/phpcoord/readme-2.3.txt | 60 ++
website/plugin-rpc/tfl/phpcoord/test-2.3.php | 206 +++++
3 files changed, 1039 insertions(+)
create mode 100644 website/plugin-rpc/tfl/phpcoord/phpcoord-2.3.php
create mode 100644 website/plugin-rpc/tfl/phpcoord/readme-2.3.txt
create mode 100644 website/plugin-rpc/tfl/phpcoord/test-2.3.php
diff --git a/website/plugin-rpc/tfl/phpcoord/phpcoord-2.3.php b/website/plugin-rpc/tfl/phpcoord/phpcoord-2.3.php
new file mode 100644
index 00000000..b69d21af
--- /dev/null
+++ b/website/plugin-rpc/tfl/phpcoord/phpcoord-2.3.php
@@ -0,0 +1,773 @@
+toSixFigureString() so that the eastings and northings
+ // are rounded rather than floored.
+ // 2.2 - 11 Feb 2006
+ // - Used different algorithm for calculating distance between latitudes
+ // and longitudes - fixes a number of problems with distance calculations
+ // 2.1 - 22 Dec 2005
+ // - Added getOSRefFromSixFigureReference function
+ // 2.0 - 21 Dec 2005
+ // - Completely different object design - conversion functions now through
+ // objects rather than static functions
+ // - Updated comments and documentation
+ // 1.1 - 11 Sep 2005
+ // - Added OSGB36/WGS84 data conversions
+ // 1.0 - 11 Aug 2005
+ // - Initial version
+ //--------------------------------------------------------------------------
+
+
+ // ================================================================== LatLng
+
+ class LatLng {
+
+ var $lat;
+ var $lng;
+
+
+ /**
+ * Create a new LatLng object from the given latitude and longitude
+ *
+ * @param lat latitude
+ * @param lng longitude
+ */
+ function LatLng($lat, $lng) {
+ $this->lat = $lat;
+ $this->lng = $lng;
+ }
+
+
+ /**
+ * Return a string representation of this LatLng object
+ *
+ * @return a string representation of this LatLng object
+ */
+ function toString() {
+ return "(" . $this->lat . ", " . $this->lng . ")";
+ }
+
+
+ /**
+ * Calculate the surface distance between this LatLng object and the one
+ * passed in as a parameter.
+ *
+ * @param to a LatLng object to measure the surface distance to
+ * @return the surface distance
+ */
+ function distance($to) {
+ $er = 6366.707;
+
+ $latFrom = deg2rad($this->lat);
+ $latTo = deg2rad($to->lat);
+ $lngFrom = deg2rad($this->lng);
+ $lngTo = deg2rad($to->lng);
+
+ $x1 = $er * cos($lngFrom) * sin($latFrom);
+ $y1 = $er * sin($lngFrom) * sin($latFrom);
+ $z1 = $er * cos($latFrom);
+
+ $x2 = $er * cos($lngTo) * sin($latTo);
+ $y2 = $er * sin($lngTo) * sin($latTo);
+ $z2 = $er * cos($latTo);
+
+ $d = acos(sin($latFrom)*sin($latTo) + cos($latFrom)*cos($latTo)*cos($lngTo-$lngFrom)) * $er;
+
+ return $d;
+ }
+
+
+ /**
+ * Convert this LatLng object from OSGB36 datum to WGS84 datum.
+ */
+ function OSGB36ToWGS84() {
+ $airy1830 = new RefEll(6377563.396, 6356256.909);
+ $a = $airy1830->maj;
+ $b = $airy1830->min;
+ $eSquared = $airy1830->ecc;
+ $phi = deg2rad($this->lat);
+ $lambda = deg2rad($this->lng);
+ $v = $a / (sqrt(1 - $eSquared * sinSquared($phi)));
+ $H = 0; // height
+ $x = ($v + $H) * cos($phi) * cos($lambda);
+ $y = ($v + $H) * cos($phi) * sin($lambda);
+ $z = ((1 - $eSquared) * $v + $H) * sin($phi);
+
+ $tx = 446.448;
+ $ty = -124.157;
+ $tz = 542.060;
+ $s = -0.0000204894;
+ $rx = deg2rad( 0.00004172222);
+ $ry = deg2rad( 0.00006861111);
+ $rz = deg2rad( 0.00023391666);
+
+ $xB = $tx + ($x * (1 + $s)) + (-$rx * $y) + ($ry * $z);
+ $yB = $ty + ($rz * $x) + ($y * (1 + $s)) + (-$rx * $z);
+ $zB = $tz + (-$ry * $x) + ($rx * $y) + ($z * (1 + $s));
+
+ $wgs84 = new RefEll(6378137.000, 6356752.3141);
+ $a = $wgs84->maj;
+ $b = $wgs84->min;
+ $eSquared = $wgs84->ecc;
+
+ $lambdaB = rad2deg(atan($yB / $xB));
+ $p = sqrt(($xB * $xB) + ($yB * $yB));
+ $phiN = atan($zB / ($p * (1 - $eSquared)));
+ for ($i = 1; $i < 10; $i++) {
+ $v = $a / (sqrt(1 - $eSquared * sinSquared($phiN)));
+ $phiN1 = atan(($zB + ($eSquared * $v * sin($phiN))) / $p);
+ $phiN = $phiN1;
+ }
+
+ $phiB = rad2deg($phiN);
+
+ $this->lat = $phiB;
+ $this->lng = $lambdaB;
+ }
+
+
+ /**
+ * Convert this LatLng object from WGS84 datum to OSGB36 datum.
+ */
+ function WGS84ToOSGB36() {
+ $wgs84 = new RefEll(6378137.000, 6356752.3141);
+ $a = $wgs84->maj;
+ $b = $wgs84->min;
+ $eSquared = $wgs84->ecc;
+ $phi = deg2rad($this->lat);
+ $lambda = deg2rad($this->lng);
+ $v = $a / (sqrt(1 - $eSquared * sinSquared($phi)));
+ $H = 0; // height
+ $x = ($v + $H) * cos($phi) * cos($lambda);
+ $y = ($v + $H) * cos($phi) * sin($lambda);
+ $z = ((1 - $eSquared) * $v + $H) * sin($phi);
+
+ $tx = -446.448;
+ $ty = 124.157;
+ $tz = -542.060;
+ $s = 0.0000204894;
+ $rx = deg2rad(-0.00004172222);
+ $ry = deg2rad(-0.00006861111);
+ $rz = deg2rad(-0.00023391666);
+
+ $xB = $tx + ($x * (1 + $s)) + (-$rx * $y) + ($ry * $z);
+ $yB = $ty + ($rz * $x) + ($y * (1 + $s)) + (-$rx * $z);
+ $zB = $tz + (-$ry * $x) + ($rx * $y) + ($z * (1 + $s));
+
+ $airy1830 = new RefEll(6377563.396, 6356256.909);
+ $a = $airy1830->maj;
+ $b = $airy1830->min;
+ $eSquared = $airy1830->ecc;
+
+ $lambdaB = rad2deg(atan($yB / $xB));
+ $p = sqrt(($xB * $xB) + ($yB * $yB));
+ $phiN = atan($zB / ($p * (1 - $eSquared)));
+ for ($i = 1; $i < 10; $i++) {
+ $v = $a / (sqrt(1 - $eSquared * sinSquared($phiN)));
+ $phiN1 = atan(($zB + ($eSquared * $v * sin($phiN))) / $p);
+ $phiN = $phiN1;
+ }
+
+ $phiB = rad2deg($phiN);
+
+ $this->lat = $phiB;
+ $this->lng = $lambdaB;
+ }
+
+
+ /**
+ * Convert this LatLng object into an OSGB grid reference. Note that this
+ * function does not take into account the bounds of the OSGB grid -
+ * beyond the bounds of the OSGB grid, the resulting OSRef object has no
+ * meaning
+ *
+ * @return the converted OSGB grid reference
+ */
+ function toOSRef() {
+ $airy1830 = new RefEll(6377563.396, 6356256.909);
+ $OSGB_F0 = 0.9996012717;
+ $N0 = -100000.0;
+ $E0 = 400000.0;
+ $phi0 = deg2rad(49.0);
+ $lambda0 = deg2rad(-2.0);
+ $a = $airy1830->maj;
+ $b = $airy1830->min;
+ $eSquared = $airy1830->ecc;
+ $phi = deg2rad($this->lat);
+ $lambda = deg2rad($this->lng);
+ $E = 0.0;
+ $N = 0.0;
+ $n = ($a - $b) / ($a + $b);
+ $v = $a * $OSGB_F0 * pow(1.0 - $eSquared * sinSquared($phi), -0.5);
+ $rho =
+ $a * $OSGB_F0 * (1.0 - $eSquared) * pow(1.0 - $eSquared * sinSquared($phi), -1.5);
+ $etaSquared = ($v / $rho) - 1.0;
+ $M =
+ ($b * $OSGB_F0)
+ * (((1 + $n + ((5.0 / 4.0) * $n * $n) + ((5.0 / 4.0) * $n * $n * $n))
+ * ($phi - $phi0))
+ - (((3 * $n) + (3 * $n * $n) + ((21.0 / 8.0) * $n * $n * $n))
+ * sin($phi - $phi0)
+ * cos($phi + $phi0))
+ + ((((15.0 / 8.0) * $n * $n) + ((15.0 / 8.0) * $n * $n * $n))
+ * sin(2.0 * ($phi - $phi0))
+ * cos(2.0 * ($phi + $phi0)))
+ - (((35.0 / 24.0) * $n * $n * $n)
+ * sin(3.0 * ($phi - $phi0))
+ * cos(3.0 * ($phi + $phi0))));
+ $I = $M + $N0;
+ $II = ($v / 2.0) * sin($phi) * cos($phi);
+ $III =
+ ($v / 24.0)
+ * sin($phi)
+ * pow(cos($phi), 3.0)
+ * (5.0 - tanSquared($phi) + (9.0 * $etaSquared));
+ $IIIA =
+ ($v / 720.0)
+ * sin($phi)
+ * pow(cos($phi), 5.0)
+ * (61.0 - (58.0 * tanSquared($phi)) + pow(tan($phi), 4.0));
+ $IV = $v * cos($phi);
+ $V = ($v / 6.0) * pow(cos($phi), 3.0) * (($v / $rho) - tanSquared($phi));
+ $VI =
+ ($v / 120.0)
+ * pow(cos($phi), 5.0)
+ * (5.0
+ - (18.0 * tanSquared($phi))
+ + (pow(tan($phi), 4.0))
+ + (14 * $etaSquared)
+ - (58 * tanSquared($phi) * $etaSquared));
+
+ $N =
+ $I
+ + ($II * pow($lambda - $lambda0, 2.0))
+ + ($III * pow($lambda - $lambda0, 4.0))
+ + ($IIIA * pow($lambda - $lambda0, 6.0));
+ $E =
+ $E0
+ + ($IV * ($lambda - $lambda0))
+ + ($V * pow($lambda - $lambda0, 3.0))
+ + ($VI * pow($lambda - $lambda0, 5.0));
+
+ return new OSRef($E, $N);
+ }
+
+
+ /**
+ * Convert a latitude and longitude to an UTM reference
+ *
+ * @return the converted UTM reference
+ */
+ function toUTMRef() {
+ $wgs84 = new RefEll(6378137, 6356752.314);
+ $UTM_F0 = 0.9996;
+ $a = $wgs84->maj;
+ $eSquared = $wgs84->ecc;
+ $longitude = $this->lng;
+ $latitude = $this->lat;
+
+ $latitudeRad = $latitude * (pi() / 180.0);
+ $longitudeRad = $longitude * (pi() / 180.0);
+ $longitudeZone = (int) (($longitude + 180.0) / 6.0) + 1;
+
+ // Special zone for Norway
+ if ($latitude >= 56.0
+ && $latitude < 64.0
+ && $longitude >= 3.0
+ && $longitude < 12.0) {
+ $longitudeZone = 32;
+ }
+
+ // Special zones for Svalbard
+ if ($latitude >= 72.0 && $latitude < 84.0) {
+ if ($longitude >= 0.0 && $longitude < 9.0) {
+ $longitudeZone = 31;
+ } else if ($longitude >= 9.0 && $longitude < 21.0) {
+ $longitudeZone = 33;
+ } else if ($longitude >= 21.0 && $longitude < 33.0) {
+ $longitudeZone = 35;
+ } else if ($longitude >= 33.0 && $longitude < 42.0) {
+ $longitudeZone = 37;
+ }
+ }
+
+ $longitudeOrigin = ($longitudeZone - 1) * 6 - 180 + 3;
+ $longitudeOriginRad = $longitudeOrigin * (pi() / 180.0);
+
+ $UTMZone = getUTMLatitudeZoneLetter($latitude);
+
+ $ePrimeSquared = ($eSquared) / (1 - $eSquared);
+
+ $n = $a / sqrt(1 - $eSquared * sin($latitudeRad) * sin($latitudeRad));
+ $t = tan($latitudeRad) * tan($latitudeRad);
+ $c = $ePrimeSquared * cos($latitudeRad) * cos($latitudeRad);
+ $A = cos($latitudeRad) * ($longitudeRad - $longitudeOriginRad);
+
+ $M =
+ $a
+ * ((1
+ - $eSquared / 4
+ - 3 * $eSquared * $eSquared / 64
+ - 5 * $eSquared * $eSquared * $eSquared / 256)
+ * $latitudeRad
+ - (3 * $eSquared / 8
+ + 3 * $eSquared * $eSquared / 32
+ + 45 * $eSquared * $eSquared * $eSquared / 1024)
+ * sin(2 * $latitudeRad)
+ + (15 * $eSquared * $eSquared / 256
+ + 45 * $eSquared * $eSquared * $eSquared / 1024)
+ * sin(4 * $latitudeRad)
+ - (35 * $eSquared * $eSquared * $eSquared / 3072)
+ * sin(6 * $latitudeRad));
+
+ $UTMEasting =
+ (double) ($UTM_F0
+ * $n
+ * ($A
+ + (1 - $t + $c) * pow($A, 3.0) / 6
+ + (5 - 18 * $t + $t * $t + 72 * $c - 58 * $ePrimeSquared)
+ * pow($A, 5.0)
+ / 120)
+ + 500000.0);
+
+ $UTMNorthing =
+ (double) ($UTM_F0
+ * ($M
+ + $n
+ * tan($latitudeRad)
+ * ($A * $A / 2
+ + (5 - $t + (9 * $c) + (4 * $c * $c)) * pow($A, 4.0) / 24
+ + (61 - (58 * $t) + ($t * $t) + (600 * $c) - (330 * $ePrimeSquared))
+ * pow($A, 6.0)
+ / 720)));
+
+ // Adjust for the southern hemisphere
+ if ($latitude < 0) {
+ $UTMNorthing += 10000000.0;
+ }
+
+ return new UTMRef($UTMEasting, $UTMNorthing, $UTMZone, $longitudeZone);
+ }
+ }
+
+
+ // =================================================================== OSRef
+
+ // References given with OSRef are accurate to 1m.
+ class OSRef {
+
+ var $easting;
+ var $northing;
+
+
+ /**
+ * Create a new OSRef object representing an OSGB grid reference. Note
+ * that the parameters for this constructor require eastings and
+ * northings with 1m accuracy and need to be absolute with respect to
+ * the whole of the British Grid. For example, to create an OSRef
+ * object from the six-figure grid reference TG514131, the easting would
+ * be 651400 and the northing would be 313100.
+ *
+ * Grid references with accuracy greater than 1m can be represented
+ * using floating point values for the easting and northing. For example,
+ * a value representing an easting or northing accurate to 1mm would be
+ * given as 651400.0001.
+ *
+ * @param easting the easting of the reference (with 1m accuracy)
+ * @param northing the northing of the reference (with 1m accuracy)
+ */
+ function OSRef($easting, $northing) {
+ $this->easting = $easting;
+ $this->northing = $northing;
+ }
+
+
+ /**
+ * Convert this grid reference into a string showing the exact values
+ * of the easting and northing.
+ *
+ * @return
+ */
+ function toString() {
+ return "(" . $this->easting . ", " . $this->northing . ")";
+ }
+
+
+ /**
+ * Convert this grid reference into a string using a standard six-figure
+ * grid reference including the two-character designation for the 100km
+ * square. e.g. TG514131.
+ *
+ * @return
+ */
+ function toSixFigureString() {
+ $hundredkmE = floor($this->easting / 100000);
+ $hundredkmN = floor($this->northing / 100000);
+ $firstLetter = "";
+ if ($hundredkmN < 5) {
+ if ($hundredkmE < 5) {
+ $firstLetter = "S";
+ } else {
+ $firstLetter = "T";
+ }
+ } else if ($hundredkmN < 10) {
+ if ($hundredkmE < 5) {
+ $firstLetter = "N";
+ } else {
+ $firstLetter = "O";
+ }
+ } else {
+ $firstLetter = "H";
+ }
+
+ $secondLetter = "";
+ $index = 65 + ((4 - ($hundredkmN % 5)) * 5) + ($hundredkmE % 5);
+ $ti = $index;
+ if ($index >= 73) $index++;
+ $secondLetter = chr($index);
+
+ $e = round(($this->easting - (100000 * $hundredkmE)) / 100);
+ $n = round(($this->northing - (100000 * $hundredkmN)) / 100);
+
+ return sprintf("%s%s%03d%03d", $firstLetter, $secondLetter, $e, $n);
+ }
+
+
+ /**
+ * Convert this grid reference into a latitude and longitude
+ *
+ * @return
+ */
+ function toLatLng() {
+ $airy1830 = new RefEll(6377563.396, 6356256.909);
+ $OSGB_F0 = 0.9996012717;
+ $N0 = -100000.0;
+ $E0 = 400000.0;
+ $phi0 = deg2rad(49.0);
+ $lambda0 = deg2rad(-2.0);
+ $a = $airy1830->maj;
+ $b = $airy1830->min;
+ $eSquared = $airy1830->ecc;
+ $phi = 0.0;
+ $lambda = 0.0;
+ $E = $this->easting;
+ $N = $this->northing;
+ $n = ($a - $b) / ($a + $b);
+ $M = 0.0;
+ $phiPrime = (($N - $N0) / ($a * $OSGB_F0)) + $phi0;
+ do {
+ $M =
+ ($b * $OSGB_F0)
+ * (((1 + $n + ((5.0 / 4.0) * $n * $n) + ((5.0 / 4.0) * $n * $n * $n))
+ * ($phiPrime - $phi0))
+ - (((3 * $n) + (3 * $n * $n) + ((21.0 / 8.0) * $n * $n * $n))
+ * sin($phiPrime - $phi0)
+ * cos($phiPrime + $phi0))
+ + ((((15.0 / 8.0) * $n * $n) + ((15.0 / 8.0) * $n * $n * $n))
+ * sin(2.0 * ($phiPrime - $phi0))
+ * cos(2.0 * ($phiPrime + $phi0)))
+ - (((35.0 / 24.0) * $n * $n * $n)
+ * sin(3.0 * ($phiPrime - $phi0))
+ * cos(3.0 * ($phiPrime + $phi0))));
+ $phiPrime += ($N - $N0 - $M) / ($a * $OSGB_F0);
+ } while (($N - $N0 - $M) >= 0.001);
+ $v = $a * $OSGB_F0 * pow(1.0 - $eSquared * sinSquared($phiPrime), -0.5);
+ $rho =
+ $a
+ * $OSGB_F0
+ * (1.0 - $eSquared)
+ * pow(1.0 - $eSquared * sinSquared($phiPrime), -1.5);
+ $etaSquared = ($v / $rho) - 1.0;
+ $VII = tan($phiPrime) / (2 * $rho * $v);
+ $VIII =
+ (tan($phiPrime) / (24.0 * $rho * pow($v, 3.0)))
+ * (5.0
+ + (3.0 * tanSquared($phiPrime))
+ + $etaSquared
+ - (9.0 * tanSquared($phiPrime) * $etaSquared));
+ $IX =
+ (tan($phiPrime) / (720.0 * $rho * pow($v, 5.0)))
+ * (61.0
+ + (90.0 * tanSquared($phiPrime))
+ + (45.0 * tanSquared($phiPrime) * tanSquared($phiPrime)));
+ $X = sec($phiPrime) / $v;
+ $XI =
+ (sec($phiPrime) / (6.0 * $v * $v * $v))
+ * (($v / $rho) + (2 * tanSquared($phiPrime)));
+ $XII =
+ (sec($phiPrime) / (120.0 * pow($v, 5.0)))
+ * (5.0
+ + (28.0 * tanSquared($phiPrime))
+ + (24.0 * tanSquared($phiPrime) * tanSquared($phiPrime)));
+ $XIIA =
+ (sec($phiPrime) / (5040.0 * pow($v, 7.0)))
+ * (61.0
+ + (662.0 * tanSquared($phiPrime))
+ + (1320.0 * tanSquared($phiPrime) * tanSquared($phiPrime))
+ + (720.0
+ * tanSquared($phiPrime)
+ * tanSquared($phiPrime)
+ * tanSquared($phiPrime)));
+ $phi =
+ $phiPrime
+ - ($VII * pow($E - $E0, 2.0))
+ + ($VIII * pow($E - $E0, 4.0))
+ - ($IX * pow($E - $E0, 6.0));
+ $lambda =
+ $lambda0
+ + ($X * ($E - $E0))
+ - ($XI * pow($E - $E0, 3.0))
+ + ($XII * pow($E - $E0, 5.0))
+ - ($XIIA * pow($E - $E0, 7.0));
+
+ return new LatLng(rad2deg($phi), rad2deg($lambda));
+ }
+ }
+
+
+ // ================================================================== UTMRef
+
+ class UTMRef {
+
+ var $easting;
+ var $northing;
+ var $latZone;
+ var $lngZone;
+
+
+ /**
+ * Create a new object representing a UTM reference.
+ *
+ * @param easting
+ * @param northing
+ * @param latZone
+ * @param lngZone
+ */
+ function UTMRef($easting, $northing, $latZone, $lngZone) {
+ $this->easting = $easting;
+ $this->northing = $northing;
+ $this->latZone = $latZone;
+ $this->lngZone = $lngZone;
+ }
+
+
+ /**
+ * Return a string representation of this UTM reference
+ *
+ * @return
+ */
+ function toString() {
+ return $this->lngZone . $this->latZone . " " .
+ $this->easting . " " . $this->northing;
+ }
+
+
+ /**
+ * Convert this UTM reference to a latitude and longitude
+ *
+ * @return the converted latitude and longitude
+ */
+ function toLatLng() {
+ $wgs84 = new RefEll(6378137, 6356752.314);
+ $UTM_F0 = 0.9996;
+ $a = $wgs84->maj;
+ $eSquared = $wgs84->ecc;
+ $ePrimeSquared = $eSquared / (1.0 - $eSquared);
+ $e1 = (1 - sqrt(1 - $eSquared)) / (1 + sqrt(1 - $eSquared));
+ $x = $this->easting - 500000.0;;
+ $y = $this->northing;
+ $zoneNumber = $this->lngZone;
+ $zoneLetter = $this->latZone;
+
+ $longitudeOrigin = ($zoneNumber - 1.0) * 6.0 - 180.0 + 3.0;
+
+ // Correct y for southern hemisphere
+ if ((ord($zoneLetter) - ord("N")) < 0) {
+ $y -= 10000000.0;
+ }
+
+ $m = $y / $UTM_F0;
+ $mu =
+ $m
+ / ($a
+ * (1.0
+ - $eSquared / 4.0
+ - 3.0 * $eSquared * $eSquared / 64.0
+ - 5.0
+ * pow($eSquared, 3.0)
+ / 256.0));
+
+ $phi1Rad =
+ $mu
+ + (3.0 * $e1 / 2.0 - 27.0 * pow($e1, 3.0) / 32.0) * sin(2.0 * $mu)
+ + (21.0 * $e1 * $e1 / 16.0 - 55.0 * pow($e1, 4.0) / 32.0)
+ * sin(4.0 * $mu)
+ + (151.0 * pow($e1, 3.0) / 96.0) * sin(6.0 * $mu);
+
+ $n =
+ $a
+ / sqrt(1.0 - $eSquared * sin($phi1Rad) * sin($phi1Rad));
+ $t = tan($phi1Rad) * tan($phi1Rad);
+ $c = $ePrimeSquared * cos($phi1Rad) * cos($phi1Rad);
+ $r =
+ $a
+ * (1.0 - $eSquared)
+ / pow(
+ 1.0 - $eSquared * sin($phi1Rad) * sin($phi1Rad),
+ 1.5);
+ $d = $x / ($n * $UTM_F0);
+
+ $latitude = (
+ $phi1Rad
+ - ($n * tan($phi1Rad) / $r)
+ * ($d * $d / 2.0
+ - (5.0
+ + (3.0 * $t)
+ + (10.0 * $c)
+ - (4.0 * $c * $c)
+ - (9.0 * $ePrimeSquared))
+ * pow($d, 4.0)
+ / 24.0
+ + (61.0
+ + (90.0 * $t)
+ + (298.0 * $c)
+ + (45.0 * $t * $t)
+ - (252.0 * $ePrimeSquared)
+ - (3.0 * $c * $c))
+ * pow($d, 6.0)
+ / 720.0)) * (180.0 / pi());
+
+ $longitude = $longitudeOrigin + (
+ ($d
+ - (1.0 + 2.0 * $t + $c) * pow($d, 3.0) / 6.0
+ + (5.0
+ - (2.0 * $c)
+ + (28.0 * $t)
+ - (3.0 * $c * $c)
+ + (8.0 * $ePrimeSquared)
+ + (24.0 * $t * $t))
+ * pow($d, 5.0)
+ / 120.0)
+ / cos($phi1Rad)) * (180.0 / pi());
+
+ return new LatLng($latitude, $longitude);
+ }
+ }
+
+
+ // ================================================================== RefEll
+
+ class RefEll {
+
+ var $maj;
+ var $min;
+ var $ecc;
+
+
+ /**
+ * Create a new RefEll object to represent a reference ellipsoid
+ *
+ * @param maj the major axis
+ * @param min the minor axis
+ */
+ function RefEll($maj, $min) {
+ $this->maj = $maj;
+ $this->min = $min;
+ $this->ecc = (($maj * $maj) - ($min * $min)) / ($maj * $maj);
+ }
+ }
+
+
+ // ================================================== Mathematical Functions
+
+ function sinSquared($x) {
+ return sin($x) * sin($x);
+ }
+
+ function cosSquared($x) {
+ return cos($x) * cos($x);
+ }
+
+ function tanSquared($x) {
+ return tan($x) * tan($x);
+ }
+
+ function sec($x) {
+ return 1.0 / cos($x);
+ }
+
+
+ /**
+ * Take a string formatted as a six-figure OS grid reference (e.g.
+ * "TG514131") and return a reference to an OSRef object that represents
+ * that grid reference. The first character must be H, N, S, O or T.
+ * The second character can be any uppercase character from A through Z
+ * excluding I.
+ *
+ * @param ref
+ * @return
+ * @since 2.1
+ */
+ function getOSRefFromSixFigureReference($ref) {
+ $char1 = substr($ref, 0, 1);
+ $char2 = substr($ref, 1, 1);
+ $east = substr($ref, 2, 3) * 100;
+ $north = substr($ref, 5, 3) * 100;
+ if ($char1 == 'H') {
+ $north += 1000000;
+ } else if ($char1 == 'N') {
+ $north += 500000;
+ } else if ($char1 == 'O') {
+ $north += 500000;
+ $east += 500000;
+ } else if ($char1 == 'T') {
+ $east += 500000;
+ }
+ $char2ord = ord($char2);
+ if ($char2ord > 73) $char2ord--; // Adjust for no I
+ $nx = (($char2ord - 65) % 5) * 100000;
+ $ny = (4 - floor(($char2ord - 65) / 5)) * 100000;
+ return new OSRef($east + $nx, $north + $ny);
+ }
+
+
+ /**
+ * Work out the UTM latitude zone from the latitude
+ *
+ * @param latitude
+ * @return
+ */
+ function getUTMLatitudeZoneLetter($latitude) {
+ if ((84 >= $latitude) && ($latitude >= 72)) return "X";
+ else if (( 72 > $latitude) && ($latitude >= 64)) return "W";
+ else if (( 64 > $latitude) && ($latitude >= 56)) return "V";
+ else if (( 56 > $latitude) && ($latitude >= 48)) return "U";
+ else if (( 48 > $latitude) && ($latitude >= 40)) return "T";
+ else if (( 40 > $latitude) && ($latitude >= 32)) return "S";
+ else if (( 32 > $latitude) && ($latitude >= 24)) return "R";
+ else if (( 24 > $latitude) && ($latitude >= 16)) return "Q";
+ else if (( 16 > $latitude) && ($latitude >= 8)) return "P";
+ else if (( 8 > $latitude) && ($latitude >= 0)) return "N";
+ else if (( 0 > $latitude) && ($latitude >= -8)) return "M";
+ else if (( -8 > $latitude) && ($latitude >= -16)) return "L";
+ else if ((-16 > $latitude) && ($latitude >= -24)) return "K";
+ else if ((-24 > $latitude) && ($latitude >= -32)) return "J";
+ else if ((-32 > $latitude) && ($latitude >= -40)) return "H";
+ else if ((-40 > $latitude) && ($latitude >= -48)) return "G";
+ else if ((-48 > $latitude) && ($latitude >= -56)) return "F";
+ else if ((-56 > $latitude) && ($latitude >= -64)) return "E";
+ else if ((-64 > $latitude) && ($latitude >= -72)) return "D";
+ else if ((-72 > $latitude) && ($latitude >= -80)) return "C";
+ else return 'Z';
+ }
+
+?>
diff --git a/website/plugin-rpc/tfl/phpcoord/readme-2.3.txt b/website/plugin-rpc/tfl/phpcoord/readme-2.3.txt
new file mode 100644
index 00000000..25aca348
--- /dev/null
+++ b/website/plugin-rpc/tfl/phpcoord/readme-2.3.txt
@@ -0,0 +1,60 @@
+--------------------------------------------------------------------------
+ PHPcoord
+ readme.txt
+
+ (c) 2005 Jonathan Stott
+
+ Created on 11-Aug-2005
+
+ 2.3 - 24 Aug 2006
+ - Changed OSRef->toSixFigureString() so that the eastings and northings
+ are rounded rather than floored.
+ 2.2 - 11 Feb 2006
+ - Used different algorithm for calculating distance between latitudes
+ and longitudes - fixes a number of problems with distance calculations
+ 2.1 - 22 Dec 2005
+ - Added getOSRefFromSixFigureReference function
+ 2.0 - 21 Dec 2005
+ - Completely different object design - conversion functions now through
+ objects rather than static functions
+ - Updated comments and documentation
+ 1.1 - 11 Sep 2005
+ - Added WGS84/OSGB36 conversions
+ 1.0 - 11 Aug 2005
+ - Initial version
+--------------------------------------------------------------------------
+
+PHPcoord is a PHP script that provides functions for handling various
+co-ordinate systems and converting between them. Currently, OSGB (Ordnance
+Survey of Great Britain) grid references, UTM (Universal Transverse
+Mercator) references and latitude/longitude are supported. A function is
+also provided to find the surface distance between two points of latitude
+and longitude.
+
+When using the OSGB conversions, the majority of applications use the
+WGS84 datum rather than the OSGB36 datum. Conversions between the two
+data were added in v1.1 - the conversions should be accurate to within
+5m or so. If accuracy is not important (i.e. to within 200m or so),
+then it isn't necessary to perform the conversions.
+
+Examples of how to use the functions provided in phpcoord.php can be
+found in the test.php script.
+
+See http://www.jstott.me.uk/phpcoord/ for latest releases and information.
+
+
+DISCLAIMER
+
+Accuracy of the co-ordinate conversions contained within the PHPcoord
+package is not guaranteed. Use of the conversions is entirely at your
+own risk and I cannot be held responsible for any consequences of
+errors created by the conversions. I do not recommend using the package
+for mission-critical applications.
+
+
+LICENSING
+
+This software product is available under the GNU General Public License
+(GPL). Terms of the GPL can be read at http://www.jstott.me.uk/gpl/.
+Any commercial use requires the purchase of a license - contact me at
+phpcoord@jstott.me.uk for details.
diff --git a/website/plugin-rpc/tfl/phpcoord/test-2.3.php b/website/plugin-rpc/tfl/phpcoord/test-2.3.php
new file mode 100644
index 00000000..4cbc11bf
--- /dev/null
+++ b/website/plugin-rpc/tfl/phpcoord/test-2.3.php
@@ -0,0 +1,206 @@
+toSixFigureString() so that the eastings and northings
+ // are rounded rather than floored.
+ // 2.2 - 11 Feb 2006
+ // - Used different algorithm for calculating distance between latitudes
+ // and longitudes - fixes a number of problems with distance calculations
+ // 2.1 - 22 Dec 2005
+ // - Added getOSRefFromSixFigureReference function
+ // 2.0 - 21 Dec 2005
+ // - Completely different object design - conversion functions now through
+ // objects rather than static functions
+ // - Updated comments and documentation
+ // 1.1 - 11 Sep 2005
+ // - Added OSGB36/WGS84 data conversions
+ // 1.0 - 11 Aug 2005
+ // - Initial version
+ //--------------------------------------------------------------------------
+
+
+ require_once("phpcoord-2.3.php");
+?>
+
+
+
+
+ phpcoord Test Script
+
+
+
+
+ phpcoord Test Script
+
+ Calculate Surface Distance between two Latitudes/Longitudes
+
+
+ The LatLngDistance function takes two latitudes/longitudes and calculates
+ the surface distance between the two in kilometres:
+
+
+
+
$lld1 = new LatLng(40.718119, -73.995667); // New York
+echo "New York Lat/Long: " . $lld1->toString() . "<br />";
+$lld2 = new LatLng(51.499981, -0.125313); // London
+$d = $lld1->distance($lld2);
+echo "Surface Distance between New York and London: " . $d . "km";
+
+ toString() . "
";
+ $lld2 = new LatLng(51.499981, -0.125313); // London
+ echo "London Lat/Long: " . $lld2->toString() . "
";
+ $d = $lld1->distance($lld2);
+ echo "Surface Distance between New York and London: " . $d . "km";
+ ?>
+
+
+ Convert OS Grid Reference to Latitude/Longitude
+
+
+ Note that the OSGB-Latitude/Longitude conversions use the OSGB36 datum by default. The
+ majority of applications use the WGS84 datum, for which the appropriate conversions
+ need to be added. See the examples below to see the difference between the two data.
+
+
+
+ Using OSGB36 (convert an OSGB grid reference to a latitude and longitude using the OSGB36 datum):
+
+
$os1 = new OSRef(651409.903, 313177.270);
+echo "OS Grid Reference: " . $os1->toString() . " - " . $os1->toSixFigureString() . "<br />";
+$ll1 = $os1->toLatLng();
+echo "Converted to Lat/Long: " . $ll1->toString();
+
+ toString() . " - " . $os1->toSixFigureString() . "
";
+ $ll1 = $os1->toLatLng();
+ echo "Converted to Lat/Long: " . $ll1->toString();
+ ?>
+
+
+
+ Using WGS84 (convert an OSGB grid reference to a latitude and longitude using the WGS84 datum):
+
+
$os1w = new OSRef(651409.903, 313177.270);
+echo "OS Grid Reference: " . $os1w->toString() . " - " . $os1w->toSixFigureString() . "<br />";
+$l1w = $os1w->toLatLng();
+$l1w->OSGB36ToWGS84();
+echo "Converted to Lat/Long: " . $ll1w->toString();
+
+ toString() . " - " . $os1w->toSixFigureString() . "
";
+ $ll1w = $os1w->toLatLng();
+ $ll1w->OSGB36ToWGS84();
+ echo "Converted to Lat/Long: " . $ll1w->toString();
+ ?>
+
+
+ Convert Latitude/Longitude to OS Grid Reference
+
+
+ Note that the OSGB-Latitude/Longitude conversions use the OSGB36 datum by default. The
+ majority of applications use the WGS84 datum, for which the appropriate conversions
+ need to be added. See the examples below to see the difference between the two data.
+
+
+
+ Using OSGB36 (convert a latitude and longitude using the OSGB36 datum to an OSGB grid reference):
+
+
$ll2 = new LatLng(52.657570301933, 1.7179215806451);
+echo "Latitude/Longitude: " . $ll2->toString() . "<br />";
+$os2 = $ll2->toOSRef();
+echo "Converted to OS Grid Ref: " . $os2->toString() . " - " . $os2->toSixFigureString();
+
+ toString() . "
";
+ $os2 = $ll2->toOSRef();
+ echo "Converted to OS Grid Ref: " . $os2->toString() . " - " . $os2->toSixFigureString();
+ ?>
+
+
+
+ Using WGS84 (convert a latitude and longitude using the WGS84 datum to an OSGB grid reference):
+
+
$ll2w = new LatLng(52.657570301933, 1.7179215806451);
+echo "Latitude/Longitude: " . $ll2->toString() . "<br />";
+$ll2w->WGS84ToOSGB36();
+$os2w = $ll2w->toOSRef();
+echo "Converted to OS Grid Ref: " . $os2w->toString() . " - " . $os2w->toSixFigureString();
+
+ toString() . "
";
+ $ll2w->WGS84ToOSGB36();
+ $os2w = $ll2w->toOSRef();
+ echo "Converted to OS Grid Ref: " . $os2w->toString() . " - " . $os2w->toSixFigureString();
+ ?>
+
+
+ Convert Six-Figure OS Grid Reference String to an OSRef Object
+
+
+ To convert a string representing a six-figure OSGB grid reference:
+
+
$os6 = "TG514131";
+echo "Six figure string: " . $os6 . "<br />";
+$os6x = getOSRefFromSixFigureReference($os6);
+echo "Converted to OS Grid Ref: " . $os6x->toString() . " - " . $os6x->toSixFigureString();
+
+ ";
+ $os6x = getOSRefFromSixFigureReference($os6);
+ echo "Converted to OS Grid Ref: " . $os6x->toString() . " - " . $os6x->toSixFigureString();
+ ?>
+
+
+ Convert UTM Reference to Latitude/Longitude
+
+
+
$utm1 = new UTMRef(456463.99, 3335334.05, "E", 12);
+echo "UTM Reference: " . $utm1->toString() . "<br />";
+$ll3 = $utm1->toLatLng();
+echo "Converted to Lat/Long: " . $ll3->toString();
+
+ toString() . "
";
+ $ll3 = $utm1->toLatLng();
+ echo "Converted to Lat/Long: " . $ll3->toString();
+ ?>
+
+
+ Convert Latitude/Longitude to UTM Reference
+
+
+
$ll4 = new LatLng(-60.1167, -111.7833);
+echo "Latitude/Longitude: " . $ll4->toString() . "<br />";
+$utm2 = $ll4->toUTMRef();
+echo "Converted to UTM Ref: " . $utm2->toString() ;
+
+ toString() . "
";
+ $utm2 = $ll4->toUTMRef();
+ echo "Converted to UTM Ref: " . $utm2->toString() ;
+ ?>
+
+
+
+ (c) 2005, Jonathan Stott
+
+
+
+