已知两个点的经纬度,计算两个点之间的距离(两种办法)

网上淘来了两种办法,一种是haversine公式,这个公式的算法在ubuntu下测试距离长测两个点,非常不准。(在我需要使用这个算法的芯片平台测试也不准,类似ubuntu平台的误差。在visual studio 跑原作者的c#程序,很准)感觉应该是不同平台数学函数不一样导致的,没有深究。

另一种算法,是求球面两点连线弧长的夹角,然后求出弧长,ubuntu测试没有问题(这种距离元误差1公里,距离短误差几十厘米,具体看测试结果)

方法:

#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"static double HaverSin(double theta)
{double v = sin(theta / 2);return v * v;
}
//haversine公式
static double Distance(double lata,double loga, double latb,double logb)
{double EARTH_RADIUS = 6371.0;double PI = 3.14;double dis = 0;double lat_a = 0.0;double lat_b = 0.0;double log_a = 0.0;double log_b = 0.0;//用haversine公式计算球面两点间的距离。//转弧度lat_a = lata  * PI / 180;lat_b = latb  * PI / 180;log_a = loga  * PI / 180;log_b = logb  * PI / 180;//差值double vLon = fabs(log_a - log_b);double vLat = fabs(lat_a - lat_b);//h is the great circle distance in radians, great circle就是一个球体上的切面,它的圆心即是球心的一个周长最大的圆。double h = HaverSin(vLat) + cos(lat_a) * cos(lat_b) * HaverSin(vLon);dis = 2 * EARTH_RADIUS * sin(sqrt(h));return dis;
}
//
static double Distance2(double lata, double loga, double latb, double logb) 
{double EARTH_RADIUS = 6371.0;double PI = 3.14;double distance = 0.0;double lat_a = 0.0;double lat_b = 0.0;double log_a = 0.0;double log_b = 0.0;//转弧度lat_a = lata  * PI / 180;lat_b = latb  * PI / 180;log_a = loga  * PI / 180;log_b = logb  * PI / 180;double dis = cos(lat_b) * cos(lat_a) * cos(log_b -log_a) + sin(lat_a) * sin(lat_b);distance = EARTH_RADIUS * acos(dis);return distance;
}int main(void)
{while(1){double distance = 0;distance = Distance(-35.468245, -110.459545, 35.467873, 110.459519);//16326.509printf("distance: %lf\n",distance);distance = Distance(35.468245, 110.459545, -35.467873, 110.459519);//7882.759printf("distance: %lf\n",distance);distance = Distance(43, 28, 88, 62);//5042.73printf("distance: %lf\n",distance);distance = Distance(28, 43, 62, 88);//4998.83printf("distance: %lf\n",distance);distance = Distance(22.535562, 113.946085, 22.535562, 113.9461);//0.002printf("distance: %lf\n",distance);distance = Distance(22.535562, 113.946085, 22.535562, 113.946);//0.009printf("distance: %lf\n",distance);distance = Distance(23.70281595, 117.1759528, 23.70507779,117.2345917);//5.975 printf("distance: %lf\n",distance);distance = Distance(23.70281595, 117.1759528, 2, 2);//12457.64printf("distance: %lf\n",distance);distance = Distance(30.05, 106.1667, 29.15344, 104.6143);//180.169printf("distance: %lf\n",distance);distance = Distance(28.86483, 121.1463, 28.86444, 121.1455);//0.089printf("distance: %lf\n",distance);distance = Distance(43.5645, 81.9229, 43, 91);//737.045printf("distance: %lf\n",distance);distance = Distance(37.48, 29.09, 36, 35);//551.593printf("distance: %lf\n\n",distance);distance = Distance2(-35.468245, -110.459545, 35.467873, 110.459519);//16326.509printf("distance: %lf\n",distance);distance = Distance2(35.468245, 110.459545, -35.467873, 110.459519);//7882.759printf("distance: %lf\n",distance);distance = Distance2(43, 28, 88, 62);printf("distance: %lf\n",distance);distance = Distance2(28, 43, 62, 88);printf("distance: %lf\n",distance);distance = Distance2(22.535562, 113.946085, 22.535562, 113.9461);printf("distance: %lf\n",distance);distance = Distance2(22.535562, 113.946085, 22.535562, 113.946);printf("distance: %lf\n",distance);distance = Distance2(23.70281595, 117.1759528, 23.70507779, 117.2345917);printf("distance: %lf\n",distance);distance = Distance2(23.70281595, 117.1759528, 2, 2);printf("distance: %lf\n",distance);distance = Distance2(30.05, 106.1667, 29.15344, 104.6143);printf("distance: %lf\n",distance);distance = Distance2(28.86483, 121.1463, 28.86444, 121.1455);printf("distance: %lf\n",distance);distance = Distance2(43.5645, 81.9229, 43, 91);printf("distance: %lf\n",distance);distance = Distance2(37.48, 29.09, 36, 35);printf("distance: %lf\n\n",distance);//sleep(3);break;}return 0;
}

ubuntu测试结果:

ning@ning-virtual-machine:~/proj/harversin$ g++ harversin.c 
ning@ning-virtual-machine:~/proj/harversin$ ./a.out 
distance: 10429.537100
distance: 6982.850624
distance: 4790.124816
distance: 4752.867756
distance: 0.001540
distance: 0.008726
distance: 5.973073
distance: 9394.042312
distance: 180.093178
distance: 0.089125
distance: 736.150314
distance: 551.118178distance: 16345.841375
distance: 7883.737691
distance: 5041.292612
distance: 4997.779018
distance: 0.001543
distance: 0.008727
distance: 5.973073
distance: 12452.776520
distance: 180.105172
distance: 0.089125
distance: 736.971269
distance: 551.462296

方法一 根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离) - 莫水千流 - 博客园

球面上任意两点之间的距离计算公式可以参考维基百科上的下述文章。

  • Great-circle distance
  • Haversine formula

值得一提的是,维基百科推荐使用Haversine公式,理由是Great-circle distance公式用到了大量余弦函数, 而两点间距离很短时(比如地球表面上相距几百米的两点),余弦函数会得出0.999...的结果, 会导致较大的舍入误差。而Haversine公式采用了正弦函数,即使距离很小,也能保持足够的有效数字。 以前采用三角函数表计算时的确会有这个问题,但经过实际验证,采用计算机来计算时,两个公式的区别不大。 稳妥起见,这里还是采用Haversine公式。

其中

  • R为地球半径,可取平均值 6371km;
  • φ1, φ2 表示两点的纬度;
  • Δλ 表示两点经度的差值。

根据2个经纬度坐标,距离计算函数

公式来历:

VERSINE(F)=1-cos(F)

Haversine名字来历是Ha-VERSINE,即Half-Versine ,表示sin的一半的意思。

hav(A) = (1-cos(A))/2 = sin(A/2)* sin(A/2)

推倒过程:

如下一个半径为1 的圆,O是圆心,A、B是弦(chord)。角度AOB=theta。则角度AOC=theta/2。OC是垂直于AB的垂线(perpendicular)。AC长度是sin(theta/2),AB长度是2*sin(theta/2)。

(图1)

如下地球图所示,假设半径R为1,O是球心,A (lat1,lon1) 和 B (lat2,lon2) 是我们感兴趣的2个点。2跟经度线 lon1,lon2相交于北极(north pole)N。EF所在的线是赤道(equator)。ACBD是平面上的等腰梯形的四个顶点(vertice)。AC和DB的弦(直线)在图上没有画出。CD的位置是:C (lat2,lon1) and D (lat1,lon2)。角度AOC是A点与C点的纬度差 dlat。角度EOF是经度E点和经度F点的差dlon。

(图2)

弦AC的长度,参照图1的方式,那么是AC=2*sin(dlat/2),弦BD也是一样的长度。

E、F 2个点是赤道上的2个点,它们的纬度是0。EF的距离是EF=2*sin(dlon/2)

A、D2个点所在的纬度是lat1。AD所在纬度的圆平面的半径是cos(lat1)。从A作一条垂线(perpendicular)到OE为AG,AO是球半径,则OG=cos(lat1),即A、D所在纬度圆圈的半径(AO`)。

这时候,AD的弦长AD= 2*sin(dlon/2)*cos(lat1),类似的可以推出CB的长度= CB=2*sin(dlon/2)*cos(lat2)

下面看一下如何求AB的长度,回到平面等腰梯形,如下图:

(图3)

AH是到CB的垂线(perpendicular),CH= (CB-AD)/2。

根据勾股定理(Pythagorean theorem): 【^2表示2的平方】

AH^2 = AC^2 - CH^2

       = AC^2 - (CB-AD)^2/4

HB 的长度是HB=AD+CH = AD+(CB-AD)/2 = (CB+AD)/2,根据勾股定理得到:

  AB^2 = AH^2 + HB^2

       = AC^2 - (CB-AD)^2/4 + (CB+AD)^2/4

       = AC^2 + CB*AD

根据前面球面上的求经纬距离的方式,我们已经得到 AC、AD和CB的长度,代入公式得到:

  AB^2 = 4*(sin^2(dlat/2) + 4*cos(lat1)*cos(lat2)*sin^2(dlon/2))

假设中间值h 是AB长度一半的平方,如下

  h = (AB/2)^2

    = (sin^2(dlat/2)) + cos(lat1) * cos(lat2) * sin^2(dlon/2)

  (请参看代码里的h)

最后一步,是求得代表AB长度的角度AOB。参照图1的方式,我们可以知道

(图4)

设AC=

,根据勾股定理(Pythagorean theorem)得到:

OC= 

= sqrt(OA^2 - AC^2)

         = 

= sqrt(1-a)   // sqrt表示开根号

如果设c是角AOB的度数值。

tan(<AOC) = tan(c)= AC/OC = sqrt(a)/sqrt(1-a)

则:

  c = 2 * arctan(sqrt(a)/sqrt(1-a)),

最后的AB真实距离,把地球半径带上就可以了。

distance = 2 * EARTH_RADIUS * c。

2)另外一种方法:

SQL Server本身是支持空间数据索引的(Spatial Indexing),具有空间数据计算能力。

他是通过一个扩展DLL Microsoft.SqlServer.Types.dll 来实现这些功能的。这是一个托管DLL,那意味着.NET C# asp.net 也可以使用些功能。

例如通过 reference 引用: Microsoft.SqlServer.Types.dll 这个dll。

var a = SqlGeography.Point(22.54587746 , 114.12873077, 4326); //上海的某个点
var b = SqlGeography.Point(23, 115, 4326); //上海的某个点,4236代表WGS84这种坐标参照系统。
Console.WriteLine(a.STDistance(b)); //距离

这个算出来的距离,与上面使用haversine公式算出的距离,误差在几米之内。

方法二https://www.jianshu.com/p/4a0eaf6743b7

计算经纬度坐标距离的原理就是就算球面两点间的距离,经纬度表示法实际是用角度描述的坐标。纬度上下一共180度,经度360度。

假设地球是标准的球形,计算距离就等于计算一个截面圆的弧长。计算弧长的话需要先求出两点相对于球芯的夹角。然后根据半径就可以求出弧长了,也就是距离。

假设A点纬度lat1,精度lng1.B点纬度lat2, 经度lng2, 地球半径为R

求这个夹角之前,先把坐标转换为直角空间坐标系的点,并让地心为坐标中心点,即
A(Rcos(lat1)cos(lng1),  Rcos(lat1)sin(lng1), Rsin(lat1))
B(R
cos(lat2)cos(lng2),  Rcos(lat2)sin(lng2), Rsin(lat2))

然后算夹角,这里用向量的夹角计算方法,可以求出夹角余弦值,那么夹角COS为
COS = (向量A*向量B) / (向量A的模 * 向量B的模)

令A为(x,y,z),B(a,b,c)
COS = (xa+yb+zc)/[√(x2+y2+z2)*√(a2+b2+c2)]

把经纬度的坐标代进去
COS = cos(lat2) * cos(lat1) * cos(lng1-lng2) + sin(lat2)*sin(lat1)

得到夹角的余弦值可得角度,然后就可以算出弧长了,即得距离(arccos 为反余弦函数,这里反余弦的结果得到的是弧度)
d = 2PIR * (arccos(COS) / 2 * PI)
d = R * arccos(COS)
最终
d = R * arccos( cos(lat2) * cos(lat1) * cos(lng2-lng1) + sin(lat2)*sin(lat1))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/243423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vivado HLS基本应用

Vivado HLS基本应用 1、双击Vivado HLS图标 2、创建工程可以&#xff0c;点快捷键或者从File->创建新工程 3、填写工程名和工程存放路径 3、添加主函数名&#xff0c;添加文件&#xff08;如果有需要的话&#xff09; 4、添加测试文件 5、优化文件的添加和主时钟的选择…

Yammer从Scala转向Java

近日&#xff0c;由Yammer雇员Coda Hale发给Typesafe的Scala商业管理层的邮件通过YCombinator被泄漏出来并在GitHub上刊出。该邮件确认Yammer正在将其基础设施栈从Scala迁回至Java&#xff0c;原因在于Scala的复杂性与性能问题。\u0026#xD;\nYammer的公关Shelley Risk向InfoQ证…

Java基本流程控制语句

package com.org.lxh;import java.util.Scanner;/*** Java流程控制语句,if,if……else,switch,while,do……while,for等等* author hemmingway <hemmingway163.com>***/ public class CommCtrl {/*** param args*/public static void main(String[] args) {// TODO Auto-…

Mozilla考虑支持H.264

历史上&#xff0c;Mozilla曾拒绝过使用非开放的编码解码器&#xff08;如H.264&#xff09;&#xff0c;InfoQ此前也就这一话题进行过报导。Mozilla之所以拒绝主要是因为支持H.264与它的思想观念不一&#xff0c;因为H.264有专利覆盖&#xff0c;并且由MPEG-LA许可使用。人们不…

芯昇 CM32M101A 固件库 W25Q128JWSIQ 驱动

注意:此型号的JEDEC ID是0xEF6018,不同于网上满天飞的驱动,调试此器件驱动一定要确认。 官方SDK里面的驱动有问题,读写数据乱码,个人感觉是完全搬运野火电子的,因为除了名不一样,格式一毛一样。 drv_spi.h #ifndef _DRV_SPI_H_ #define _DRV_SPI_H_#ifdef __cplusplu…

MATLAB实现简单目标跟踪

MATLAB实现简单目标跟踪 预处理:中值滤波; 目标检测:二值化 后处理:形态学滤波或者连通性处理 目标跟踪:计算形心 clear all; close all; %预处理-中值滤波 t = imread(1.png);%原始图像 t1 = rgb2gray(t);%灰度图像 t2=imnoise(t1,salt & pepper,0.3);%加入椒盐噪声…

Java数组操作

package com.org.lxh;import java.util.Arrays;/*** 讲解Java数组* author hemmingway <hemmingway163.com>**/ public class ArrayDemo {/*** param args*/SuppressWarnings("unused") //元注释&#xff0c;忽略没有使用的变量public static void main(Strin…

振臂高呼式的写作:谈肖亦农的《毛乌素绿色传奇》

这是2011年底我与肖亦农和鄂尔多斯文联主席乌力吉布林在人民大会堂参加中国作家协会代表大会的合影&#xff0c;半年后我们又在人民大会堂相聚&#xff0c;是参加肖亦农的最新作品《毛乌素绿色传奇》研讨会。 肖亦农是我多年的朋友&#xff0c;是兄长&#xff0c;也是内蒙老乡&…

蜕变与成长中的青春创作:评论家谈少数民族青年作家的创作

在日前由中国作家协会主办&#xff0c;中国少数民族作家学会、《民族文学》杂志社协办的少数民族青年作家作品研讨会上&#xff0c;来自全国的10位少数民族青年写作者成为主要研讨对象。他们是照日格图(蒙古族)、苏笑嫣(蒙古族)、鲍尔金娜(蒙古族)、陶丽群(壮族)、马金莲(回族)…

Ubuntu 国内镜像源

中科大镜像站 阿里云镜像站 兰州大学镜像站 北京理工大学镜像站 浙江大学镜像站 清华大学镜像站

彩色图转化为灰度图

彩色图转化为灰度图 源文件 `timescale 1ns / 1ps module rgb2gary(input [7:0] rgb_r,input [7:0] rgb_g,input [7:0] rgb_b,output [7:0] gary); //Verilog不支持小数 // assign gary = 0.299 * rgb_r + 0.587 * rgb_g + 0.114 * rgb_b; wire [17:0] gary_te…

Java面向对象入门

package com.org.lxh;import java.util.Calendar;/*** 面向对象编程入门* author hemmingway <hemmingway163.com>**/ public class Chp6 {int num500; //成员变量public static int num2200; //静态变量public static final double PI3.1415926; /…

时间与经验的等待:谈几位少数民族“80后”和“90后”作家

照日格图是我欣赏的蒙古族青年散文家。两年前&#xff0c;我就读过他的《怀念一垛草》。这篇散文通过打草与草垛将故事连接在一起&#xff0c;表现了蒙古人质朴真实的生活和命运。那些既熟悉又陌生的细节让我有种莫名的感动&#xff0c;它既让我们了解了草原秋天的景象&#xf…

win10系统如何禁用驱动程序强制签名

1. 首先打开并登录操作系统左下角。开始菜单上单击选择设置 2. 在设置页面选择“更新和安全” 3.在”更新和安全页面“找到左侧的恢复选项&#xff0c;在右侧选择”立即重新启动” 4.在启动页面选择疑难解答 5. 进入疑难解答页面选择”高级选项“ 6.在”高级选项“页面中选择”…

说不尽的嘎达梅林:读郭雪波的长篇小说《青旗•嘎达梅林》

嘎达梅林做为一个民族英雄&#xff0c;已经是个永久的传奇。很多文学作品、电影、电视&#xff0c;还有音乐都表现过这个人物&#xff0c;使他的影响力已经超出了蒙古民族的范畴&#xff0c;成为整个中华民族的英雄人物长廊中的一个典型。正因为如此也给后来的写作者制造了难题…

实现图像的二值化

实现图像的二值化 源文件 `timescale 1ns / 1ps module binarization(//module clockinput clk , // 时钟信号input rst_n , // 复位信号(低有效)//图像处理前的数据接口input ycbcr_vsync , // vsync信号input ycbcr_hsync , // hsync信号input ycbcr_de , // data enable…

Java面向对象进阶

相关额外的代码待上传。。。 /*** 面向对象进阶*/ package com.org.lxh;import com.org.lxh.ext.Demo; import com.org.lxh.impl.AysTest; import com.org.lxh.impl.Person; import com.org.lxh.impl.Test; import com.org.lxh.inter.InterTest; import com.org.lxh.obj.Addres…

2012 IBM软件技术峰会:IBM与开发者谈四大热门领域看法

8月23日&#xff0c;以“技术维新&#xff0c;预见未来”为主题的2012 IBM软件技术峰会在京举行&#xff0c;本次大会在“大数据、云计算、敏捷、移动”四个领域展开讨论&#xff0c;IBM全球副总裁兼中国开发中心总经理王阳、IBM软件集团Rational总经理Kristof Kloeckner、IBM系…

实现图像的中值滤波

实现图像的中值滤波 底层模块 `timescale 1ns / 1ps module median_filter #(parameter DATA_WIDTH = 8 ) (input clk , //pixel clkinput reset_p ,input [7:0] data_in ,input data_in_valid ,input data_in_hs ,input dat…

我的博客今天6岁298天了,我领取了元老博主徽章

我的博客今天6岁298天了&#xff0c;我领取了徽章. 2005.11.26&#xff0c;我在新浪博客安家。1999.08.20&#xff0c;我写下了第一篇博文&#xff1a;《小说是读者的艺术》。2006.04.20&#xff0c;我上传了第一张图片到相册。至今&#xff0c;我的博客共获得845,523次访问。…