Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I find the lat/long that is x km north of a given lat/long?

Tags:

c#

geometry

gis

I have some C# code that generates google maps. This codes looks at all the Points I need to plot on the map and then works out the Bounds of a rectangle to include those points. It then passes this bounds to the Google Maps API to set the zoom level appropriately to show all of the points on the map.

This code is working fine however I have a new requirement.

One of the points may have a precision associated with it. If this is the case then I draw a circle around the point with the radius set to the precision value. Again this works fine however my bounds checking is now not doing what I want it to do. I want to have the bounding box include the complete circle.

This requires an algorithm to take a point x and calculate the point y that would be z metres north of x and also z metres south of x.

Does anyone have this algorithm, preferably in C#. I did find a generic algorithm here but I appear to have not implemented this correctly as the answers I am getting are 1000s of km adrift.

This is the Generic example

Lat/lon given radial and distance  A point {lat,lon} is a distance d out on the tc radial from point 1 if:       lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))      IF (cos(lat)=0)         lon=lon1      // endpoint a pole      ELSE         lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi      ENDIF 

And this is my C# translation.

  // Extend a Point North/South by the specified distance     public static Point ExtendPoint(Point _pt, int _distance, int _bearing )     {         Decimal lat = 0.0;         Decimal lng = 0.0;          lat = Math.Asin(Math.Sin(_pt.Lat) * Math.Cos(_distance) + Math.Cos(_pt.Lat) *              Math.Sin(_distance) * Math.Cos(_bearing));           if (Math.Cos(lat) == 0)          {             lng = _pt.Lng;      // endpoint a pole          }          else           {              lng = (                  (_pt.Lng - Math.Asin(Math.Sin(_bearing) * Math.Sin(_distance) / Math.Cos(lat))                   + Math.PI) % (2 * Math.PI)) - Math.PI;          }           ret = new Point(lat,lng);          return ret;     } 

I am calling this function with a bearing of 0 to calculate the new northerly position and a value of 180 to calculate the new southerly position.

Can anyone either see what I have done wrong or perhaps provide a known working algorithm?

like image 304
Steve Weet Avatar asked Jul 14 '09 12:07

Steve Weet


People also ask

How is Lat Long calculated?

One of the most common ways to calculate distances using latitude and longitude is the haversine formula, which is used to measure distances on a sphere. This method uses spherical triangles and measures the sides and angles of each to calculate the distance between points.

What is X in Lat Long?

Latitude is the Y axis, longitude is the X axis. Since latitude can be positive and negative (north and south of the Equator), and longitude can be as well (negative west of Greenwich and positive eastward) when the -180 to +180 longitude system is use.

What is the formula to be used to determine the latitude of a line given its distance and bearing?

Here is the formula to find the second point, when first point, bearing and distance is known: latitude of second point = la2 = asin(sin la1 * cos Ad + cos la1 * sin Ad * cos θ), and. longitude of second point = lo2 = lo1 + atan2(sin θ * sin Ad * cos la1 , cos Ad – sin la1 * sin la2)


1 Answers

I have a very similar piece of code. It got me very close results when compared to another implementation.

I think the problem with yours is that you are using "distance" as linear distance in meters instead of angular distance in radians.

/// <summary> /// Calculates the end-point from a given source at a given range (meters) and bearing (degrees). /// This methods uses simple geometry equations to calculate the end-point. /// </summary> /// <param name="source">Point of origin</param> /// <param name="range">Range in meters</param> /// <param name="bearing">Bearing in degrees</param> /// <returns>End-point from the source given the desired range and bearing.</returns> public static LatLonAlt CalculateDerivedPosition(LatLonAlt source, double range, double bearing) {     double latA = source.Latitude * UnitConstants.DegreesToRadians;     double lonA = source.Longitude * UnitConstants.DegreesToRadians;     double angularDistance = range / GeospatialConstants.EarthRadius;     double trueCourse = bearing * UnitConstants.DegreesToRadians;      double lat = Math.Asin(         Math.Sin(latA) * Math.Cos(angularDistance) +          Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));      double dlon = Math.Atan2(         Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),          Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));      double lon = ((lonA + dlon + Math.PI) % UnitConstants.TwoPi) - Math.PI;      return new LatLonAlt(         lat * UnitConstants.RadiansToDegrees,          lon * UnitConstants.RadiansToDegrees,          source.Altitude); } 

Where

public const double EarthRadius = 6378137.0;   //  WGS-84 ellipsoid parameters 

and LatLonAlt is in degrees/meters (conversion takes place internally). Adjust as needed.

I assume you can figure out what the value for UnitConstants.DegreesToRadians is :)

like image 161
Erich Mirabal Avatar answered Oct 05 '22 22:10

Erich Mirabal