代码改变世界

经纬度相关计算

2010-07-13 03:01 by 韩龙, ... 阅读, ... 评论, 收藏, 编辑

近期做一个与GRPS相关的应用,涉及到经纬度的计算,找资料时颇费了一番功夫,特此将其相关资料整理了一下,发布出来,希望对用到的同学有所帮助。

闲话少说,经纬度计算主要有两种:

1. 知道两点的经纬度值,计算两点间的距离

2. 知道一点的经纬度,知道另一点相对于此点的角度,距离。计算另一点的经纬度信息

对于第一种计算,网上搜索到大概有三种:

1. 把地球当球体,根据球面公式计算

2. 根据如下公式进行计算:

其中A点纬度、经度分别为lat1和lon1,B点的纬度、经度分别为lat2和lon2,D为距离。 

这个公式搜索结果挺多,在百度搜索"经纬度 计算距离"很多都是这个公式。 

3. Google地图中反推出的算法(详见参考文档1)。公式如下图 

 

公式中经纬度均用弧度表示;lat1,lon1 表示A点经纬度,lat2,lon2 表示B点经纬度; 
a= lat1 – lat2 为两点纬度之差 ; 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);
        }
    }
}

  

示例运行结果: 

 

参考文档:

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

开发环境:VS2008

经纬度计算代码下载