通过经纬度坐标计算距离的方法(经纬度距离计算)

最近在网上搜索“通过经纬度坐标计算距离的方法”,发现网上大部分都是如下的代码:

#define PI 3.14159265

static double Rc = 6378137;  // 赤道半径

static double Rj = 6356725;  // 极半径

class JWD

{

public:

double m_Longitude, m_Latitude;

double m_RadLo, m_RadLa;

double Ec;

double Ed;

public:

JWD(double longitude, double latitude)

{

m_Longitude = longitude;

m_Latitude = latitude;

m_RadLo = longitude * PI/180.;

m_RadLa = latitude * PI/180.;

Ec = Rj + (Rc - Rj) * (90.-m_Latitude) / 90.;

Ed = Ec * cos(m_RadLa);

}

~JWD() {};

};

static JWD GetJWDB(JWD A, double x,double y)

{

double dx=x;

double dy=y;

double BJD = (dx/A.Ed + A.m_RadLo) * 180./PI;

double BWD = (dy/A.Ec + A.m_RadLa) * 180./PI;

JWD B(BJD, BWD);

return B;

}

void main()

{

double referla=30.0;

double referlo=60.0;

double dx=500.0;

double dy=60.0;

JWD A(referla,referlo),B(0.0,0.0);

B=GetJWDB(A,dx,dy);

cout < < "  LA = " < < B.m_Latitude < < "  LO= " < < B.m_Longitude < < endl;

}

上面这段与之类似的代码是最容易通过搜索引擎找到的。大部分都是相互的转载,从来没有说明和注释。给初学者造成了很大的困扰。特别是:

Ec = Rj + (Rc - Rj) * (90.-m_Latitude) / 90.;

Ed = Ec * cos(m_RadLa);

Ec、Ed这2个参数,有人还在CSDN上发帖询问“函数中Ec,Ed是什么意思”。但从来没有见到有人回答。

提问的链接:

我刚开始接触这个问题,在中文世界中也只能搜到这些Ctrl+C 到Ctrl+V的东西。全球最大的中文互联网上也没有任何解答。已经明白的人知道很简单,但初学者肯定很疑惑。更何况现在LBS应用已经非常多了。肯定有非常多的人已经找到了更好的解答方式。 但对于我来说,用最常用的关键词,最容易的找到了这些复制的答案,但疑点重重。本着好奇的心,经过一番了解,我把结果给大家分析一下。下面是C#的代码:

public const double Ea = 6378137; //赤道半径

public const double Eb = 6356725; //极半径

private static void GetJWDB(double GLAT, double GLON, double distance, double angle, out double BJD, out doubleBWD)

{

double dx = distance * 1000 * Math.Sin(angle * Math.PI / 180.0);

double dy = distance * 1000 * Math.Cos(angle * Math.PI / 180.0);

//double ec = 6356725 + 21412 * (90.0 - GLAT) / 90.0;

//21412 是赤道半径与极半径的差

double ec = Eb + (Ea-Eb) * (90.0 - GLAT) / 90.0;

double ed = ec * Math.Cos(GLAT * Math.PI / 180);

BJD = (dx / ed + GLON * Math.PI / 180.0) * 180.0 /Math.PI;

BWD = (dy / ec + GLAT * Math.PI / 180.0) * 180.0 /Math.PI;

}

上面这个函数一看就是懂中文的人搞的,名字叫GetJWDB,取得经纬度。他根据输入的经度、纬度、距离和一个角度,得到另外一个经纬度坐标,输出参数为BJD、BWD。

1)angle * Math.PI / 180.0 作用是将角度转换为弧度,经纬度坐标是角度值,计算时需要换为弧度。这里所有的计算都是用弧度。

2)函数以正北方(due north) 也就是指南针的方向为0度,顺时针方向增加。如下图,Distance距离如果是d的话,dx就是x轴方向的长度,即longitude经度方向的长度;dy就是y轴方向的长度,即latitude纬度方向的长度。

dx、dy的计算方式也可以是以正东(due east)方向为0度。那:dx=distance* Cos(θ),dy=distance*Sin(θ)。区别是Cos 与Sin互换。(图上未标)

图1

3)Ea 表示赤道半径,Eb表示极半径,地球是一个近似球体,Ea与Eb稍微有点差距。ec的作用就是修正因为纬度不断变化的球半径长度。如果在GLAT=0,即在赤道上的时候,ec=Eb+(Ea-Eb)*(90-0)/90=Ea,那ec就刚好是赤道半径Ea;如果在极点GLAT=90,ec=Eb+(Ea-Eb)*(90-90)/90=Eb,那ec 就刚好是极半径Eb。

4)Ed是GLAT所在纬度的纬度圈的半径,如下图:

图2

截面过球心,此时截面的面积最大,此圆叫球的大圆(Great Cycle),沿着经线进行截面,得到的都是大圆(Great Cycle)。球面被不经过球心. 的截面所截得的圆. 叫做小圆。纬度圈所在的圆是一个小圆。地球半径R,平均值R=6371.0Km, Ed如果用地球半径R表示,那就是Ed=R*Cos(θ),可以参看

《根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)》这里提到的“A、D所在纬度圆圈的半径(AO`)”。放到上面函数里,因为它不断修正地球半径ec,那就是ed = ec * Math.Cos(GLAT * Math.PI / 180);

5)按照地球经纬度的划分,如下图:

每等分的纬度之间,经度线段的长度是一定的。 A段,B段长度是一样的。

每一等分的经度之间,纬度线段的长度是从赤道向2极点减小的。C端,D段的长度是不一样的。

图3

参看上图,那dx / ed 就相当于是在GLAT这个纬度上dx长度与总长度的占比,算出来应该是个经度跨度。如果这个经度跨度加上起始给定的经度就是最终的经度。

同理 dy/R就是在GLON这个经度上的dy长度与地球平均半径R的占比,算出来应该是一个纬度跨度。如果这个纬度跨度加上起始给定的纬度就是最终的纬度。这里使用了R,取地球平均半径。

dy/ec 就是用不断修正的ec半径替代了平均半径R。

(dy / ec + GLAT * Math.PI / 180.0) 就是起始纬度加上distance距离的最终纬度,同时需要将该结果转换为角度。 转换角度方法是:弧度* 180.0 / Math.PI。

BWD = (dy / ec + GLAT * Math.PI / 180.0) * 180.0 / Math.PI;

(dx / ed + GLON * Math.PI / 180.0)就是起始经度加上distance距离的最终经度,同时需要将该结果转换为角度。

BJD = (dx / ed + GLON * Math.PI / 180.0) * 180.0 / Math.PI;

这个根据一个经纬度坐标、距离然后求另外一个经纬度坐标的作用,主要就是确定一个最小外包矩形(Minimum bounding rectangle,简称MBR)。例如,我要找一个坐标点(lat,lon)的5公里范围内的所有商户信息、景点信息等。这个MBR就是一个最大的范围,这个矩形是包含5公里范围内所有这些有效信息的一个最小矩形。利用公式,求出四个方向0度、90度、180度、270度方向上的四个坐标点就可以得到这个MBR。

public const double Ea = 6378137; //赤道半径

public const double Eb = 6356725; //极半径

private static void GetlatLon(double LAT, double LON, double distance, double angle, out double newLon, out doublenewLat)

{

double dx = distance * 1000 * Math.Sin(angle * Math.PI / 180.0);

double dy = distance * 1000 * Math.Cos(angle * Math.PI / 180.0);

double ec = Eb + (Ea-Eb) * (90.0 - LAT) / 90.0;

double ed = ec * Math.Cos(LAT * Math.PI / 180);

newLon = (dx / ed + LON * Math.PI / 180.0) * 180.0 /Math.PI;

newLat = (dy / ec + LAT * Math.PI / 180.0) * 180.0 /Math.PI;

}

public static void GetRectRange(double centorlatitude, double centorLogitude, double distance, out double maxLatitude, out double minLatitude, out double maxLongitude, out doubleminLongitude)

{

double temp = 0.0;

GetlatLon(centorlatitude, centorLogitude, distance, 0, out temp, outmaxLatitude);

GetlatLon(centorlatitude, centorLogitude, distance, 180, out temp, outminLatitude);

GetlatLon(centorlatitude, centorLogitude, distance, 90, out maxLongitude, outtemp);

GetlatLon(centorlatitude, centorLogitude, distance, 270, out minLongitude , outtemp);

}

这里得到的maxLatitude, minLatitude, maxLongitude, minLongitude就组成矩形的四个顶点。

网上另外的方法,

这里的“Destination point given distance and bearing from start point”一节介绍了。我直接把代码贴上来:

这里GetRectRange 这个函数 也是以正北方(due north)为起始角度,顺时针方向,求得maxLatitude, minLatitude, maxLongitude, minLongitude 这样一个MBR。2种方法的误差很小。我觉得都是可以用的公式。

///

///where φ is latitude, λ is longitude, θ is the bearing (clockwise from north),

///δ is the angular distance d/R; d being the distance travelled, R the earth’s radius

///bearing 方位 0,90,180,270

///

private static void GetNewLatLon(double lat, double lon, double d, double bearing, out double lat2, out doublelon2)

{

lat2 = 0.0;

lon2 = 0.0;

double R = 6378.137;

var φ1 =ConvertDegreesToRadians(lat);

var λ1 =ConvertDegreesToRadians(lon);

var θ =ConvertDegreesToRadians(bearing);

var φ2 = Math.Asin(Math.Sin(φ1) * Math.Cos(d / R) +Math.Cos(φ1) * Math.Sin(d / R) *Math.Cos(θ));

var λ2 = λ1 + Math.Atan2(Math.Sin(θ) * Math.Sin(d / R) *Math.Cos(φ1),

Math.Cos(d / R) - Math.Sin(φ1) *Math.Sin(φ2));

λ2 = (λ2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI; //normalise to -180..+180°

lat2 =ConvertRadiansToDegrees(φ2);

lon2 =ConvertRadiansToDegrees(λ2);

}

如果有一个应用,表里存有100万的数据,数据包含一个lat、lon的经纬度信息。就可以先根据输入的经纬度和距离得到一个MBR,然后通过类似

SELECT Id

FROM IdInfoTable

WHERE latitude >= minLat AND latitude < maxLat

AND longitude >= minLon AND longitude < maxLon

完整代码:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceGetJWD

{

public classGetMBR

{

public doubleMaxLatitude;

public doubleMinLatitude;

public doubleMaxLongitude;

public doubleMinLongitude;

public doubleMaxLatitude2;

public doubleMinLatitude2;

public doubleMaxLongitude2;

public doubleMinLongitude2;

public GetMBR(double centorlatitude, double centorLogitude, doubledistance)

{

GetRectRange(centorlatitude, centorLogitude, distance, out MaxLatitude, out MinLatitude, out MaxLongitude, outMinLongitude);

GetRectRange2(centorlatitude, centorLogitude, distance, out MaxLatitude2, out MinLatitude2, out MaxLongitude2, outMinLongitude2);

}

public const double Ea = 6378137; //赤道半径

public const double Eb = 6356725; //极半径

private static void GetlatLon(double LAT, double LON, double distance, double angle, out double newLon, out doublenewLat)

{

double dx = distance * 1000 * Math.Sin(angle * Math.PI / 180.0);

double dy = distance * 1000 * Math.Cos(angle * Math.PI / 180.0);

double ec = Eb + (Ea - Eb) * (90.0 - LAT) / 90.0;

double ed = ec * Math.Cos(LAT * Math.PI / 180);

newLon = (dx / ed + LON * Math.PI / 180.0) * 180.0 /Math.PI;

newLat = (dy / ec + LAT * Math.PI / 180.0) * 180.0 /Math.PI;

}

public static void GetRectRange(double centorlatitude, double centorLogitude, doubledistance,

out double maxLatitude, out double minLatitude, out double maxLongitude, out doubleminLongitude)

{

double temp = 0.0;

GetlatLon(centorlatitude, centorLogitude, distance, 0, out temp, outmaxLatitude);

GetlatLon(centorlatitude, centorLogitude, distance, 180, out temp, outminLatitude);

GetlatLon(centorlatitude, centorLogitude, distance, 90, out maxLongitude, outtemp);

GetlatLon(centorlatitude, centorLogitude, distance, 270, out minLongitude, outtemp);

}

public static void GetRectRange2(double centorlatitude, double centorLogitude, doubledistance,

out double maxLatitude, out double minLatitude, out double maxLongitude, out doubleminLongitude)

{

double temp = 0.0;

GetNewLatLon(centorlatitude, centorLogitude, distance, 0, out maxLatitude, outtemp);

GetNewLatLon(centorlatitude, centorLogitude, distance, 180, out minLatitude, outtemp);

GetNewLatLon(centorlatitude, centorLogitude, distance, 90, out temp, outmaxLongitude);

GetNewLatLon(centorlatitude, centorLogitude, distance, 270, out temp, outminLongitude);

}

///

///where φ is latitude, λ is longitude, θ is the bearing (clockwise from north),

///δ is the angular distance d/R; d being the distance travelled, R the earth’s radius

///bearing 方位 0,90,180,270

///

private static void GetNewLatLon(double lat, double lon, double d, double bearing, out double lat2, out doublelon2)

{

lat2 = 0.0;

lon2 = 0.0;

double R = 6378.137;

var φ1 =ConvertDegreesToRadians(lat);

var λ1 = ConvertDegreesToRadians(lon);

var θ = ConvertDegreesToRadians(bearing);

var φ2 = Math.Asin(Math.Sin(φ1) * Math.Cos(d / R) +

Math.Cos(φ1) * Math.Sin(d / R) * Math.Cos(θ));

var λ2 = λ1 + Math.Atan2(Math.Sin(θ) * Math.Sin(d / R) * Math.Cos(φ1),

Math.Cos(d / R) - Math.Sin(φ1) * Math.Sin(φ2));

λ2 = (λ2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalise to -180..+180°

lat2 = ConvertRadiansToDegrees(φ2);

lon2 = ConvertRadiansToDegrees(λ2);

}

public static double ConvertDegreesToRadians(double degrees)

{

return degrees * Math.PI / 180;

}

public static double ConvertRadiansToDegrees(double radian)

{

return radian * 180.0 / Math.PI;

}

}

class Test

{

static void Main(string[] args)

{

double latorg = 22.54587746, lonorg = 114.12873077;

var gpsdis = new GetMBR(latorg, lonorg, 5);

Console.WriteLine("maxlat:{0}, minlat:{1}, maxlon:{2}, minlon:{3}",

gpsdis.MaxLatitude, gpsdis.MinLatitude, gpsdis.MaxLongitude, gpsdis.MinLongitude);

Console.WriteLine("maxlat:{0}, minlat:{1}, maxlon:{2}, minlon:{3}",

gpsdis.MaxLatitude2, gpsdis.MinLatitude2, gpsdis.MaxLongitude2, gpsdis.MinLongitude2);

}

}

}

谨以此文纪念那篇CSDN上因为 “本帖子已过去太久远了,不再提供回复功能。”而永远至今晚为止都还没有答案的帖子!

如今LBS应用泛滥,JavaScript到处都能看到源码,gitHub上sourceCode随处可见的时代,希望此文能引导后人,少走我的弯路。如果有更好的方案,也欢迎留言。值此庆祝五一佳节!

给定经纬度计算距离_通过经纬度坐标计算距离的方法(经纬度距离计算)ZZ相关推荐

  1. 弹性地基梁板法计算原理_一种筏板基础内力分析方法与流程

    本发明涉及建筑建设技术领域,具体涉及一种筏板基础内力分析方法. 背景技术: 筏板基础设计通常采用有限元分析(pkpm系列jccad及yjk系列基础设计模块软件),有限元分析由地基基础建模.地基基础有限 ...

  2. 根据经纬度计算范围_遗传算法可视化项目(插曲):关于距离的计算

    今天暂时先不讲遗传算法,我要解决的是TSP问题,具体什么TSP问题之前文章里讲过了,大家可以点一下历史消息或者这里: 遗传算法可视化项目(1):概述 遗传算法可视化项目(2):获取信息 遗传算法可视化 ...

  3. 根据经纬度确定行政区域_使用高德地图api导入行政区域及经纬度

    package com.test; import java.util.HashMap; import java.util.Map; import org.json.JSONArray; import ...

  4. r 语言计算欧氏距离_一文搞懂常用R语言统计值计算:打倒描述性统计拦路虎

    本文来自:R语言:用R计算各种统计值 作者:生物信息学习 目录: 求极差(range) 做频数分布表和频数分布图(graph of frequency distribution) 算术平均数(mean ...

  5. python地图 两点距离_使用Python调用百度地图Api获取两地距离

    完整代码可以关注公众号:Romi的杂货铺 1.获取百度api接口 首先需要在百度的公众平台http://lbsyun.baidu.com/上点击控制台,如果是新用户的话需要进行注册和验证.注册和验证完 ...

  6. 调节e18-d80nk的测量距离_地坪研磨机磨盘平整度的调节方法及好处

    地坪研磨机磨盘平整度的调节方法及好处 名词解释 调节磨盘平整度主要是指将四个磨盘调到静止或运转时磨盘趋向处于同一个平面. 调节方法 1.采用一把高度卡尺或任意一把尺条测量准确磨盘面到箱体底部边沿距离 ...

  7. 求两条轨迹间的hausdorff距离_题型 | 圆上有n个点到直线距离为d?

    圆上有n个点到直线的距离为d 圆 上到直线 的距离为 的点有( )个 方法一:常规方法,画图分析 由图象可以明显看出,圆在直线上方的部分内没有满足题意的点,在直线下方的部分内有两个满足题意的点. 但是 ...

  8. 单代号网络图计算例题_算例分享:SDOF动力系统的共振响应计算

    本文给出一个单自由度系统的共振响应分析实例. 单自由度体系受到简谐荷载激励,相关参数如下: 单自由度体系刚度k=2×106N/m,质量m=2×105kg,阻尼c=1.0×105N·s/m,受到0.5H ...

  9. 弹性地基梁板法计算原理_独立基础加防水板的设计方法的思考

    [注意]:本文依据老规范写成,同时文中的独立柱基加防水板基础由于防水板下未设置软垫层,因此,实际上是一种变厚度的筏板基础,与<建筑结构>技术通讯2007年第7期中的独立柱基加防水板基础不同 ...

  10. 如何判断车与路边线距离_教你如何判断车身与边线的距离?一看就懂

    教你如何判断车身与边线的距离?一看就懂 2018-12-31 11:08 来源: 汽车老八卦 新手上路,常常无法判断自己的车处在车道的哪个位置,或者在对向来车的时候总是担心自己距离左边太近,会和对向行 ...

最新文章

  1. 小巫新闻客户端底部菜单切换实现
  2. 万物新生(爱回收)递交赴美上市招股书,平台服务收入年复合增长达627.7%
  3. SpringBoot退出登录,使session失效
  4. Ubuntu 16.04 安装 Gazebo
  5. 算法训练 纪念品分组(java)
  6. (篇三)C语言的冒泡排序多解、选择排序、数组合并、矩阵相加
  7. Linux 命令(25)—— cp 命令
  8. adobe reader XI 打开后闪退(或过几秒后自动退出)【终极解决方案】
  9. 简述多媒体计算机的特点,多媒体技术的主要特点
  10. SIFT与SURF算法
  11. origin9.0中文版
  12. 计算机表格的条件公式,电脑Excel输出时如何进行多条件判断
  13. cpu超线程优缺点_今天看了下百度百科!看到了超线程的优缺点啊!转!
  14. connect() to unix:/home/tmp/myproject.sock failed (2: No such file or directory)
  15. 打包签名用 文件配置遇到的坑(Keystore was tampered with, or password was incorrect)
  16. C 二维数组存入学生成绩 ,并求平均分,对平均分降序排序
  17. http://ai.taobao.com/?pid=mm_40428920_1105750338_109783200329
  18. Android框架之路——Banner实现轮播图(RecyclerView添加Header)
  19. 从CSDN到个人博客空间
  20. 数商云采购管理系统方案助力采购平台:缩短采购周期、降本增效

热门文章

  1. PHP:150个内置函数简单整合
  2. 【甘道夫】基于scikit-learn实现逻辑回归LogisticRegression
  3. 操作系统和应用的关系
  4. IOIO DeOdexer支持棒棒糖和棉花糖v1.1
  5. 用代码实现一个简单计算器
  6. Equalization Loss论文小结(CVPR2020)
  7. 你应该知道的一些IT名词
  8. 前端面试题整合(自用...持续更...)
  9. Bluetooth SDP介绍
  10. C#专题 | TcpIp通信