Monday, 18 May 2015

Eastings/Northings to LatLngs conversion

The remit here is to take Eastings/Northings (A UK based Ordnance Survey Gridreferencing system) and convert to LatLngs (the grid-referencing done by most GPS systems, and most importantly, Google Maps).

The algorithms for doing these conversions are here, and the accompanying guide I found really interesting. Basically, it comes down to Eastings/Northings are based on a 2-dimensional grid (assuming that England is roughly flat), but LatLngs are based on a 3-dimensional sphere (I'm looking at you, planet Earth...)

This call for me had the perfect storm of lots of complicated maths, knowledge of 2 programming languages, and the sexy prospect of overlaying the results on Google Maps. 

Total trophy moment when I got it to work....

*&---------------------------------------------------------------------*
*& Report  YPD_PL1_LATLNG
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT  YPD_PL1_LATLNG.


datapi type f,
      radPHI0 type f,
      radLAM0 type f,
      af0 type f,
      bf0 type f,
      e2 type f,
      Et type f,
      phi0 type f,
      lam0 type f,
      w_deciPhi0 type f,
      w_DeciLam0 type f,
      o_lat type f,
      o_lng type f.


constantsc_a type value '6377563.396',
           c_b type value '6356256.909',
           c_e0 type value '400000',
           c_n0 type value '100000-',
           c_f0 type value '0.9996012717',
           c_deciPhi0 type value '49.00000000',
           c_deciLam0 type value '2.00000000-',
           c_Phi0 type VALUE '0.855211333',
           C_Lam0 type value '0.034906585-'.

parametersp_east type int4 default '359536',
            p_north type int4 default '403646'.


start-of-selection.

write'East:'p_east', North'p_north.


perform initialise_vars.
perform E_N_to_LAT using p_east p_north c_n0 c_f0 changing o_lat.
perform E_N_to_LNG using p_east p_north c_n0 c_f0 changing o_lng.


form E_N_to_Lat using p_East type int4
                          p_North type int4
                          p_n0 type f
                          p_f0 type f
                 changing e_n_to_lat type f.

dataaf0 type f,
      bf0 type f,
      e2 type f,
      n type f,
      Et type f,
      VII type f,
      VIII type f,
      IX type f,
      PHid type f,
      nu type f,
      rho type f,
      eta2 type f.


*'Un-project Transverse Mercator eastings and northings back to latitude.
*'Input: - _
* eastings (East) and northings (North) in meters; _
* ellipsoid axis dimensions (a & b) in meters; _
* eastings (e0) and northings (n0) of false origin in meters; _
* central meridian scale factor (f0) and _
* latitude (PHI0) and longitude (LAM0) of false origin in decimal degrees.

"'REQUIRES THE "Marc" AND "InitialLat" FUNCTIONS



*'Compute af0, bf0, e squared (e2), n and Et
    af0 c_a * p_f0.
    bf0 c_b * p_f0.
    e2 af0 ** bf0 ** af0 ** .
    n af0 bf0 af0 + bf0 ).
    Et p_East c_e0.

*'Compute initial value for latitude (PHI) in radians
  perform InitialLat using p_north c_n0 af0 RadPHI0 n bf0 changing PHId.



*'Compute nu, rho and eta2 using value for PHId
    nu af0 / Sqrte2 * SinPHId )  ** ).
    rho nu * e2 )  e2 * SINPHId ** ).
    eta2 nu / rho 1.

*'Compute Latitude
    VII TanPHId * rho * nu ).
    VIII TanPHId 24 * rho * nu ** TanPHId ** + eta2 * eta2 * TanPHId ** ).
    IX TanPHId )  720 * rho * nu ** 61 90 TanPHId )  ** 45 TanPHId ** ).

    E_N_to_Lat 180 / Pi PHId Et ** * VII Et ** * VIII Et ** * IX ).

  WRITE:'Lat Calculation'.
  write:'Lat:'e_n_to_lat.
  write:'VII'VII.
  write:'IX'IX.


endform.



form initialise_vars.

    Pi '3.14159265358979' .

"Convert angle measures to radians
    RadPHI0 c_DeciPhi0 * Pi / 180 ).
    RadLAM0 c_DeciLam0 * Pi / 180 ).


endform.


form marc using p_bf0 type f
                   p_n type f
                   p_phi0 type f
                   p_phi type f
          changing p_marc type f.

  dataphi_minus_phi0 type f,
        phi_plus_phi0 type f,
        phi_minus_phi0_times_2 type f,
        phi_plus_phi0_times_2 type f,
        phi_minus_phi0_times_3 type f,
        phi_plus_phi0_times_3 type f.

  datal_test1 type f,
        l_line1 type f,
        l_line2 type f,
        l_line3 type f,
        l_line4 type f.

  DATAL_MARC2 TYPE F.

"Copied from VB Macro Calculation; They can nest function calculations, ABAP can't... stupid ABAP.
  phi_minus_phi0 p_phi p_phi0.
  phi_plus_phi0 p_phi + p_phi0.
  phi_minus_phi0_times_2 phi_minus_phi0 * 2.
  phi_plus_phi0_times_2 phi_plus_phi0 * 2.
  phi_minus_phi0_times_3 phi_minus_phi0 * 3.
  phi_plus_phi0_times_3 phi_plus_phi0 * 3.

  l_test1 SinPhi_minus_phi0 ).

    l_line1 p_bf0.
    l_line1 + p_n + p_n ** p_n ** p_PHI p_PHI0 ).
    l_line2 * p_n p_n ** 21 p_n ** Sinphi_minus_phi0 COSphi_plus_phi0 ).
    l_line3 15 p_n ** 15 p_n ** Sinphi_minus_phi0_times_2 Cosphi_plus_phi0_times_2 ).
    l_line4 35 24 p_n ** Sinphi_minus_phi0_times_3 )  Cosphi_plus_phi0_times_3 ).

*    Marc = bf0 * (((1 + n + ((5 / 4) * (n ^ 2)) + ((5 / 4) * (n ^ 3))) * (PHI - PHI0)) _
*    - (((3 * n) + (3 * (n ^ 2)) + ((21 / 8) * (n ^ 3))) * (Sin(PHI - PHI0)) * (Cos(PHI + PHI0))) _
*    + ((((15 / 8) * (n ^ 2)) + ((15 / 8) * (n ^ 3))) * (Sin(2 * (PHI - PHI0))) * (Cos(2 * (PHI + PHI0)))) _
*    - (((35 / 24) * (n ^ 3)) * (Sin(3 * (PHI - PHI0))) * (Cos(3 * (PHI + PHI0)))))


L_MARC2 p_bf0 * l_line1 l_line2 + l_line3 l_line4 ).

p_marc l_marc2.

*      p_Marc = p_bf0 * ( ( ( 1 + p_n + ( ( 5 / 4 ) * ( p_n ** 2 ) ) + ( ( 5 / 4 ) * ( p_n ** 3 ) ) ) * ( p_PHI - PHI0 ) )
*    - ( ( ( 3 * p_n ) + ( 3 * ( p_n ** 2 ) ) + ( ( 21 / 8 ) * ( p_n ** 3 ) ) ) * ( Sin( phi_minus_phi0 ) ) * ( COS( phi_plus_phi0 ) ) )
*    + ( ( ( ( 15 / 8 ) * ( p_n ** 2 ) ) + ( ( 15 / 8 ) * ( p_n ** 3 ) ) ) * ( Sin( phi_minus_phi0_times_2 ) ) * ( Cos( phi_plus_phi0_times_2 ) ) )
*    - ( ( ( 35 / 24 ) * ( p_n ** 3 ) ) * ( Sin( phi_minus_phi0_times_3 ) )  * ( Cos( phi_plus_phi0_times_3 ) ) ) ) .




endform.


form InitialLat using p_North type int4
                      p_n0 type f
                      P_afo type f
                      p_PHI0 type f
                      p_n type f
                      p_bfo type f
               changing p_InitialLat type f.

*'Compute initial value for Latitude (PHI) IN RADIANS.
*'Input: - _
* northing of point (North) and northing of false origin (n0) in meters; _
* semi major axis multiplied by central meridian scale factor (af0) in meters; _
* latitude of false origin (PHI0) IN RADIANS; _
* n (computed from a, b and f0) and _
* ellipsoid semi major axis multiplied by central meridian scale factor (bf0) in meters.

*'REQUIRES THE "Marc" FUNCTION
*'THIS FUNCTION IS CALLED BY THE "E_N_to_Lat", "E_N_to_Long" and "E_N_to_C" FUNCTIONS
*'THIS FUNCTION IS ALSO USED ON IT'S OWN IN THE  "Projection and Transformation Calculations.xls" SPREADSHEET

datal_phi1 type f,
      l_phi2 type f,
      type f,
      delta type f,
      l_myCounter type f.

"First PHI value (PHI1)
    l_PHI1 p_North p_n0 / p_afo + P_PHI0.

*'Calculate M
    perform marc using p_bfo
                       p_n
                       p_phi0
                       l_phi1
               changing M.


*'Calculate new PHI value (PHI2)
    l_PHI2 p_North p_n0 / p_afo + l_PHI1.

*'Iterate to get final value for InitialLat

    Do 10000 times.       "Prevent Infinity.
      delta p_North p_n0 M.
      if ABSdelta '0.00001'.
        exit.
      endif.

        l_PHI2 (  DELTA  / P_afo + l_PHI1.

    perform marc using p_bfo
                       p_n
                       p_phi0
                       l_phi2
               changing M.


        l_PHI1 l_PHI2.
        l_myCounter l_myCounter + 1.
    enddo.

    p_InitialLat l_PHI2.

endform.

form E_N_to_LNG using p_East type int4
                          p_North type int4
                          p_n0 type f
                          p_f0 type f
                 changing e_n_to_lng type f.


"Un-project Transverse Mercator eastings and northings back to longitude.

dataaf0 type f,
      bf0 type f,
      e2 type f,
      n type f,
      Et type f,
      VII type f,
      VIII type f,
      IX type f,
      PHid type f,
      nu type f,
      rho type f,
      eta2 type f,
      type f,
      XI type f,
      XII type f,
      XIIA type f.


"Compute af0, bf0, e squared (e2), n and Et
    af0 c_a * p_f0.
    bf0 c_b * p_f0.
    e2 af0 ** bf0 ** af0 ** ).
    n af0 bf0 af0 + bf0  ).
    Et p_East c_e0.

*'Compute initial value for latitude (PHI) in radians
  perform InitialLat using p_north c_n0 af0 RadPHI0 n bf0 changing PHId.

*'Compute nu, rho and eta2 using value for PHId
    nu af0 / Sqrte2 * SinPHId )  ** ).
    rho nu * e2 )  e2 * SINPHId ** ).
    eta2 nu / rho 1.

" Compute Longitude
    CosPHId ** -/ nu.
    XI CosPHId ** -nu ** nu / rho TanPHId ** ).
    XII CosPHId ** -120 nu ** 28 TanPHId ** 24 TanPHId ** ).
    XIIA CosPHId ** -5040 nu ** 61 662 TanPHId ** 1320 TanPHId ** 720 TanPHId ** ).

    E_N_to_Lng 180 / Pi RadLAM0 + Et * Et ** * XI Et ** * XII Et ** * XIIA ).

  WRITE:'Lng Calculation'.
  write:'Lat:'e_n_to_lng.

Endform.

No comments:

Post a Comment