osgb_wgs84 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []