Class: Silva::Transform

Inherits:
Object
  • Object
show all
Defined in:
lib/silva/transform.rb

Overview

Encapsulates the hairy maths required to perform the various transforms. Checked against documentation provided by Orndance Survey: www.ordnancesurvey.co.uk/oswebsite/gps/osnetfreeservices/furtherinfo/questdeveloper.html www.ordnancesurvey.co.uk/oswebsite/gps/information/coordinatesystemsinfo/guidecontents/guide6.html

Constant Summary collapse

AIRY1830 =

The Airy ellipsoid used by the OSGB36 datum.

{ :a => 6377563.396, :b => 6356256.91 }
GRS80 =

The GRS80 ellipsoid used by the WGS84 datum.

{ :a => 6378137, :b=> 6356752.3141 }
N0 =

The northing of true origin

-100000.0
# The easting of true origin
E0 =

The easting of true origin

400000.0
F0 =

The scale factor on central meridian

0.9996012717
PHI0 =

The latitude of true origin, in radians

49 * Math::PI / 180
LAMBDA0 =

The longitude of true origin, in radians

-2 * Math::PI / 180
HELMERT_PARAMS =

Helmert transform parameters

{
  :tx=> -446.448, :ty=> 125.157, :tz=> -542.060, # m
  :rx=> -0.1502, :ry=> -0.2470, :rz=> -0.8421, # sec
  :s=> 20.4894 # ppm
}
DEGREE_ROUNDING_PLACES =

Decimal places to round results in degrees.

6

Class Method Summary collapse

Class Method Details

.en_to_osgb36(en) ⇒ Silva::System::Osgb36

Convert an OSGB36 easting, northing system to :osgb36 co-ordinate system

Parameters:

Returns:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/silva/transform.rb', line 73

def self.en_to_osgb36(en)
  # Algorithm from:
  # http://www.ordnancesurvey.co.uk/oswebsite/gps/osnetfreeservices/furtherinfo/questdeveloper.html
  a, b = AIRY1830[:a], AIRY1830[:b]
  e = en.easting
  n = en.northing
  phi_prime = PHI0
  m = 0

  while n - N0 - m >= 0.0001 do
    phi_prime = (n - N0 - m) / (a * F0) + phi_prime
    m = meridional_arc(phi_prime)
  end

  nu, rho, eta2 = transverse_and_meridional_radii(phi_prime)

  vii = Math.tan(phi_prime) / (2 * rho * nu)
  viii = Math.tan(phi_prime)/(24 * rho * nu**3) * \
  (5 + 3 * Math.tan(phi_prime)**2 + eta2 - 9 * Math.tan(phi_prime)**2 * eta2)
  ix = Math.tan(phi_prime) / (720 * rho * nu**5) * (61 + 90 * Math.tan(phi_prime)**2 + 45 * Math.tan(phi_prime)**4)
  x = (1 / Math.cos(phi_prime)) / nu
  xi = (1 / Math.cos(phi_prime)) / (6 * nu**3) * (nu / rho + 2 * Math.tan(phi_prime)**2)
  xii = (1 / Math.cos(phi_prime)) / (120 * nu**5) * (5 + 28 * Math.tan(phi_prime)**2 + 24 * Math.tan(phi_prime)**4)
  xiia = (1 / Math.cos(phi_prime)) / (5040 * nu**7) * \
  (61 + 662 * Math.tan(phi_prime)**2 + 1320 * Math.tan(phi_prime)**4 + 720 * Math.tan(phi_prime)**6)

  phi = phi_prime - vii * (e - E0)**2 + viii * (e - E0)**4 - ix * (e - E0)**6
  lambda = LAMBDA0 + x * (e - E0) - xi * (e - E0)**3 + xii * (e - E0)**5 - xiia * (e - E0)**7

  System.create(:osgb36, :lat => to_deg(phi).round(DEGREE_ROUNDING_PLACES), \
                :long => to_deg(lambda).round(DEGREE_ROUNDING_PLACES), :alt => 0)
end

.osgb36_to_en(osgb36) ⇒ Silva::System::En

Convert an :osgb36 co-ordinate system to :en (eastings and northings)

Parameters:

Returns:



63
64
65
# File 'lib/silva/transform.rb', line 63

def self.osgb36_to_en(osgb36)
  self.latlong_to_en(osgb36, AIRY1830)
end

.osgb36_to_wgs84(osgb36) ⇒ Silva::System::Wgs84

Convert an :osgb36 co-ordinate system :wgs84

Parameters:

Returns:



43
44
45
# File 'lib/silva/transform.rb', line 43

def self.osgb36_to_wgs84(osgb36)
  helmert_transform(osgb36, :wgs84, AIRY1830, HELMERT_PARAMS.inject({}) { |h, (k, v)| h[k] = v * -1; h }, GRS80)
end

.wgs84_to_osgb36(wgs84) ⇒ Silva::System::Osgb36

Convert a :wgs84 co-ordinate system to :osgb36

Parameters:

Returns:



53
54
55
# File 'lib/silva/transform.rb', line 53

def self.wgs84_to_osgb36(wgs84)
  helmert_transform(wgs84, :osgb36, GRS80, HELMERT_PARAMS, AIRY1830)
end