Link to home
Start Free TrialLog in
Avatar of logitech334
logitech334

asked on

Visual Basic .NET 2015 calculating new lat/lon based on bearing and distance

Hello guys,

I have wrote a vb.net code

Const EarthRadius As Double = 6371

    Public Shared Function FindPointAtDistanceFrom(lat1 As Decimal, lon1 As Decimal, bearing As Double, range As Double) As PointF
        Dim latA As Decimal = deg2rad(lat1)
        Dim lonA As Decimal = deg2rad(lon1)
        Dim angularDistance As Decimal = range / EarthRadius
        Dim trueCourse As Decimal = deg2rad(bearing - 270)
        Dim lat As Decimal = Math.Asin(Math.Sin(latA) * Math.Cos(angularDistance) + Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse))
        Dim dlon As Decimal = lonA + Math.Atan2(Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA), Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat))
        Dim lon As Decimal = ((lonA - dlon + Math.PI) Mod (Math.PI * 3)) - Math.PI
        ' lon1 + ATAN2(COS(d/R)-SIN(lat1)*SIN(lat2), SIN(brng)*SIN(d/R)*COS(lat1)) 
        'Dim lon As Double = lonA + Math.Atan2(Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA), Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat))

        Dim prt As PointF = New PointF(rad2deg(lat), rad2deg(dlon))
        Return prt
    End Function

Open in new window


Which calculates the point on specified distance in km, however, I am getting very inaccurate result (~15-20km difference). The result for values: heading 360 (0-north), 111.2km and lon 61.0000 lat -30.0000 (61N30W) i am expecting is 62.0000 and -30.0000) as the distance between longs is around 111.2km. I guess it is some accuracy problem in vb.net math calculations. Would you give me any advice how  to make this formula working in vb.net (it was supposed to give me accurate point to meters - not kilometers).

The output result of above formula currently is: 62,15471 (Long) and -29.99496.

Thanks in advance.
Avatar of byundt
byundt
Flag of United States of America image

What happens if you declare your variables as Double rather than Decimal?

I'm an Excel VBA kind of guy, and so had to read up on the Decimal variable type at http://www.visualbasic.w3computing.com/vb2008/2/vb-decimal-data-type.php. I bolded one specific sentence in the quote below, where it leads me to believe that Double might work better.
If you perform the same calculations with Single variables, the result will be truncated (and rounded) to three decimal digits: 4,075.795. Notice that the Decimal data type didn't introduce any rounding errors. It's capable of representing the result with the exact number of decimal digits. This is the real advantage of Decimals, which makes them ideal for financial applications. For scientific calculations, you must still use Doubles. Decimal numbers are the best choice for calculations that require a specific precision (such as four or eight decimal digits).
Avatar of logitech334
logitech334

ASKER

Hello, thank you for your reply. "Decimal" thing was last change I did to this code to chceck if that works better. I get exactly the same wrong coords on doubles.
I was comparing your code to the discussion on Great Circle type calculations at http://www.movable-type.co.uk/scripts/latlong.html   I tried your sample problem on their calculator, and it returned the exact answer expected: 62 degrees longitude, -30 degrees latitude.

Your code matched the formulas on Movable Type. I assume that your VB.Net code uses the same convention for atan2 that Movable Type did. If you note the footnote 4 just above the middle of the page, the question is whether atan2 uses y as the first paramter and x as the second--or the converse.
I'm not a real expert at this, but I do see a problem here:
lon 61.0000 lat -30.0000 (61N30W)
As you can see here for example, the latitude should be N/S and the longitude E/W.
Now that may be a simple typo but it could explain the error. Either reverse the lat/lon arguments or the bearing is calculated wrong (where did you get that -270 from?). In fact, if I enter bearing 90 (or 270) in your function it returns a result that matches your expectation (moving 1 degree of latitude) but you'd still need to double check which is which with regard to lat/lon going in and coming out of your function.
SOLUTION
Avatar of byundt
byundt
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I've tried couple of your suggestions however I can't still get it working. I've managed it to work for -30 60 point but when I try to calculate another it returns value (of latitude) 2x smaller (on distance ~300 nautical miles) than it should be. Moreover, "bearing" by definition is not a bearing (VB .NET issues?) - thats why i put -270 there to rotate it so I could get points on the correct radial from known lat/lon. I am having exactly the same issues with the last formula from here: https://www.experts-exchange.com/questions/22555684/VB6-Lat-Lon-given-heading-and-distance.html I do not know if this will help if I say that I tried even Vincenty's formulas but they were affected by the same issues. I now doubt if this is formula's itself related issue. Do you have further ideas?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It is worth noting that on almost any Great Circle route, the instantaneous bearing will be different from what it was at the beginning of the trip. The only exceptions are those routes that head strictly north/south or east/west. The function (and Movable Type webpage) are looking for the initial bearing. This is why you can't connect two points on a paper map with a straight line and call that your bearing. You must draw the Great Circle route and measure the initial bearing.
Thank you, above thing should be now solved - there was some problems with type PointF x/y usage so function missed lat with lons and round around. Before I set status to Solved I'd like to ask you for the same related thing - I have another function:

  Public Shared Function CalcAzimuth(ByVal lat1 As Double, ByVal long1 As Double, ByVal lat2 As Double, ByVal long2 As Double) As Double
        Dim dlon As Double = Rad(long2) - Rad(long1)
        lat1 = Rad(lat1)
        long1 = Rad(long1)
        lat2 = Rad(lat2)
        long2 = Rad(long2)
        Dim x As Decimal = Math.Sin(dlon) * Math.Cos(lat2)
        Dim y As Decimal = Math.Cos(lat1) * Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(lat2) * Math.Cos(dlon)
        Dim brng As Double = Math.Atan2(y, x)
        brng = Deg(brng)
        brng = Math.Abs((brng + 360) Mod 360)
        Main.Label1.Text = brng.ToString
        Return brng
    End Function

Open in new window


This function should return bearing to the point. I compare results from lat -15 and long 55.5 to -10 and long 57 (W/N) - the bearing should be ~60 (final ~63) as per http://www.movable-type.co.uk/scripts/latlong.html however my application returns now ~73 which is very inaccurate for me.
How odd, when I run your function with arguments (-15, 55, -10, 55) I get the result 90.

Can you please post a clear example preferably including screenshot of what you have input on that website?
Hello,

Here are outputs:

User generated image
User generated image
User generated image
Thanks in advance,
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Guys,

I am very thankful to everyone for support you gave me. It worked and I am very happy to continue my project since it was very hard for me to finish/continue the project without proper calculations. The code I've posted could be very disorganized however it is the reason of overnight working & coding. I have tried different methods to find a solution and there it is. Thank you very much to all of you! :)