/
GeoCalculator.cs
157 lines (141 loc) · 9.45 KB
/
GeoCalculator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* Geolocation Class Library
* Author: Scott Schluer (scott.schluer@gmail.com)
* May 29, 2012
* https://github.com/scottschluer/Geolocation
*/
using System;
namespace Geolocation
{
/// <summary>
/// Various utility methods for calculating geographically-based values
/// </summary>
public static class GeoCalculator
{
private static double EarthRadiusInMiles = 3959.0;
private static double EarthRadiusInNauticalMiles = 3440.0;
private static double EarthRadiusInKilometers = 6371.0;
private static double EarthRadiusInMeters = 6371000.0;
/// <summary>
/// Calculate the distance between two sets of coordinates.
/// <param name="originLatitude">The latitude of the origin location in decimal notation</param>
/// <param name="originLongitude">The longitude of the origin location in decimal notation</param>
/// <param name="destinationLatitude">The latitude of the destination location in decimal notation</param>
/// <param name="destinationLongitude">The longitude of the destination location in decimal notation</param>
/// <param name="decimalPlaces">The number of decimal places to round the return value to</param>
/// <param name="distanceUnit">The unit of distance</param>
/// <returns>A <see cref="Double"/> value representing the distance in miles from the origin to the destination coordinate</returns>
/// </summary>
public static double GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, DistanceUnit distanceUnit = DistanceUnit.Miles)
{
if (!CoordinateValidator.Validate(originLatitude, originLongitude))
throw new ArgumentException("Invalid origin coordinates supplied.");
if (!CoordinateValidator.Validate(destinationLatitude, destinationLongitude))
throw new ArgumentException("Invalid destination coordinates supplied.");
double radius = GetRadius(distanceUnit);
return Math.Round(
radius * 2 *
Math.Asin(Math.Min(1,
Math.Sqrt(
(Math.Pow(Math.Sin(originLatitude.DiffRadian(destinationLatitude) / 2.0), 2.0) +
Math.Cos(originLatitude.ToRadian()) * Math.Cos(destinationLatitude.ToRadian()) *
Math.Pow(Math.Sin((originLongitude.DiffRadian(destinationLongitude)) / 2.0),
2.0))))), decimalPlaces);
}
/// <summary>
/// Calculate the distance between two sets of <see cref="Coordinate"/> objects
/// </summary>
/// <param name="originCoordinate">A <see cref="Coordinate"/> object representing the origin location</param>
/// <param name="destinationCoordinate">A <see cref="Coordinate"/> object representing the destination location</param>
/// <param name="decimalPlaces">The number of decimal places to round the return value to</param>
/// <param name="distanceUnit">The unit of distance</param>
/// <returns>A <see cref="Double"/> value representing the distance in miles from the origin to the destination coordinate</returns>
public static Double GetDistance(Coordinate originCoordinate, Coordinate destinationCoordinate, int decimalPlaces = 1, DistanceUnit distanceUnit = DistanceUnit.Miles)
{
return GetDistance(originCoordinate.Latitude, originCoordinate.Longitude, destinationCoordinate.Latitude,
destinationCoordinate.Longitude, decimalPlaces, distanceUnit);
}
/// <summary>
/// Calculates the bearing, in degrees between two geographic points
/// </summary>
/// <param name="originLatitude">The latitude of the origin location in decimal notation</param>
/// <param name="originLongitude">The longitude of the origin location in decimal notation</param>
/// <param name="destinationLatitude">The latitude of the destination location in decimal notation</param>
/// <param name="destinationLongitude">The longitude of the destination location in decimal notation</param>
/// <returns>A <see cref="Double"/> value indicating the bearing from the origin to the destination</returns>
public static double GetBearing(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude)
{
if (!CoordinateValidator.Validate(originLatitude, originLongitude))
throw new ArgumentException("Invalid origin coordinates supplied.");
if (!CoordinateValidator.Validate(destinationLatitude, destinationLongitude))
throw new ArgumentException("Invalid destination coordinates supplied.");
var destinationRadian = (destinationLongitude - originLongitude).ToRadian();
var destinationPhi = Math.Log(Math.Tan(destinationLatitude.ToRadian() / 2 + Math.PI / 4) / Math.Tan(originLatitude.ToRadian() / 2 + Math.PI / 4));
if (Math.Abs(destinationRadian) > Math.PI)
destinationRadian = destinationRadian > 0
? -(2 * Math.PI - destinationRadian)
: (2 * Math.PI + destinationRadian);
return Math.Atan2(destinationRadian, destinationPhi).ToBearing();
}
/// <summary>
/// Calculates the bearing, in degrees between two <see cref="Coordinate"/> objects
/// </summary>
/// <param name="originCoordinate">A <see cref="Coordinate"/> object representing the origin location</param>
/// <param name="destinationCoordinate">A <see cref="Coordinate"/> object representing the destination location</param>
/// <returns>A <see cref="Double"/> value indicating the bearing from the origin to the destination</returns>
public static double GetBearing(Coordinate originCoordinate, Coordinate destinationCoordinate)
{
return GetBearing(originCoordinate.Latitude, originCoordinate.Longitude, destinationCoordinate.Latitude,
destinationCoordinate.Longitude);
}
/// <summary>
/// Gets the cardinal or ordinal direction from the origin point to the destination point
/// </summary>
/// <param name="originLatitude">The latitude of the origin location in decimal notation</param>
/// <param name="originLongitude">The longitude of the origin location in decimal notation</param>
/// <param name="destinationLatitude">The latitude of the destination location in decimal notation</param>
/// <param name="destinationLongitude">The longitude of the destination location in decimal notation</param>
/// <returns>A string value indicating the cardinal or ordinal direction from the origin to the desintation point</returns>
public static string GetDirection(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude)
{
if (!CoordinateValidator.Validate(originLatitude, originLongitude))
throw new ArgumentException("Invalid origin coordinates supplied.");
if (!CoordinateValidator.Validate(destinationLatitude, destinationLongitude))
throw new ArgumentException("Invalid destination coordinates supplied.");
double bearing = GetBearing(originLatitude, originLongitude, destinationLatitude, destinationLongitude);
if (bearing >= 337.5 || bearing <= 22.5) return "N";
if (bearing > 22.5 && bearing <= 67.5) return "NE";
if (bearing > 67.5 && bearing <= 112.5) return "E";
if (bearing > 112.5 && bearing <= 157.5) return "SE";
if (bearing > 157.5 && bearing <= 202.5) return "S";
if (bearing > 202.5 && bearing <= 247.5) return "SW";
if (bearing > 247.5 && bearing <= 292.5) return "W";
if (bearing > 292.5 && bearing < 337.5) return "NW";
return String.Empty;
}
/// <summary>
/// Gets the cardinal or ordinal direction from the origin point to the destination point
/// </summary>
/// <param name="originCoordinate">A <see cref="Coordinate"/> object representing the origin location</param>
/// <param name="destinationCoordinate">A <see cref="Coordinate"/> object representing the destination location</param>
/// <returns>A <see cref="String"/> value indicating the cardinal or ordinal direction from the origin to the desintation point</returns>
public static string GetDirection(Coordinate originCoordinate, Coordinate destinationCoordinate)
{
return GetDirection(originCoordinate.Latitude, originCoordinate.Longitude, destinationCoordinate.Latitude,
destinationCoordinate.Longitude);
}
private static double GetRadius(DistanceUnit distanceUnit)
{
switch (distanceUnit)
{
case DistanceUnit.Kilometers:
return EarthRadiusInKilometers;
case DistanceUnit.Meters:
return EarthRadiusInMeters;
case DistanceUnit.NauticalMiles:
return EarthRadiusInNauticalMiles;
default:
return EarthRadiusInMiles;
}
}
}
}