Dziś chciałem się podzielić dwoma funkcjami związanymi z GPS. Pierwsza z nich w oblicza odległość między dwoma punktami. Odległość podawana jest w metrach.
/// <summary> /// Calculates the distance between two points. /// </summary> /// <param name="firstCoordinate">The first coordinate.</param> /// <param name="secondCoordinate">The second coordinate.</param> /// <returns>Distance between points in meters</returns> private static double CalculateDistance(GeoCoordinate firstCoordinate, GeoCoordinate secondCoordinate) { double R = 6371.0; // km double lon1 = DegToRad(firstCoordinate.Longitude); double lat1 = DegToRad(firstCoordinate.Latitude); double lon2 = DegToRad(secondCoordinate.Longitude); double lat2 = DegToRad(secondCoordinate.Latitude); double dLat = lat2 - lat1; double dLon = lon2 - lon1; double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Sin(dLon / 2) * Math.Sin(dLon / 2) * Math.Cos(lat1) * Math.Cos(lat2); double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); return R * c * 1000; }
Druga natomiast funkcja służy do znalezienia współrzędnych punktu, który znajduje po środku dwóch podanych punktów.
/// <summary> /// Calculates the middle point coordinate. /// </summary> /// <param name="firstCoordinate">The first coordinate.</param> /// <param name="secondCoordinate">The second coordinate.</param> /// <returns>Middle point coordinate</returns> private GeoCoordinate CalculateMidPoint(GeoCoordinate firstCoordinate, GeoCoordinate secondCoordinate) { double lon1 = DegToRad(firstCoordinate.Longitude); double lat1 = DegToRad(firstCoordinate.Latitude); double lon2 = DegToRad(secondCoordinate.Longitude); double lat2 = DegToRad(secondCoordinate.Latitude); double deltaLong = lon2 - lon1; double Bx = Math.Cos(lat2) * Math.Cos(deltaLong); double By = Math.Cos(lat2) * Math.Sin(deltaLong); double lat3 = RadToDeg(Math.Atan2(Math.Sin(lat1) + Math.Sin(lat2), Math.Sqrt((Math.Cos(lat1) + Bx) * (Math.Cos(lat1) + Bx) + By * By))); double lon3 = RadToDeg(lon1 + Math.Atan2(By, Math.Cos(lat1) + Bx)); return new GeoCoordinate(lat3, lon3); }
Obie funkcje korzystają z dwóch metod pomocniczych, które przekształcają stopnie na radiany i odwrotnie.
/// <summary> /// Converts radians to degrees /// </summary> /// <param name="radians">The radians.</param> /// <returns>The degrees.</returns> private static double RadToDeg(double radians) { return radians * (180 / Math.PI); } /// <summary> /// Converts degrees to radians /// </summary> /// <param name="degrees">The degrees.</param> /// <returns>The radians</returns> private static double DegToRad(double degrees) { return degrees * (Math.PI / 180); }
Mam nadzieję, że komuś przydadzą się te funkcje.
Ładna publikacja,
Moja propozycja aby zwiększyć dokładności, zdefiniować średnicę planety co do metra np. dla WGS84 było by jak poniżej:
#define EARTH_MAJOR_AXIS_WGS84 (double) 6378137.0
Thanks, that was useful.