Latitude/Longitude Conversion Problem

Here's the situation:
I need some assistance with converting the following:
Background:
1. In Air Navigation, devices known as Navigational Aids (Navaid) send out radio beams known as Radials ranging from 0 to 359 degrees. Distance from the navaid is also transmitted in nautical miles. (known as DME)
2. The latitude/longitude of the Navaid is a known constant.

The Problem:

I have tried everything I can think of to come up with this:
1. Given a Radial & DME, convert to standard Latitude & Longitude
2. Give a Latitude & Longitude, convert to a Radial & DME

Any assistance is greatly appreciated.
dantindallAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

amebaCommented:
2.b distance

Option Explicit
Private Type tpInfo
     ID As String
     x As Double
     y As Double
End Type
Dim airports(1 To 2) As tpInfo

Private Sub Form_Click()
    airports(1).ID = "SJJ"
    airports(1).x = 18.336
    airports(1).y = 43.825
   
    airports(2).ID = "NAP"
    airports(2).x = 14.269
    airports(2).y = 40.834
   
    Dim dist As Double
    dist = distance(airports(1).y, airports(1).x, airports(2).y, airports(2).x)
    MsgBox dist
End Sub

Public Function distance(p1 As Double, t1 As Double, p2 As Double, t2 As Double) As Double
'arccos( Cos[p1]*Cos[p2]*Cos[t2 - t1] + Sin[p1]*Sin[p2] )
    Dim x As Double
    Dim rp1 As Double
    Dim rt1 As Double
    Dim rp2 As Double
    Dim rt2 As Double
    Dim PI As Double
    PI = Atn(1) * 4        'calculate pi
    rp1 = p1 * PI / 180    'change angles in degrees to radians
    rt1 = t1 * PI / 180
    rp2 = p2 * PI / 180
    rt2 = t2 * PI / 180
    'ozo's formula
    x = Cos(rp1) * Cos(rp2) * Cos(rt2 - rt1) + Sin(rp1) * Sin(rp2)
    'find angle, change back to degrees, and multiply by 69
    distance = 69.09398 * Arccos(x) * (180 / PI)
End Function

Private Function Arccos(ByVal x As Double) As Double
'From the VB help - seems to handle -ve angles better
   If Abs(x) <> 1 Then
       Arccos = Atn(-x / Sqr(-x * x + 1)) + 2 * Atn(1)
    Else
        Arccos = IIf(x = 1, 0, Atn(1) * 4)
    End If
End Function
0
amebaCommented:
I'll see if I can find formula, or maybe expert 'ozo' has formula for 2.a (angle).
For 1. you will also need coordinates of 1 airport.
0
BarryTiceCommented:
Are DMEs short enough that we can assume two dimensions (i.e., can we assume the curvature of the earth has a negligible impact on the distance traveled)? This significantly simplifies the geometry.
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

ArkCommented:
Hi dantindall
Here is solution for short distances. It will work fine if distance (DME) not exeed 200 nautical miles. If more, you will need 3D solution. Ameba show you how to calculate distanse (BTW, you need add ABS to the final formula - arccos may be negative, Dist - not). For Azimuth you can use followin formula
CtgA = tgF2*CosF1-SinF1*Cos(L2-L1)
where F1,F2 - Latitude, L2,L1 - Longitude. If you still need long range solution, I'll do it (my base education is Navigation, not air, but sea :))
'----------
Option Explicit
Const LatNavAid = 40
Const LonNavAid = 130
Const PI = 3.1415926
Private Type Lat_Lon
   Lat As Double
   Lon As Double
End Type
Private Type Rad_Dist
   Radial As Double
   DME As Double
End Type
Dim LL As Lat_Lon
Dim RD As Rad_Dist

Private Function RadDist(inpData As Lat_Lon) As Rad_Dist
   Dim dF As Double, dL As Double
   dF = inpData.Lat - LatNavAid
   dL = inpData.Lon - LonNavAid
   If dF = 0 Then
      RadDist.Radial = 90
   Else
      RadDist.Radial = Atn(dL * Cos(LatNavAid * PI / 180) / dF) * 180 / PI
   End If
   If RadDist.Radial < 0 Then RadDist.Radial = RadDist.Radial + 360
   If dF < 0 Then RadDist.Radial = RadDist.Radial + 180
   RadDist.DME = Sqr(dF ^ 2 + (dL * Cos(LatNavAid * PI / 180)) ^ 2)
End Function

Private Function LatLon(inpData As Rad_Dist) As Lat_Lon
   Dim dF As Double, dL As Double
   dF = inpData.DME * Cos(inpData.Radial * PI / 180) / 60
   dL = inpData.DME * Sin(inpData.Radial * PI / 180) * Cos(LatNavAid * PI / 180) / 60
   LatLon.Lat = LatNavAid + dF
   LatLon.Lon = LonNavAid + dL
End Function
'-------------
'Using
Private Sub Command1_Click()
  LL.Lat = 50
  LL.Lon = 140
  Text1 = RadDist(LL).Radial
  Text2 = RadDist(LL).DME
End Sub

Private Sub Command2_Click()
  RD.DME = 100
  RD.Radial = 180
  Text1 = LatLon(RD).Lat
  Text2 = LatLon(RD).Lon
End Sub
0
ArkCommented:
2ameba

Why you multiple degrees to 69.09398?
One Nautical miles = 1 minute, 1 degree=60 minutes

Cheers
0
ArkCommented:
Hi dantindall
Here is LongRange solution
Data formats:
Angle-degrees
Distance - miles
Latitude/longitude - degrees
works around the world :)
'----------------
Option Explicit
Const LatNavAid = 40
Const LonNavAid = 130
Const PI As Double = 3.14159265358979
Private Type Lat_Lon
   Lat As Double
   Lon As Double
End Type
Private Type Rad_Dist
   Radial As Double
   DME As Double
End Type
Dim LL As Lat_Lon
Dim RD As Rad_Dist

Private Function RadDist(inpData As Lat_Lon) As Rad_Dist
   Dim dF As Double, dL As Double
   dF = inpData.Lat - LatNavAid
   dL = inpData.Lon - LonNavAid
   If dF = 0 Then
      RadDist.Radial = 90
   Else
      RadDist.Radial = Atn(Sin(Rad(dL)) / (Tan(Rad(inpData.Lat)) * Cos(Rad(LatNavAid)) - Sin(Rad(LatNavAid)) * Cos(Rad(dL)))) * 180 / PI
   End If
   If RadDist.Radial < 0 Then RadDist.Radial = RadDist.Radial + 360
   If dF < 0 Then RadDist.Radial = RadDist.Radial + 180
   If RadDist.Radial > 360 Then RadDist.Radial = RadDist.Radial - 360
   RadDist.DME = Abs(Arccos(Sin(Rad(LatNavAid)) * Sin(Rad(inpData.Lat)) + Cos(Rad(inpData.Lat)) * Cos(Rad(LatNavAid)) * Cos(Rad(inpData.Lon - LonNavAid)))) * 180 * 60 / PI
   dL = 1
End Function

Private Function LatLon(inpData As Rad_Dist) As Lat_Lon
   Dim dL As Double, tmp As Double
   If inpData.Radial = 90 Or inpData.Radial = 270 Then
      tmp = LatNavAid
   Else
      tmp = Arcsin(Cos(Rad(inpData.DME / 60)) * Sin(Rad(LatNavAid)) + Sin(Rad(inpData.DME / 60)) * Cos(Rad(LatNavAid)) * Cos(Rad(inpData.Radial))) * 180 / PI
   End If
   LatLon.Lat = tmp
   If inpData.Radial = 0 Or inpData.Radial = 180 Then
      dL = 0
   Else
      dL = Arcsin(Sin(Rad(inpData.DME / 60)) * Sin(Rad(inpData.Radial)) / Sqr(1 - Sin(Rad(tmp)) ^ 2)) * 180 / PI
   End If
   LatLon.Lon = LonNavAid + dL
End Function

Private Function Arccos(ByVal x As Double) As Double
   If Abs(x) <> 1 Then
       Arccos = Atn(-x / Sqr(-x * x + 1)) + 2 * Atn(1)
    Else
       Arccos = IIf(x = 1, 0, Atn(1) * 4)
    End If
End Function

Private Function Arcsin(ByVal x As Double) As Double
   If Abs(x) <> 1 Then
       Arcsin = Atn(x / Sqr(-x * x + 1))
    Else
       Arcsin = IIf(x = 1, Atn(1) * 2, Atn(1) * 6)
    End If
End Function

Private Function Rad(x As Double) As Double
  Rad = x * PI / 180
End Function
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
amebaCommented:
>Why you multiple degrees to 69.09398?
Thanks for the correction, you are right, it's one minute of latitude:

"1 international nautical mile = 1.852 km = 1.1508 miles = 6076.1155 feet
The international nautical mile is also known as the international air mile.
The geographical nautical mile is 6080 feet (0.064% larger)."
0
amebaCommented:
>BTW, you need add ABS to the final formula - arccos may be negative
arccos is positive (0 to 180 degrees) :)
0
dantindallAuthor Commented:
Ok,
this got over my head in a hurry. I now know why i never could get the solution on my own.
To clarify a couple of things:

BarryTice:
DME's are not known until runtime. User may want to enter a value of 179 degree Radial at 350 DME.

0
dantindallAuthor Commented:
Thanks to all for the assistance. I think that the answer is at hand.

Ark:
in both of the solutions, you have a couple of constants defined.
LatNavAid
LonNavAid
If I understand this correctly, I should place the Latitude & Longitude of my base navaid in those variables.
The Latitudes/Longitudes that I have and that my users will use are in the format:
Latitude:39,54,57
Longitude:80,54,57

How did you arrive at the values of 40 and 130 respectivly?

Additionally, I dropped the code into a form and placed 4 text boxes on it. Passing in a DME and Radial, the code returns a value in decimal format.
The program that this will be used in will need the latitude/longitudes in a format of:
latitude: 39,54,54
Longitude: 80,54,57
0
tomk120999Commented:
Hi, dantindall, you can convert decimal degrees (DecDeg) to Deg, Min, Sec like this:
Deg = int(DecDeg)
Min = Int((DecDeg - Deg) * 60) 'decimal only * 60 minutes
Sec = Int((DecDeg - Deg - Min/60) * 60^2) 'remaining decimal of a degree * 3600 seconds - Min/60 gives the decimal portion for minutes.

The Int() function discards fractional seconds, and so forth.  To convert Deg, Min, Sec to DecDeg

DecDeg = Deg + Min/60 + Sec/(60^2) 'or Sec/3600, the number of seconds per degree.

HTH, good luck as usual...
0
ArkCommented:
Hi dantindall
My functions both work with decimal format. Your input and output formats are strings. You can convert them to/from with following functions

Private Function Dec2Str(x As Double) As String
  Dim Deg As Integer, Min As Integer, Sec As Integer
  Dim y As Double
  y = Abs(x)
  Deg = Int(y)
  Min = Right$("0" & CStr(Int((y - Deg) * 60)), 2) & ","
  Sec = Right$("0" & CStr(Int((y - Deg - Min / 60) * 3600)), 2)
  Dec2String = CStr(Deg) & "," & Right$("0" & CStr(Int((y - Deg) * 60)), 2) & "," & Right$("0" & CStr(Int((y - Deg - Min / 60) * 3600)), 2)
  If x < 0 Then Dec2Str = "- " & Dec2Str
' or Dec2Str = Dec2Str & " S"
' or Dec2Str = Dec2Str & " W"
End Function

Private Function Str2Dec(x As String) As Double
  Dim a As Integer, b As Integer
  Dim y As String
  If Left$(x, 1) = "-" Then y = Mid$(x, 2)
  a = 0
  For i = 0 To 1
      b = InStr(a + 1, y, ",")
      Str2Dec = Str2Dec + Val(Mid$(y, a + 1, b - a)) / (60 ^ i)
      a = b
  Next i
  Str2Dec = Str2Dec + Val(Mid$(y, a + 1)) / 3600
  If Left$(x, 1) = "-" Then Str2Dec = Str2Dec * -1
End Function

'Using
'LatNavAid_Str = "39,54,54"
'LatNavAid_Dec = Str2Dec (LatNavAid_Str)
'output = 39.915

' My functions return data at decimal format. You can convert it to string, using Dec2Str function. In all calculations is better to use decimal format. If you need, I can change my functions for your format. I assumed that 39,54,54 meens 39 degrees, 54 minutes, 54 seconds - it's correct?

Cheers
Ark   ark@fesma.ru
0
tomk120999Commented:
Great, Ark, that's just about how I would implement the actual code from the basic math.  Glad to meet you and dantindall.
good luck as usual...
0
dantindallAuthor Commented:
Thanks to all for the comments. this has been most helpful.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.