Skip to content

Instantly share code, notes, and snippets.

@bmcbride
Created January 18, 2017 16:37
Show Gist options
  • Save bmcbride/43b4a6496f31b1d1621a64891699f653 to your computer and use it in GitHub Desktop.
Save bmcbride/43b4a6496f31b1d1621a64891699f653 to your computer and use it in GitHub Desktop.
Fulcrum Data Event to convert WGS84 coordinates to Ordnance Survey Great Britain (OSGB) / British National Grid (BNG).
/**
* GeoTools javascript coordinate transformations
* http://files.dixo.net/geotools.html
*
* This file copyright (c)2005 Paul Dixon ([email protected])
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* ---------------------------------------------------------------------------
*
* Credits
*
* The algorithm used by the script for WGS84-OSGB36 conversions is derived
* from an OSGB spreadsheet (www.gps.gov.uk) with permission. This has been
* adapted into PHP by Ian Harris, and Irish added by Barry Hunter. Conversion
* accuracy is in the order of 7m for 90% of Great Britain, and should be
* be similar to the conversion made by a typical GPSr
*
* See accompanying documentation for more information
* http://www.nearby.org.uk/tests/GeoTools2.html
*/
/*****************************************************************************
*
* GT_OSGB holds OSGB grid coordinates
*
*****************************************************************************/
function GT_OSGB(){this.northings=0,this.eastings=0,this.status="Undefined"}function GT_Irish(){this.northings=0,this.eastings=0,this.status="Undefined"}function GT_WGS84(){this.latitude=0,this.longitude=0}function GT_Math(){}GT_OSGB.prefixes=new Array(new Array("SV","SW","SX","SY","SZ","TV","TW"),new Array("SQ","SR","SS","ST","SU","TQ","TR"),new Array("SL","SM","SN","SO","SP","TL","TM"),new Array("SF","SG","SH","SJ","SK","TF","TG"),new Array("SA","SB","SC","SD","SE","TA","TB"),new Array("NV","NW","NX","NY","NZ","OV","OW"),new Array("NQ","NR","NS","NT","NU","OQ","OR"),new Array("NL","NM","NN","NO","NP","OL","OM"),new Array("NF","NG","NH","NJ","NK","OF","OG"),new Array("NA","NB","NC","ND","NE","OA","OB"),new Array("HV","HW","HX","HY","HZ","JV","JW"),new Array("HQ","HR","HS","HT","HU","JQ","JR"),new Array("HL","HM","HN","HO","HP","JL","JM")),GT_OSGB.prototype.setGridCoordinates=function(t,a){this.northings=a,this.eastings=t,this.status="OK"},GT_OSGB.prototype.setError=function(t){this.status=t},GT_OSGB.prototype._zeropad=function(t,a){for(var h=new String(t);h.length<a;)h="0"+h;return h},GT_OSGB.prototype.getGridRef=function(t){0>t&&(t=0),t>5&&(t=5);var a="",h="";if(t>0){var o=Math.floor(this.northings/1e5),r=Math.floor(this.eastings/1e5),a=Math.floor(this.eastings%1e5),h=Math.floor(this.northings%1e5),n=5-t;a=Math.floor(a/Math.pow(10,n)),h=Math.floor(h/Math.pow(10,n))}var e=GT_OSGB.prefixes[o][r];return e+" "+this._zeropad(a,t)+" "+this._zeropad(h,t)},GT_OSGB.prototype.parseGridRef=function(t){var a=!1;this.northings=0,this.eastings=0;var h;for(h=5;h>=1;h--){var o=new RegExp("^([A-Z]{2})\\s*(\\d{"+h+"})\\s*(\\d{"+h+"})$","i"),r=t.match(o);if(r){var n=r[1],e=0,i=0;if(h>0){var s=Math.pow(10,5-h);e=parseInt(r[2],10)*s,i=parseInt(r[3],10)*s}var M,_;t:for(_=0;_<GT_OSGB.prefixes.length;_++)for(M=0;M<GT_OSGB.prefixes[_].length;M++)if(GT_OSGB.prefixes[_][M]==n){this.eastings=1e5*M+e,this.northings=1e5*_+i,a=!0;break t}}}return a},GT_OSGB.prototype.getWGS84=function(){var t=0,a=GT_Math.E_N_to_Lat(this.eastings,this.northings,6377563.396,6356256.91,4e5,-1e5,.999601272,49,-2),h=GT_Math.E_N_to_Long(this.eastings,this.northings,6377563.396,6356256.91,4e5,-1e5,.999601272,49,-2),o=GT_Math.Lat_Long_H_to_X(a,h,t,6377563.396,6356256.91),r=GT_Math.Lat_Long_H_to_Y(a,h,t,6377563.396,6356256.91),n=GT_Math.Lat_H_to_Z(a,t,6377563.396,6356256.91),e=GT_Math.Helmert_X(o,r,n,446.448,.247,.8421,-20.4894),i=GT_Math.Helmert_Y(o,r,n,-125.157,.1502,.8421,-20.4894),s=GT_Math.Helmert_Z(o,r,n,542.06,.1502,.247,-20.4894),M=GT_Math.XYZ_to_Lat(e,i,s,6378137,6356752.313),_=GT_Math.XYZ_to_Long(e,i),p=new GT_WGS84;return p.setDegrees(M,_),p},GT_Irish.prefixes=new Array(new Array("V","Q","L","F","A"),new Array("W","R","M","G","B"),new Array("X","S","N","H","C"),new Array("Y","T","O","J","D"),new Array("Z","U","P","K","E")),GT_Irish.prototype.setGridCoordinates=function(t,a){this.northings=a,this.eastings=t,this.status="OK"},GT_Irish.prototype.setError=function(t){this.status=t},GT_Irish.prototype._zeropad=function(t,a){for(var h=new String(t);h.length<a;)h="0"+h;return h},GT_Irish.prototype.getGridRef=function(t){0>t&&(t=0),t>5&&(t=5);var a="",h="";if(t>0){var o=Math.floor(this.northings/1e5),r=Math.floor(this.eastings/1e5),a=Math.floor(this.eastings%1e5),h=Math.floor(this.northings%1e5),n=5-t;a=Math.floor(a/Math.pow(10,n)),h=Math.floor(h/Math.pow(10,n))}var e=GT_Irish.prefixes[r][o];return e+" "+this._zeropad(a,t)+" "+this._zeropad(h,t)},GT_Irish.prototype.parseGridRef=function(t){var a=!1;this.northings=0,this.eastings=0;var h;for(h=5;h>=1;h--){var o=new RegExp("^([A-Z]{1})\\s*(\\d{"+h+"})\\s*(\\d{"+h+"})$","i"),r=t.match(o);if(r){var n=r[1],e=0,i=0;if(h>0){var s=Math.pow(10,5-h);e=parseInt(r[2],10)*s,i=parseInt(r[3],10)*s}var M,_;t:for(M=0;M<GT_Irish.prefixes.length;M++)for(_=0;_<GT_Irish.prefixes[M].length;_++)if(GT_Irish.prefixes[M][_]==n){this.eastings=1e5*M+e,this.northings=1e5*_+i,a=!0;break t}}}return a},GT_Irish.prototype.getWGS84=function(t){var a=0;t?(e=this.eastings,n=this.northings):(e=this.eastings-49,n=this.northings+23.4);var h=GT_Math.E_N_to_Lat(e,n,6377340.189,6356034.447,2e5,25e4,1.000035,53.5,-8),o=GT_Math.E_N_to_Long(e,n,6377340.189,6356034.447,2e5,25e4,1.000035,53.5,-8),r=new GT_WGS84;if(t){var i=GT_Math.Lat_Long_H_to_X(h,o,a,6377340.189,6356034.447),s=GT_Math.Lat_Long_H_to_Y(h,o,a,6377340.189,6356034.447),M=GT_Math.Lat_H_to_Z(h,a,6377340.189,6356034.447),_=GT_Math.Helmert_X(i,s,M,482.53,.214,.631,8.15),p=GT_Math.Helmert_Y(i,s,M,-130.596,1.042,.631,8.15),G=GT_Math.Helmert_Z(i,s,M,564.557,1.042,.214,8.15),w=GT_Math.XYZ_to_Lat(_,p,G,6378137,6356752.313),T=GT_Math.XYZ_to_Long(_,p);r.setDegrees(w,T)}else r.setDegrees(h,o);return r},GT_WGS84.prototype.setDegrees=function(t,a){this.latitude=t,this.longitude=a},GT_WGS84.prototype.parseString=function(t){var a=!1,h=new String(t),o=/([ns])\s*(\d+)[°\s]+(\d+\.\d+)\s+([we])\s*(\d+)[°\s]+(\d+\.\d+)/i,r=h.match(o);if(r){a=!0;var n="s"==r[1]||"S"==r[1]?-1:1,e="w"==r[4]||"W"==r[4]?-1:1,i=parseFloat(r[2]),s=parseFloat(r[3]),M=parseFloat(r[5]),_=parseFloat(r[6]);this.latitude=n*(i+s/60),this.longitude=e*(M+_/60)}return a},GT_WGS84.prototype.isGreatBritain=function(){return this.latitude>49&&this.latitude<62&&this.longitude>-9.5&&this.longitude<2.3},GT_WGS84.prototype.isIreland=function(){return this.latitude>51.2&&this.latitude<55.73&&this.longitude>-12.2&&this.longitude<-4.8},GT_WGS84.prototype.isIreland2=function(){for(var t=[[-12.19,50.38],[-6.39,50.94],[-5.07,53.71],[-5.25,54.71],[-6.13,55.42],[-10.65,56.15],[-12.19,50.38]],a=0,h=!1,o=this.longitude,r=this.latitude,n=0;n<t.length;n++)a++,a==t.length&&(a=0),(t[n][1]<r&&t[a][1]>=r||t[a][1]<r&&t[n][1]>=r)&&t[n][0]+(r-t[n][1])/(t[a][1]-t[n][1])*(t[a][0]-t[n][0])<o&&(h=!h);return h},GT_WGS84.prototype.getIrish=function(t){var a=new GT_Irish;if(this.isIreland()){var h=0;if(t)var o=GT_Math.Lat_Long_H_to_X(this.latitude,this.longitude,h,6378137,6356752.313),r=GT_Math.Lat_Long_H_to_Y(this.latitude,this.longitude,h,6378137,6356752.313),n=GT_Math.Lat_H_to_Z(this.latitude,h,6378137,6356752.313),e=GT_Math.Helmert_X(o,r,n,-482.53,-.214,-.631,-8.15),i=GT_Math.Helmert_Y(o,r,n,130.596,-1.042,-.631,-8.15),s=GT_Math.Helmert_Z(o,r,n,-564.557,-1.042,-.214,-8.15),M=GT_Math.XYZ_to_Lat(e,i,s,6377340.189,6356034.447),_=GT_Math.XYZ_to_Long(e,i);else var M=this.latitude,_=this.longitude;var p=GT_Math.Lat_Long_to_East(M,_,6377340.189,6356034.447,2e5,1.000035,53.5,-8),G=GT_Math.Lat_Long_to_North(M,_,6377340.189,6356034.447,2e5,25e4,1.000035,53.5,-8);t||(p+=49,G-=23.4),a.setGridCoordinates(Math.round(p),Math.round(G))}else a.setError("Coordinate not within Ireland");return a},GT_WGS84.prototype.getOSGB=function(t){var a=new GT_OSGB;if(this.isGreatBritain()){var h=0,o=GT_Math.Lat_Long_H_to_X(this.latitude,this.longitude,h,6378137,6356752.313),r=GT_Math.Lat_Long_H_to_Y(this.latitude,this.longitude,h,6378137,6356752.313),n=GT_Math.Lat_H_to_Z(this.latitude,h,6378137,6356752.313),e=GT_Math.Helmert_X(o,r,n,-446.448,-.247,-.8421,20.4894),i=GT_Math.Helmert_Y(o,r,n,125.157,-.1502,-.8421,20.4894),s=GT_Math.Helmert_Z(o,r,n,-542.06,-.1502,-.247,20.4894),M=GT_Math.XYZ_to_Lat(e,i,s,6377563.396,6356256.91),_=GT_Math.XYZ_to_Long(e,i),p=GT_Math.Lat_Long_to_East(M,_,6377563.396,6356256.91,4e5,.999601272,49,-2),G=GT_Math.Lat_Long_to_North(M,_,6377563.396,6356256.91,4e5,-1e5,.999601272,49,-2);a.setGridCoordinates(Math.round(p),Math.round(G))}else a.setError("Coordinate not within Great Britain");return a},GT_Math.E_N_to_Lat=function(t,a,h,o,r,n,e,i,s){var M=3.14159265358979,_=i*(M/180),p=h*e,G=o*e,w=(Math.pow(p,2)-Math.pow(G,2))/Math.pow(p,2),T=(p-G)/(p+G),u=t-r,g=GT_Math.InitialLat(a,n,p,_,T,G),f=p/Math.sqrt(1-w*Math.pow(Math.sin(g),2)),l=f*(1-w)/(1-w*Math.pow(Math.sin(g),2)),d=f/l-1,L=Math.tan(g)/(2*l*f),c=Math.tan(g)/(24*l*Math.pow(f,3))*(5+3*Math.pow(Math.tan(g),2)+d-9*d*Math.pow(Math.tan(g),2)),S=Math.tan(g)/(720*l*Math.pow(f,5))*(61+90*(2^Math.tan(g))+45*Math.pow(Math.tan(g),4)),v=180/M*(g-Math.pow(u,2)*L+Math.pow(u,4)*c-(6^u)*S);return v},GT_Math.E_N_to_Long=function(t,a,h,o,r,n,e,i,s){var M=3.14159265358979,_=i*(M/180),p=s*(M/180),G=h*e,w=o*e,T=(Math.pow(G,2)-Math.pow(w,2))/Math.pow(G,2),u=(G-w)/(G+w),g=t-r,f=GT_Math.InitialLat(a,n,G,_,u,w),l=G/Math.sqrt(1-T*Math.pow(Math.sin(f),2)),d=l*(1-T)/(1-T*Math.pow(Math.sin(f),2)),L=Math.pow(Math.cos(f),-1)/l,c=Math.pow(Math.cos(f),-1)/(6*Math.pow(l,3))*(l/d+2*Math.pow(Math.tan(f),2)),S=Math.pow(Math.cos(f),-1)/(120*Math.pow(l,5))*(5+28*Math.pow(Math.tan(f),2)+24*Math.pow(Math.tan(f),4)),v=Math.pow(Math.cos(f),-1)/(5040*Math.pow(l,7))*(61+662*Math.pow(Math.tan(f),2)+1320*Math.pow(Math.tan(f),4)+720*Math.pow(Math.tan(f),6)),H=180/M*(p+g*L-Math.pow(g,3)*c+Math.pow(g,5)*S-Math.pow(g,7)*v);return H},GT_Math.InitialLat=function(t,a,h,o,r,n){for(var e=(t-a)/h+o,i=GT_Math.Marc(n,r,o,e),s=(t-a-i)/h+e;Math.abs(t-a-i)>1e-5;)s=(t-a-i)/h+e,i=GT_Math.Marc(n,r,o,s),e=s;return s},GT_Math.Lat_Long_H_to_X=function(t,a,h,o,r){var n=3.14159265358979,e=t*(n/180),i=a*(n/180),s=(Math.pow(o,2)-Math.pow(r,2))/Math.pow(o,2),M=o/Math.sqrt(1-s*Math.pow(Math.sin(e),2));return(M+h)*Math.cos(e)*Math.cos(i)},GT_Math.Lat_Long_H_to_Y=function(t,a,h,o,r){var n=3.14159265358979,e=t*(n/180),i=a*(n/180),s=(Math.pow(o,2)-Math.pow(r,2))/Math.pow(o,2),M=o/Math.sqrt(1-s*Math.pow(Math.sin(e),2));return(M+h)*Math.cos(e)*Math.sin(i)},GT_Math.Lat_H_to_Z=function(t,a,h,o){var r=3.14159265358979,n=t*(r/180),e=(Math.pow(h,2)-Math.pow(o,2))/Math.pow(h,2),i=h/Math.sqrt(1-e*Math.pow(Math.sin(n),2));return(i*(1-e)+a)*Math.sin(n)},GT_Math.Helmert_X=function(t,a,h,o,r,n,e){var i=3.14159265358979,s=1e-6*e,M=r/3600*(i/180),_=n/3600*(i/180);return t+t*s-a*_+h*M+o},GT_Math.Helmert_Y=function(t,a,h,o,r,n,e){var i=3.14159265358979,s=1e-6*e,M=r/3600*(i/180),_=n/3600*(i/180);return t*_+a+a*s-h*M+o},GT_Math.Helmert_Z=function(t,a,h,o,r,n,e){var i=3.14159265358979,s=1e-6*e,M=r/3600*(i/180),_=n/3600*(i/180);return-1*t*_+a*M+h+h*s+o},GT_Math.XYZ_to_Lat=function(t,a,h,o,r){var n=Math.sqrt(Math.pow(t,2)+Math.pow(a,2)),e=(Math.pow(o,2)-Math.pow(r,2))/Math.pow(o,2),i=Math.atan2(h,n*(1-e)),s=GT_Math.Iterate_XYZ_to_Lat(o,e,i,h,n),M=3.14159265358979;return s*(180/M)},GT_Math.Iterate_XYZ_to_Lat=function(t,a,h,o,r){for(var n=t/Math.sqrt(1-a*Math.pow(Math.sin(h),2)),e=Math.atan2(o+a*n*Math.sin(h),r);Math.abs(h-e)>1e-9;)h=e,n=t/Math.sqrt(1-a*Math.pow(Math.sin(h),2)),e=Math.atan2(o+a*n*Math.sin(h),r);return e},GT_Math.XYZ_to_Long=function(t,a){var h=3.14159265358979;return Math.atan2(a,t)*(180/h)},GT_Math.Marc=function(t,a,h,o){return t*((1+a+5/4*Math.pow(a,2)+5/4*Math.pow(a,3))*(o-h)-(3*a+3*Math.pow(a,2)+21/8*Math.pow(a,3))*Math.sin(o-h)*Math.cos(o+h)+(15/8*Math.pow(a,2)+15/8*Math.pow(a,3))*Math.sin(2*(o-h))*Math.cos(2*(o+h))-35/24*Math.pow(a,3)*Math.sin(3*(o-h))*Math.cos(3*(o+h)))},GT_Math.Lat_Long_to_East=function(t,a,h,o,r,n,e,i){var s=3.14159265358979,M=t*(s/180),_=a*(s/180),p=i*(s/180),G=h*n,w=o*n,T=(Math.pow(G,2)-Math.pow(w,2))/Math.pow(G,2),u=G/Math.sqrt(1-T*Math.pow(Math.sin(M),2)),g=u*(1-T)/(1-T*Math.pow(Math.sin(M),2)),f=u/g-1,l=_-p,d=u*Math.cos(M),L=u/6*Math.pow(Math.cos(M),3)*(u/g-Math.pow(Math.tan(M),2)),c=u/120*Math.pow(Math.cos(M),5)*(5-18*Math.pow(Math.tan(M),2)+Math.pow(Math.tan(M),4)+14*f-58*Math.pow(Math.tan(M),2)*f);return r+l*d+Math.pow(l,3)*L+Math.pow(l,5)*c},GT_Math.Lat_Long_to_North=function(t,a,h,o,r,n,e,i,s){var M=3.14159265358979,_=t*(M/180),p=a*(M/180),G=i*(M/180),w=s*(M/180),T=h*e,u=o*e,g=(Math.pow(T,2)-Math.pow(u,2))/Math.pow(T,2),f=(T-u)/(T+u),l=T/Math.sqrt(1-g*Math.pow(Math.sin(_),2)),d=l*(1-g)/(1-g*Math.pow(Math.sin(_),2)),L=l/d-1,c=p-w,S=GT_Math.Marc(u,f,G,_),v=S+n,H=l/2*Math.sin(_)*Math.cos(_),y=l/24*Math.sin(_)*Math.pow(Math.cos(_),3)*(5-Math.pow(Math.tan(_),2)+9*L),N=l/720*Math.sin(_)*Math.pow(Math.cos(_),5)*(61-58*Math.pow(Math.tan(_),2)+Math.pow(Math.tan(_),4));return v+Math.pow(c,2)*H+Math.pow(c,4)*y+Math.pow(c,6)*N};
ON('change-geometry', function(e) {
// create a wgs84 coordinate
wgs84 = new GT_WGS84();
wgs84.setDegrees(LATITUDE(), LONGITUDE());
// convert to OSGB
osgb = wgs84.getOSGB();
// get a grid reference with 3 digits of precision
gridref = osgb.getGridRef(3);
// set the value of the 'bng' text field
SETVALUE('bng', gridref);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment