﻿B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=8.3
@EndOfDesignText@

' Conversions between Lat/Lon and local grid systems and supporting utilities.

' TRF = Terrestrial Reference Frame.  Grid = Cartesian Grid.


Sub Class_Globals
	
	Type LatLon (Latitude, Longitude As Double)					' Latitude/Longitude reference in degrees
  Type GridRef (Easting, Northing As Double)					' Cartesian grid reference in metres
	
	Dim PI As Double = 3.1415926535897932385
	Dim RADIAN As Double = 2.0 * PI / 360	
	
End Sub

Public Sub Initialize
		
End Sub


Private Sub TRFtoGrid(Degrees As LatLon, a As Double, b As Double, N0 As Int, E0 As Int, F0 As Double, phi0 As Double, lambda0 As Double) As GridRef
'	TRF Lat/Lon To Grid East/North by Transverse Mercator projection.

'	<Phi> is latitude - negative if south of equator (all angles in radians)
'	<Lambda> is longitude - negative if west of prime meridian
'	<a> And <b> are major and minor axes of ellipsoid
'	<N0> And <E0> are easting and northing of grid origin
'	<F0> is scale factor on central meridian of grid
'	<phi0> And <lambda0> are latitude and longitude of grid origin
'	<East> And <North> are easting and northing of converted grid reference

	Dim Phi, Lambda As Double
	Dim n, n2, n3, e2, nu, rho, eta2 As Double					' Geometric terms
	Dim M, I, II, III, IIIa, IV, V, VI As Double  	    ' Intermediate terms
	Dim sin1, sin2, cos1, cos2, cos3, cos5 As Double
	Dim tan1, tan2, tan4 As Double											' Trig's of <phi> and their powers
	Dim phidiff, phi2diff, phi3diff As Double						' (Phi - phi0), (Phi + phi0) and
	Dim phisum, phi2sum, phi3sum As Double							'    their multiples
	Dim L, L2, L3, L4, L5, L6 As Double									' (Lambda - lambda0) And its powers
	Dim x As Double																			' Temporary intermediate value term
	
	Dim result As GridRef

	Phi = Degrees.Latitude * RADIAN											' Convert to radian measure
	Lambda = Degrees.Longitude * RADIAN

  n = (a - b) / (a + b)
  n2 = n * n
  n3 = n2 * n
  e2 = (a * a - b * b) / (a * a)											' Eccentricity squared value

  ' Calculate trigonometric factors
	sin1 = Sin(Phi)	: cos1 = Cos(Phi)
  sin2 = sin1 * sin1
  cos2 = cos1 * cos1	: cos3 = cos2 * cos1	: cos5 = cos3 * cos2
  tan1 = sin1 / cos1	: tan2 = tan1 * tan1	: tan4 = tan2 * tan2

  x = (1 - e2 * sin2)
  nu = a * F0 / Sqrt(x)
  rho = a * F0 * ( 1 - e2) / Sqrt(x * x * x)

  eta2 = nu / rho - 1.0

  phidiff = (Phi - phi0)	: phi2diff = phidiff + phidiff
  phi3diff = phi2diff + phidiff
  phisum = (Phi + phi0)	: phi2sum = phisum + phisum
  phi3sum = phi2sum + phisum

  M = b*F0 * ( (1 + n + 1.25 * (n2 + n3)) * phidiff _
                - (3 * (n + n2) + 2.625 * n3) * Sin(phidiff) * Cos (phisum) _
                + 1.875 * (n2 + n3) * Sin(phi2diff) * Cos(phi2sum) _
                - 35/24 * n3 * Sin(phi3diff) * Cos(phi3sum))
  I = M + N0
  x = nu * sin1
  II = x * cos1 * 0.5
  III = x * cos3 * (5 - tan2 + 9*eta2) / 24
  IIIa = x * cos5 * (61 - 58*tan2 + tan4) / 720
  IV = nu * cos1
  V = nu * cos3 * (nu / rho - tan2) / 6
  VI = nu * cos5 * (5 - 18*tan2 + tan4 + 14*eta2 - 58*tan2*eta2) / 120

  L = (Lambda - lambda0)
  L2 = L * L	: L3 = L2 * L	: L4 = L3 * L	: L5 = L4 * L	: L6 = L5 * L

	result.Northing = I + II * L2 + III * L4 + IIIa * L6
	result.Easting = E0 + IV * L + V * L3 + VI * L5
	Return result	
End Sub

Private Sub GridToTRF(Position As GridRef, a As Double, b As Double, N0 As Double, E0 As Double, F0 As Double, phi0 As Double, lambda0 As Double) As LatLon
' Grid East/North To TRF Lat/Lon by Inverse Transverse Mercator projection

' <East> And <North> are easting and northing of converted grid reference.
' <a> And <b> are major and minor axes of ellipsoid.
' <N0> And <E0> are easting and northing of grid origin.
' <F0> Is scale factor on central meridian of grid.
' <phi0> And <lambda0> are latitude and longitude of grid origin.
' <Phi> Is latitude - negative If south of equator (all in radians).
' <Lambda> Is longitude - negative If west of prime meridian.

	Dim East, North As Double
	Dim n, n2, n3, e2, rho, eta2 As Double							' Geometric terms
  Dim nu, nu2, nu3, nu5, nu7 As Double
  Dim M, VII, VIII, IX, X, XI, XII, XIIA As Double		' Intermediate terms
  Dim phi1 As Double																	' <Phi prime> in OS booklet
  Dim sin1, sin2, cos1, sec As Double
  Dim tan1, tan2, tan4, tan6 As Double								' Trig's of <phi1> and their powers
  Dim phidiff, phi2diff, phi3diff As Double						' (phi1 - phi0), (phi1 + phi0) and
  Dim phisum, phi2sum, phi3sum As Double							' their multiples
  Dim Ediff, Ediff2 As Double													' (E - E0) and its square
  Dim z As Double																			' Temporary intermediate value term
	
	Dim result As LatLon

  East = Position.Easting
	North = Position.Northing
  n = (a - b) / (a + b)																' Calculate 'M' constant terms
  n2 = n * n
  n3 = n2 * n
  e2 = (a * a - b * b) / (a * a)											' Eccentricity squared value

  z = 1 / a /F0
  phi1 = (North - N0) * z + phi0
	Do Until (Abs(North - N0 - M) < 0.001)
    phidiff = (phi1 - phi0)	: phi2diff = phidiff + phidiff
    phi3diff = phi2diff + phidiff
    phisum = (phi1 + phi0)	: phi2sum = phisum + phisum
    phi3sum = phi2sum + phisum
    M = b * F0 * ((1 + n + 1.25 * (n2 + n3)) * phidiff _
              - (3 * (n + n2) + 2.625 * n3) * Sin(phidiff) * Cos (phisum) _
              + 1.875 * (n2 + n3) * Sin(phi2diff) * Cos(phi2sum) _
              - 35/24 * n3 * Sin(phi3diff) * Cos(phi3sum))
    phi1 = (North - N0 - M) * z + phi1
	Loop

	' Now that <phi1> has been determined calculate trigonometric factors
  sin1 = Sin(phi1)	: cos1 = Cos(phi1)
  sin2 = sin1 * sin1	: sec = 1 / cos1
  tan1 = sin1 / cos1	: tan2 = tan1 * tan1	: tan4 = tan2 * tan2
  tan6 = tan2 * tan4

  z = (1 - e2 * sin2)
  nu = a * F0 / Sqrt(z)
  nu2 = nu * nu	: nu3 = nu2 * nu	: nu5 = nu2 * nu3	: nu7 = nu5 * nu2
  rho = a * F0 * ( 1 - e2) / Sqrt(z * z * z)
  eta2 = nu / rho - 1.0

  VII = tan1 / rho / nu * 0.5
  VIII = tan1 / rho / nu3 * (5 + 3 * tan2 + eta2 - 9 * tan2 * eta2) / 24
  IX = tan1 / rho / nu5 * (61 + 90 * tan2 + 45 * tan4) / 720
  X = sec / nu
  XI = sec / nu3 * (nu / rho + tan2 + tan2) / 6
  XII = sec / nu5 * (5 + 28 * tan2 + 24 * tan4) / 120
  XIIA = sec / nu7 * (61 + 662 * tan2 + 1320 * tan4 + 720 * tan6) / 5040

  Ediff = (East - E0)	: Ediff2 = Ediff * Ediff
  result.Latitude = (phi1 + Ediff2 * (-VII + Ediff2 * (VIII - IX * Ediff2))) / RADIAN
	result.Longitude = (lambda0 + Ediff * (X - XI * (Ediff2 + XII * ( Ediff2 - XIIA * Ediff2)))) / RADIAN
	Return result
End Sub

' Conversion from WGS84/GRS80 ellipsoid To GB National Grid
Public Sub WGS84ToOSGB(TRF As LatLon) As GridRef
  Dim result As GridRef
  result = TRFtoGrid(TRF, 6378137.000, 6356752.3141, -100000, 400000, 0.9996012717, 0.8552113335, -0.03490658504)
	Return result
End Sub

' Conversion from GB National Grid to WGS84 lat/lon
Public Sub OSGBToWGS84(Ref As GridRef) As LatLon
	Dim result As LatLon
	result = GridToTRF(Ref, 6378137.000, 6356752.3141, -100000, 400000, 0.9996012717, 0.8552113335, -0.03490658504)
	Return result
End Sub