經緯度相關計算

近期作一個與GRPS相關的應用,涉及到經緯度的計算,找資料時頗費了一番功夫,特此將其相關資料整理了一下,發佈出來,但願對用到的同窗有所幫助。 html

經緯度算法

經緯度計算主要有兩種: 
1. 知道兩點的經緯度值,計算兩點間的距離
2. 知道一點的經緯度,知道另外一點相對於此點的角度,距離。計算另外一點的經緯度信息  git

對於第一種計算,網上搜索到大概有三種:
1. 把地球當球體,根據球面公式計算

2.根據以下公式進行計算:

其中A點緯度、經度分別爲lat1和lon1,B點的緯度、經度分別爲lat2和lon2,D爲距離。 
這個公式搜索結果挺多,在百度搜索"經緯度 計算距離"不少都是這個公式。  算法

3. 從Google地圖中反推出的算法(詳見參考文檔1)。公式以下圖 

公式中經緯度均用弧度表示;lat1,lon1 表示A點經緯度,lat2,lon2 表示B點經緯度;
a= lat1lat2 爲兩點緯度之差 ; b= lon1 - lon2 爲兩點經度之差;
6378.137爲地球半徑,單位爲千米;

第一種沒作驗證,第二種測試了一下,誤差較大(以圓明園、動物園之間的距離進行測定)目前採用的是第三種算法。
第二種計算,找到的資料不多,卻是找到很多遇到相同問題的朋友。不過最終仍是找到了(詳見參考文檔2)。並使用第一種計算進行反驗證,誤差很小。

代碼


經緯度類 
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

namespace GeoSite
{
    /// <summary>
    /// 經緯度表示類
    /// 經緯度計算主要有兩種:
    /// 1. 知道兩點的經緯度值,計算兩點間的距離
    /// 2. 知道一點的經緯度,知道另外一點相對於此點的角度,距離。計算另外一點的經緯度信息
    /// http://blog.csdn.net/fdnike/archive/2007/07/18/1696603.aspx
    /// </summary>
    public class LatLon
    {
        /// <summary>
        /// 赤道半徑 earth radius
        /// </summary>
        public const double EARTH_RADIUS = 6378137;

        /// <summary>
        /// 極半徑 polar radius
        /// </summary>
        public const double POLAR_RADIUS = 6356725;

        /// <summary>
        /// 
        /// </summary>
        public LatLon()
        { }

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="lat">維度</param>
        /// <param name="lon">經度</param>
        public LatLon(double lat, double lon)
        {
            this.Lat = lat;
            this.Lon = lon;
        }

        /// <summary>
        /// 緯度
        /// </summary>
        public double Lat { get; set; }

        /// <summary>
        /// 經度
        /// </summary>
        public double Lon { get; set; }

        /// <summary>
        /// 緯度的弧度
        /// </summary>
        public double RadLat { get { return Lat * Math.PI / 180; } }

        /// <summary>
        /// 經度的弧度
        /// </summary>
        public double RadLon { get { return Lon * Math.PI / 180; } }

        /// <summary>
        /// ?
        /// </summary>
        public double Ec { get { return POLAR_RADIUS + (EARTH_RADIUS - POLAR_RADIUS) * (90 - Lat) / 90; } }

        /// <summary>
        /// ?
        /// </summary>
        public double Ed { get { return Ec * Math.Cos(RadLat); } }
    }
}


計算類:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

namespace GeoSite
{
    /// <summary>
    /// Geo輔助類
    /// </summary>
    public static class GeoHelper
    {
        /// <summary>
        /// 根據兩點的經緯度計算兩點距離
        /// </summary>
        /// <param name="src">A點維度</param>        
        /// <param name="dest">B點經度</param>
        /// <returns></returns>
        public static double GetDistance(LatLon src, LatLon dest)
        {
            if (Math.Abs(src.Lat) > 90 || Math.Abs(dest.Lat) > 90 || Math.Abs(src.Lon) > 180 || Math.Abs(dest.Lon) > 180)
                throw new ArgumentException("經緯度信息不正確!");          

            double latDis = src.RadLat - dest.RadLat;
            double lonDis = src.RadLon - dest.RadLon;

            double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(latDis / 2), 2) + Math.Cos(src.Lat) * Math.Cos(dest.Lat) * Math.Pow(Math.Sin(lonDis / 2), 2)));
            s = s * LatLon.EARTH_RADIUS / 1000;
            s = Math.Round(s * 10000) / 10000;

            return s;            
        }

        /// <summary>
        /// 根據兩點的經緯度計算兩點距離
        /// </summary>
        /// <param name="lat1">A點維度</param>
        /// <param name="lon1">A點經度</param>
        /// <param name="lat2">B點維度</param>
        /// <param name="lon2">B點經度</param>
        /// <returns></returns>
        public static double GetDistance(double lat1, double lon1, double lat2, double lon2)
        {
            LatLon src = new LatLon(lat1, lon1);
            LatLon dest = new LatLon(lat2, lon2);
            return GetDistance(src, dest);
        }
        

        /// <summary>
        /// 已知點A經緯度,根據B點據A點的距離,和方位,求B點的經緯度
        /// </summary>
        /// <param name="a">已知點A</param>
        /// <param name="distance">B點到A點的距離 </param>
        /// <param name="angle">B點相對於A點的方位,12點鐘方向爲零度,角度順時針增長</param>
        /// <returns>B點的經緯度座標</returns>
        public static LatLon GetLatLon(LatLon a, double distance, double angle)
        {
            double dx = distance * 1000 * Math.Sin(angle * Math.PI / 180);
            double dy = distance * 1000 * Math.Cos(angle * Math.PI / 180);

            double lon = (dx / a.Ed + a.RadLon) * 180 / Math.PI;
            double lat = (dy / a.Ec + a.RadLat) * 180 / Math.PI;

            LatLon b = new LatLon(lat, lon);
            return b;
        }

        /// <summary>
        /// 已知點A經緯度,根據B點據A點的距離,和方位,求B點的經緯度
        /// </summary>
        /// <param name="longitude">已知點A經度</param>
        /// <param name="latitude">已知點A緯度</param>
        /// <param name="distance">B點到A點的距離</param>
        /// <param name="angle">B點相對於A點的方位,12點鐘方向爲零度,角度順時針增長</param>
        /// <returns>B點的經緯度座標</returns>
        public static LatLon GetLatLon(double longitude, double latitude, double distance, double angle)
        {
            LatLon a = new LatLon(latitude, longitude);
            return GetLatLon(a, distance, angle);
        }
    }
}


示例運行結果:  

c#

參考文檔:

1. 經過經緯度計算距離的公式
http://www.storyday.com/html/y2009/2212_according-to-latitude-and-longitude-distance-calculation-formula.html
2. 經緯度距離計算
http://blog.csdn.net/fdnike/archive/2007/07/18/1696603.aspx

源碼下載

http://files.cnblogs.com/hellofox2000/GeoSite.rar
相關文章
相關標籤/搜索