主要方法:
public static double CalculateSurfaceDistance(double lat1, double lng1, double lat2, double lng2) 获取两个坐标标点距离。
public static GEOSquare CircumscribedSquare(double latitudeInDegrees, double longitudeInDegrees, double radiusInMeters) 获取指定点与距离的外界正方形。
/// <summary>
/// Class that provides calculations based on assuming that the earth is a perfect sphere.
/// </summary>
public class SphericalCalculations
{
/// <summary>
///
/// </summary>
public static double EarthEquatorialRadiusInMeters = 6371000;
/// <summary>
/// Get randians
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private static double Radians(double d)
{
return d * Math.PI / 180.0;
}
/// <summary>
/// Calculate the distance (in meters) between the two given lat/long points (in radians)
/// on the surface of the sphere. Uses the Haversine formula.
/// </summary>
public static double CalculateSurfaceDistance(double lat1, double lng1, double lat2, double lng2)
{
double radLat1 = Radians(lat1);
double radLat2 = Radians(lat2);
double a = radLat1 - radLat2;
double b = Radians(lng1) - Radians(lng2);
double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +
Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
s = s * EarthEquatorialRadiusInMeters;
s = Math.Round(s * 10000) / 10000;
return s;
}
/// <summary>
///
/// </summary>
/// <param name="latitudeInDegrees"></param>
/// <param name="longitudeInDegrees"></param>
/// <param name="radiusInMeters"></param>
/// <returns></returns>
public static GEOSquare CircumscribedSquare(double latitudeInDegrees, double longitudeInDegrees, double radiusInMeters)
{
double requestLatitudeInRadians =Radians( latitudeInDegrees );
double requestLongitudeInRadians = Radians(longitudeInDegrees);
//
// First we will calculate the latitude and longitude (spherical coordinates, phi and
// theta respectively) of the parallelogram that bounds the circle with the given radius
// on the surface of the sphere.
//
double phiSurfaceDistance = radiusInMeters / EarthEquatorialRadiusInMeters;
double phiMin = requestLatitudeInRadians - phiSurfaceDistance;
double phiMax = requestLatitudeInRadians + phiSurfaceDistance;
double thetaSurfaceDistanceAtPhiMin = radiusInMeters /
(SphericalCalculations.EarthEquatorialRadiusInMeters * Math.Cos(phiMin));
double thetaSurfaceDistanceAtPhiMax = radiusInMeters /
(SphericalCalculations.EarthEquatorialRadiusInMeters * Math.Cos(phiMax));
//
// Since it it a lot easier to search for points within a rectangle in a database, we
// will describe a rectangle that bounds the parallelogram.
//
double upperLeftPhi = phiMin;
double upperLeftTheta = requestLongitudeInRadians - thetaSurfaceDistanceAtPhiMin;
// Determine the larger of the two bases
double rectangleWidth = thetaSurfaceDistanceAtPhiMax >
thetaSurfaceDistanceAtPhiMin ?
thetaSurfaceDistanceAtPhiMax * 2 :
thetaSurfaceDistanceAtPhiMin * 2;
// Determine the height
double rectangleHeight = phiMax - phiMin;
GEOSquare resultSquare = new GEOSquare
{
LatitudeFrom = upperLeftPhi * 180.0 / Math.PI,
LatitudeTo = (upperLeftPhi + rectangleHeight) * 180.0 / Math.PI,
LongitudeFrom = upperLeftTheta * 180.0 / Math.PI,
LongitudeTo = (upperLeftTheta + rectangleWidth) * 180.0 / Math.PI
};
return resultSquare;
}
public class GEOSquare
{
public double LatitudeFrom { get; set; }
public double LatitudeTo { get; set; }
public double LongitudeFrom { get; set; }
public double LongitudeTo { get; set; }
}
}
测试代码:
[TestMethod]
public void TestCircumscribedSquare()
{
//
// TODO: Add test logic here
//
double latitudeInDegrees = 37.3456D;
double longitudeInDegrees=119.1234D;
long searchRadiusInMeters=3080;
SphericalCalculations.GEOSquare square = SphericalCalculations.CircumscribedSquare(latitudeInDegrees, longitudeInDegrees, searchRadiusInMeters);
Console.WriteLine("CircumscribedSquare: LatitudeFrom-To:{0}-{1};LongitudeFromTo:{2}-{3}", square.LatitudeFrom, square.LatitudeTo, square.LongitudeFrom, square.LongitudeTo);
Console.WriteLine("Difference in Latitude:{0}; Difference in Longitude:{1}", square.LatitudeTo - square.LatitudeFrom, square.LongitudeTo - square.LongitudeFrom);
Console.WriteLine("-------------------------");
Console.WriteLine(searchRadiusInMeters * Math.Sqrt(2));
Console.WriteLine(SphericalCalculations.CalculateSurfaceDistance(latitudeInDegrees, longitudeInDegrees, square.LatitudeFrom, square.LongitudeFrom));
Console.WriteLine(SphericalCalculations.CalculateSurfaceDistance(latitudeInDegrees, longitudeInDegrees, square.LatitudeFrom, square.LongitudeTo));
Console.WriteLine(SphericalCalculations.CalculateSurfaceDistance(latitudeInDegrees, longitudeInDegrees, square.LatitudeTo, square.LongitudeFrom));
Console.WriteLine(SphericalCalculations.CalculateSurfaceDistance(latitudeInDegrees, longitudeInDegrees, square.LatitudeTo, square.LongitudeTo));
}
[TestMethod]
public void TestGetdistinace()
{
double latitudeInDegrees = 37.3456D;
double longitudeInDegrees = 119.1234D;
Console.WriteLine(SphericalCalculations.CalculateSurfaceDistance(latitudeInDegrees, longitudeInDegrees, latitudeInDegrees, longitudeInDegrees + 0.001));
Console.WriteLine(SphericalCalculations.CalculateSurfaceDistance(51.517477, -0.096044, 51.517610, -0.097589));
}
[TestMethod]
public void TestGetBeiJingToShangHaiDistinace()
{
// Coordinates of BeiJing is (39°54'20",116°23'29")
double latitudeOfBeiJing = 39 + 54 / 60.0000 + 20 / 3600.0000;
double longitudeOfBeiJing = 116 + 23 / 60.0000 + 29 / 3600.0000;
// Coordinates of Shanghai is (31°13'49.5",121°28'13.21")
double latitudeOfShangHai = 31 + 13 / 60.0000 + 49.5 / 360.0000;
double longitudeOfShangHai = 121 + 28 / 60.0000 + 13.21 / 3600.00;
Console.WriteLine("Distance from Beijing to Shanghai is:");
Console.WriteLine("{0:0.00}KM",SphericalCalculations.CalculateSurfaceDistance(latitudeOfBeiJing, longitudeOfBeiJing, latitudeOfShangHai, longitudeOfShangHai)/1000);
//-11.355 25.44
Console.WriteLine("{0:0.00}M", SphericalCalculations.CalculateSurfaceDistance(11.4, 25.44, 11.3, 25.44));
}