Election results in the London Borough of Sutton.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

182 lines
5.6 KiB

  1. # https://raw.github.com/LambethCouncil/OSGB36_Converter/master/OSGB36.rb
  2. module OSGB36
  3. extend self
  4. # Takes OSGB36 Easting/Northing coords
  5. # and returns WGS84 Latitude and Longitude
  6. def en_to_ll(easting, northing)
  7. @OSGB36_ll = to_OSGB36(easting, northing)
  8. to_WGS84(@OSGB36_ll[:latitude], @OSGB36_ll[:longitude])
  9. end
  10. # Takes OSGB36 Easting/Northing coords and returns
  11. # OSGB36 Latitude and Longitude
  12. def to_OSGB36(easting, northing)
  13. @OSGB_F0 = 0.9996012717
  14. @N0 = -100000.0
  15. @E0 = 400000.0
  16. @phi0 = deg_to_rad(49.0)
  17. @lambda0 = deg_to_rad(-2.0)
  18. @a = 6377563.396
  19. @b = 6356256.909
  20. @eSquared = ((@a * @a) - (@b * @b)) / (@a * @a)
  21. @phi = 0.0
  22. @lambda = 0.0
  23. @E = easting
  24. @N = northing
  25. @n = (@a - @b) / (@a + @b)
  26. @M = 0.0
  27. @phiPrime = ((@N - @N0) / (@a * @OSGB_F0)) + @phi0
  28. begin
  29. @M =
  30. (@b * @OSGB_F0)\
  31. * (((1 + @n + ((5.0 / 4.0) * @n * @n) + ((5.0 / 4.0) * @n * @n * @n))\
  32. * (@phiPrime - @phi0))\
  33. - (((3 * @n) + (3 * @n * @n) + ((21.0 / 8.0) * @n * @n * @n))\
  34. * Math.sin(@phiPrime - @phi0)\
  35. * Math.cos(@phiPrime + @phi0))\
  36. + ((((15.0 / 8.0) * @n * @n) + ((15.0 / 8.0) * @n * @n * @n))\
  37. * Math.sin(2.0 * (@phiPrime - @phi0))\
  38. * Math.cos(2.0 * (@phiPrime + @phi0)))\
  39. - (((35.0 / 24.0) * @n * @n * @n)\
  40. * Math.sin(3.0 * (@phiPrime - @phi0))\
  41. * Math.cos(3.0 * (@phiPrime + @phi0))))
  42. @phiPrime += (@N - @N0 - @M) / (@a * @OSGB_F0)
  43. end while ((@N - @N0 - @M) >= 0.001)
  44. @v = @a * @OSGB_F0 * ((1.0 - @eSquared * sin_pow_2(@phiPrime)) ** -0.5)
  45. @rho =
  46. @a\
  47. * @OSGB_F0\
  48. * (1.0 - @eSquared)\
  49. * ((1.0 - @eSquared * sin_pow_2(@phiPrime)) ** -1.5)
  50. @etaSquared = (@v / @rho) - 1.0
  51. @VII = Math.tan(@phiPrime) / (2 * @rho * @v)
  52. @VIII =
  53. (Math.tan(@phiPrime) / (24.0 * @rho * (@v ** 3.0)))\
  54. * (5.0\
  55. + (3.0 * tan_pow_2(@phiPrime))\
  56. + @etaSquared\
  57. - (9.0 * tan_pow_2(@phiPrime) * @etaSquared))
  58. @IX =
  59. (Math.tan(@phiPrime) / (720.0 * @rho * (@v ** 5.0)))\
  60. * (61.0\
  61. + (90.0 * tan_pow_2(@phiPrime))\
  62. + (45.0 * tan_pow_2(@phiPrime) * tan_pow_2(@phiPrime)))
  63. @X = sec(@phiPrime) / @v
  64. @XI =
  65. (sec(@phiPrime) / (6.0 * @v * @v * @v))\
  66. * ((@v / @rho) + (2 * tan_pow_2(@phiPrime)))
  67. @XII =
  68. (sec(@phiPrime) / (120.0 * (@v ** 5.0)))\
  69. * (5.0\
  70. + (28.0 * tan_pow_2(@phiPrime))\
  71. + (24.0 * tan_pow_2(@phiPrime) * tan_pow_2(@phiPrime)))
  72. @XIIA =
  73. (sec(@phiPrime) / (5040.0 * (@v ** 7.0)))\
  74. * (61.0\
  75. + (662.0 * tan_pow_2(@phiPrime))\
  76. + (1320.0 * tan_pow_2(@phiPrime) * tan_pow_2(@phiPrime))\
  77. + (720.0\
  78. * tan_pow_2(@phiPrime)\
  79. * tan_pow_2(@phiPrime)\
  80. * tan_pow_2(@phiPrime)))
  81. @phi =
  82. @phiPrime\
  83. - (@VII * ((@E - @E0) ** 2.0))\
  84. + (@VIII * ((@E - @E0) ** 4.0))\
  85. - (@IX * ((@E - @E0) ** 6.0))
  86. @lambda =
  87. @lambda0\
  88. + (@X * (@E - @E0))\
  89. - (@XI * ((@E - @E0) ** 3.0))\
  90. + (@XII * ((@E - @E0) ** 5.0))\
  91. - (@XIIA * ((@E - @E0) ** 7.0))
  92. { :latitude => rad_to_deg(@phi), :longitude => rad_to_deg(@lambda) }
  93. end
  94. # Takes OSGB36 Latitude and Longitude coords
  95. # and returns WGS84 Latitude and Longitude
  96. def to_WGS84(latitude,longitude)
  97. @a = 6377563.396
  98. @b = 6356256.909
  99. @eSquared = ((@a * @a) - (@b * @b)) / (@a * @a)
  100. @phi = deg_to_rad(latitude)
  101. @lambda = deg_to_rad(longitude)
  102. @v = @a / (Math.sqrt(1 - @eSquared * sin_pow_2(@phi)))
  103. @H = 0
  104. @x = (@v + @H) * Math.cos(@phi) * Math.cos(@lambda)
  105. @y = (@v + @H) * Math.cos(@phi) * Math.sin(@lambda)
  106. @z = ((1 - @eSquared) * @v + @H) * Math.sin(@phi)
  107. @tx = 446.448
  108. @ty = -124.157
  109. @tz = 542.060
  110. @s = -0.0000204894
  111. @rx = deg_to_rad( 0.00004172222)
  112. @ry = deg_to_rad( 0.00006861111)
  113. @rz = deg_to_rad( 0.00023391666)
  114. @xB = @tx + (@x * (1 + @s)) + (-@rx * @y) + (@ry * @z)
  115. @yB = @ty + (@rz * @x) + (@y * (1 + @s)) + (-@rx * @z)
  116. @zB = @tz + (-@ry * @x) + (@rx * @y) + (@z * (1 + @s))
  117. @a = 6378137.000
  118. @b = 6356752.3141
  119. @eSquared = ((@a * @a) - (@b * @b)) / (@a * @a)
  120. @lambdaB = rad_to_deg(Math.atan(@yB / @xB))
  121. @p = Math.sqrt((@xB * @xB) + (@yB * @yB))
  122. @phiN = Math.atan(@zB / (@p * (1 - @eSquared)))
  123. (1..10).each do |i|
  124. @v = @a / (Math.sqrt(1 - @eSquared * sin_pow_2(@phiN)))
  125. @phiN1 = Math.atan((@zB + (@eSquared * @v * Math.sin(@phiN))) / @p)
  126. @phiN = @phiN1
  127. end
  128. @phiB = rad_to_deg(@phiN)
  129. { :latitude => @phiB, :longitude => @lambdaB }
  130. end
  131. private # Some Math
  132. def deg_to_rad(degrees)
  133. degrees / 180.0 * Math::PI
  134. end
  135. def rad_to_deg(r)
  136. (r/Math::PI)*180
  137. end
  138. def sin_pow_2(x)
  139. Math.sin(x) * Math.sin(x)
  140. end
  141. def cos_pow_2(x)
  142. Math.cos(x) * Math.cos(x)
  143. end
  144. def tan_pow_2(x)
  145. Math.tan(x) * Math.tan(x)
  146. end
  147. def sec(x)
  148. 1.0 / Math.cos(x)
  149. end
  150. end