osgb_wgs84 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/osgb_wgs84.rb +190 -0
  2. metadata +51 -0
@@ -0,0 +1,190 @@
1
+ class OSGB_WGS84
2
+ #ellipse parameters
3
+ @e = { :wgs84 => { :a=> 6378137, :b=> 6356752.3142, :f=> 1 / 298.257223563 },
4
+ :airy1830 => { :a=> 6377563.396, :b=> 6356256.910, :f=> 1 / 299.3249646 } };
5
+
6
+ #helmert transform parameters
7
+ @h = { :wgs84toOSGB36 => { :tx=> -446.448, :ty=> 125.157, :tz=> -542.060, # m
8
+ :rx=> -0.1502, :ry=> -0.2470, :rz=> -0.8421, # sec
9
+ :s=> 20.4894 }, # ppm
10
+ :osgb36toWGS84 => { :tx=> 446.448, :ty=> -125.157, :tz=> 542.060,
11
+ :rx=> 0.1502, :ry=> 0.2470, :rz=> 0.8421,
12
+ :s=> -20.4894 } };
13
+
14
+
15
+ def self.OSGB36_to_WGS84(p1lat, p1lon, p1height)
16
+ p2 = convert(p1lat, p1lon, p1height, @e[:airy1830], @h[:osgb36toWGS84], @e[:wgs84]);
17
+ return p2;
18
+ end
19
+
20
+
21
+ def self.WGS84_to_OSGB36(p1lat, p1lon, p1height)
22
+ p2 = convert(p1lat, p1lon, p1height, @e[:wgs84], @h[:wgs84toOSGB36], @e[:airy1830]);
23
+ return p2;
24
+ end
25
+
26
+ # OSGB36 lat lon to OS UK grid eastings & northings
27
+ # http://www.movable-type.co.uk/scripts/latlong-gridref.html
28
+ def self.OSGB36_to_OSNG(lat, long)
29
+ lat = toRad(lat);
30
+ lon = toRad(long);
31
+
32
+ a = 6377563.396; b = 6356256.910 # Airy 1830 major & minor semi-axes
33
+ f0 = 0.9996012717 # NatGrid scale factor on central meridian
34
+ lat0 = toRad(49); lon0 = toRad(-2) # NatGrid true origin
35
+ n0 = -100000; e0 = 400000; # northing & easting of true origin, metres
36
+ e2 = 1 - (b*b) / (a*a); # eccentricity squared
37
+ n = (a-b) / (a+b); n2 = n*n; n3 = n*n*n;
38
+
39
+ cosLat = Math.cos(lat); sinLat = Math.sin(lat);
40
+ nu = a*f0/Math.sqrt(1-e2*sinLat*sinLat); # transverse radius of curvature
41
+ rho = a*f0*(1-e2) / ( (1-e2*sinLat*sinLat) ** 1.5); # meridional radius of curvature
42
+ eta2 = nu/rho-1;
43
+
44
+ ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0);
45
+ mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0);
46
+ mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0));
47
+ md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0));
48
+ m = b * f0 * (ma - mb + mc - md); # meridional arc
49
+
50
+ cos3lat = cosLat*cosLat*cosLat;
51
+ cos5lat = cos3lat*cosLat*cosLat;
52
+ tan2lat = Math.tan(lat)*Math.tan(lat);
53
+ tan4lat = tan2lat*tan2lat;
54
+
55
+ i = m + n0;
56
+ ii = (nu/2)*sinLat*cosLat;
57
+ iii = (nu/24)*sinLat*cos3lat*(5-tan2lat+9*eta2);
58
+ iiiA = (nu/720)*sinLat*cos5lat*(61-58*tan2lat+tan4lat);
59
+ iv = nu*cosLat;
60
+ v = (nu/6)*cos3lat*(nu/rho-tan2lat);
61
+ vi = (nu/120) * cos5lat * (5 - 18*tan2lat + tan4lat + 14*eta2 - 58*tan2lat*eta2);
62
+
63
+ dLon = lon-lon0;
64
+ dLon2 = dLon*dLon
65
+ dLon3 = dLon2*dLon
66
+ dLon4 = dLon3*dLon
67
+ dLon5 = dLon4*dLon
68
+ dLon6 = dLon5*dLon
69
+
70
+ n = i + ii*dLon2 + iii*dLon4 + iiiA*dLon6;
71
+ e = e0 + iv*dLon + v*dLon3 + vi*dLon5;
72
+
73
+ return [ e, n ] #return raw easting and northings instead
74
+
75
+ #return gridrefNumToLet( e, n, 8)
76
+ end
77
+
78
+ #convert numeric grid reference (in metres) to standard-form grid ref
79
+ def self.OSNG_numbers_to_letters(e, n, digits)
80
+ #get the 100km-grid indices
81
+ e100k = (e / 100000).floor; n100k = (n / 100000).floor;
82
+
83
+ return '' if (e100k<0 or e100k>6 or n100k<0 or n100k>12)
84
+
85
+ #translate those into numeric equivalents of the grid letters
86
+ l1 = (19-n100k) - (19-n100k) % 5 + ((e100k+10) / 5).floor;
87
+ l2 = (19-n100k) * 5 % 25 + e100k % 5;
88
+
89
+ # compensate for skipped 'I' and build grid letter-pairs
90
+ l1=l1+1 if (l1 > 7)
91
+ l2=l2+1 if (l2 > 7)
92
+ # letPair = (l1 +'A'[0]).chr + (l2 +'A'[0]).chr ; #(Old code for Ruby 1.8 replaced with following line for ruby1.9)
93
+ letPair = (l1 +'A'.unpack('C')[0]).chr + (l2 +'A'.unpack('C')[0]).chr ;
94
+
95
+ # strip 100km-grid indices from easting & northing, and reduce precision
96
+ e = ( (e % 100000) / (10 ** (5 - digits / 2)) ).floor;
97
+ n = ( (n % 100000) / (10 ** (5 - digits / 2)) ).floor;
98
+
99
+ gridRef = letPair + e.to_s.rjust(digits / 2) + n.to_s.rjust(digits / 2)
100
+
101
+ return gridRef;
102
+ end
103
+
104
+ private
105
+
106
+ def self.toRad(degrees)
107
+ return degrees * Math::PI / 180;
108
+ end
109
+
110
+ def self.toDeg(rads)
111
+ return rads * 180 / Math::PI
112
+ end
113
+
114
+ def self.convert(p1lat, p1lon, p1height, e1, t, e2)
115
+ # -- convert polar to cartesian coordinates (using ellipse 1)
116
+
117
+ p1lat = toRad(p1lat); p1lon = toRad(p1lon);
118
+
119
+ a = e1[:a]; b = e1[:b];
120
+
121
+ sinPhi = Math.sin(p1lat); cosPhi = Math.cos(p1lat);
122
+ sinLambda = Math.sin(p1lon); cosLambda = Math.cos(p1lon);
123
+ h = p1height;
124
+
125
+ eSq = (a*a - b*b) / (a*a);
126
+ nu = a / Math.sqrt(1 - eSq*sinPhi*sinPhi);
127
+
128
+ x1 = (nu+h) * cosPhi * cosLambda;
129
+ y1 = (nu+h) * cosPhi * sinLambda;
130
+ z1 = ((1-eSq)*nu + h) * sinPhi;
131
+
132
+
133
+ # -- apply helmert transform using appropriate params
134
+
135
+ tx = t[:tx]; ty = t[:ty]; tz = t[:tz];
136
+ rx = t[:rx] / 3600 * Math::PI/180; #normalise seconds to radians
137
+ ry = t[:ry] / 3600 * Math::PI/180;
138
+ rz = t[:rz] / 3600 * Math::PI/180;
139
+ s1 = t[:s] / 1e6 + 1; #normalise ppm to (s+1)
140
+
141
+ #apply transform
142
+ x2 = tx + x1*s1 - y1*rz + z1*ry;
143
+ y2 = ty + x1*rz + y1*s1 - z1*rx;
144
+ z2 = tz - x1*ry + y1*rx + z1*s1;
145
+
146
+
147
+ # -- convert cartesian to polar coordinates (using ellipse 2)
148
+
149
+ a = e2[:a]; b = e2[:b];
150
+ precision = 4 / a; # results accurate to around 4 metres
151
+
152
+ eSq = (a*a - b*b) / (a*a);
153
+ p = Math.sqrt(x2*x2 + y2*y2);
154
+ phi = Math.atan2(z2, p*(1-eSq)); phiP = 2 * Math::PI;
155
+ while ( (phi-phiP).abs > precision) do
156
+ nu = a / Math.sqrt(1 - eSq*Math.sin(phi)*Math.sin(phi));
157
+ phiP = phi;
158
+ phi = Math.atan2(z2 + eSq*nu*Math.sin(phi), p);
159
+ end
160
+ lambda = Math.atan2(y2, x2);
161
+ h = p/Math.cos(phi) - nu;
162
+
163
+ #return array [lat,lon,height]
164
+ return [ toDeg(phi), toDeg(lambda), h ];
165
+ end
166
+
167
+ # # Example WGS84 lat/lon to convert
168
+ # lon = -0.10322
169
+ # lat = 51.52237
170
+
171
+
172
+ # osgb36point = OSGB_WGS84::WGS84_to_OSGB36(lat,lon, height)
173
+ # oslat = osgb36point[0]
174
+ # oslon = osgb36point[1]
175
+ # osh = osgb36point[2]
176
+
177
+ # osUKgridPoint = OSGB_WGS84::OSGB36_to_OSNG(oslat,oslon)
178
+ # easting = osUKgridPoint[0].round
179
+ # northing = osUKgridPoint[1].round
180
+
181
+ # gridrefLetters = OSGB_WGS84::OSNG_numbers_to_letters(easting,northing, 8)
182
+
183
+ # puts "wgs84 lat:" + lat.to_s + ", wgs84 lon:" + lon.to_s
184
+ # puts "http://www.openstreetmap.org/?mlat=" + lat.to_s + "&mlon=" + lon.to_s + "&zoom=16"
185
+ # puts "Converts to:";
186
+ # puts "osgb36 lat:" + oslat.to_s + ", osgb36 lon:" + oslon.to_s
187
+ # puts "Converts to:";
188
+ # puts "easting:" + easting.to_s + ", northing:" + northing.to_s + " As a grid ref:" + gridrefLetters
189
+ # puts "http://streetmap.co.uk/grid/" + easting.to_s + "_" + northing.to_s + "_106"
190
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: osgb_wgs84
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Veness
9
+ - Harry Wood
10
+ - Aaron B. Russell
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2012-09-21 00:00:00.000000000 Z
15
+ dependencies: []
16
+ description: This gem converts Ordnance Survey National Grid co-ordinates to and from
17
+ WGS84 co-ordinates. It is based on a JavaScript implementation originally by Chris
18
+ Veness, which was then ported to Ruby by Harry Wood and bundled into a gem by Aaron
19
+ B. Russell.
20
+ email: aaron@unadopted.co.uk
21
+ executables: []
22
+ extensions: []
23
+ extra_rdoc_files: []
24
+ files:
25
+ - lib/osgb_wgs84.rb
26
+ homepage: https://github.com/arussell/osgb_wgs84
27
+ licenses:
28
+ - CC-BY
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubyforge_project:
47
+ rubygems_version: 1.8.24
48
+ signing_key:
49
+ specification_version: 3
50
+ summary: Ordnance Survey National Grid to WGS84 co-ordinate converter
51
+ test_files: []