如何将纬度或经度转换为米?

182

如果我有一个标准NMEA格式的纬度或经度读数,是否有一种简单的方式/公式将该读数转换为米,并且我可以在Java(J9)中实现?

编辑: 好吧,似乎我想做的事情不是很容易,但我真正想做的是:

假设我有一个航点的纬度和经度以及一个用户的纬度和经度,是否有一种简单的方法来比较它们,以决定何时告诉用户他们已经接近航点的合理距离?我知道“合理”是主观的,但这很容易实现还是过于数学化了?


2
你是指 UTM 吗?http://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system - Adrian Archer
1
将lat/long转换为米是什么意思?米指的是哪里?您是否正在寻找一种计算从一个坐标到另一个坐标沿着地球表面距离的方法? - Baltimark
2
我偶然发现了这个问题,想要在经纬度上执行SQL查询,并找到了这篇很棒的文章,底部有一些Java代码。它可能也会对你感兴趣。 - Kristof Van Landschoot
1
可能是重复的问题:如何计算两个经纬度点之间的距离? - Teepeemm
1
这里大部分的答案都使用简单的球面三角学,因此与 GPS 系统中使用的 WGS84 椭球距离相比,结果相对粗糙。其中一些答案提到了 Vincenty 的椭球公式,但该算法是为 1960 年代的台式计算器设计的,存在稳定性和精度问题;我们现在有更好的硬件和软件。请参阅 GeographicLib,这是一个高质量的库,具有各种语言的实现。(我不确定 GDAL 在其 WGS84 工作中使用什么,我认为它仍然使用 Vincenty)。 - PM 2Ring
显示剩余4条评论
19个回答

236

这里是一个JavaScript函数:

function measure(lat1, lon1, lat2, lon2){  // generally used geo measurement function
    var R = 6378.137; // Radius of earth in KM
    var dLat = lat2 * Math.PI / 180 - lat1 * Math.PI / 180;
    var dLon = lon2 * Math.PI / 180 - lon1 * Math.PI / 180;
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
    Math.sin(dLon/2) * Math.sin(dLon/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;
    return d * 1000; // meters
}

解释: https://en.wikipedia.org/wiki/Haversine_formula

哈弗赛公式用于计算两个点在球面上的经纬度间的大圆距离。


3
寻找用于WGS和UTM转换的库:https://github.com/urbanetic/utm-converter - Aram Kocharyan
6
如果有人能在上述代码中添加一些解释性注释,我会非常感激。提前谢谢! - Ravindranath Akila
发现这个,这个评论似乎是对它的采纳。该链接还说它是基于此文章上的距离计算。所以任何未解答的问题都可以在原始链接中找到。 :) - Joachim
1
我该如何将高程加入到这个计算中? - dangalg
1
@dangalg,假设地面是平的,距离较近,您还有高度alt1alt2,而dm是以米为单位的距离(上面的measure函数的结果)。 您可以使用JS的hypothenuse函数Math.hypot(x, y),其中xdmymax(alt1, alt2) - min(alt1, alt2) - Marco Aurélio da Silva

119

如果你正在寻找一个简单的公式,那么这可能是最简单的方法,假设地球是一个周长为40075公里的球体。

1°纬度线对应的长度 = 总是111.32公里

1°经度线对应的长度 = 40075公里 * cos( 纬度 ) / 360


2
经度方程是如何工作的?在纬度为90度的情况下,您预计它应该显示约111公里附近;但实际上它显示为0;同样,靠近它的值也接近于0。 - Reece
16
赤道的纬度为0°,极点的纬度为90°(并非相反)。对于赤道,该公式给出40075公里* cos(0°)/ 360 = 111公里。对于极点,该公式给出40075 * cos(90°)/ 360 = 0公里。 - Ben
1
我认为这种方法很简单,特别是问题并没有要求精确计算两点之间的距离,而只是要求它们是否“足够接近”。使用这些公式,我们可以轻松检查用户是否在以航路点为中心的正方形内。检查正方形比检查圆形要简单得多。 - Ben
1
这比使用Haversine要快得多,如果你正在进行近似计算,它非常有效,谢谢。 - Richard
不对。如果等式左边是Km,右边也会是Km,而不是米。 - SeF
1
现在已经更正了,结果以公里为单位。 - Ben

38

我使用从 http://en.wikipedia.org/wiki/Lat-lon 中的公式来近似计算两个坐标之间的短距离:

m_per_deg_lat = 111132.954 - 559.822 * cos( 2 * latMid ) + 1.175 * cos( 4 * latMid);
m_per_deg_lon = 111132.954 * cos ( latMid );

下面的代码中,我保留了原始数字以显示它们与维基百科公式的关系。

double latMid, m_per_deg_lat, m_per_deg_lon, deltaLat, deltaLon,dist_m;

latMid = (Lat1+Lat2 )/2.0;  // or just use Lat1 for slightly less accurate estimate


m_per_deg_lat = 111132.954 - 559.822 * cos( 2.0 * latMid ) + 1.175 * cos( 4.0 * latMid);
m_per_deg_lon = (3.14159265359/180 ) * 6367449 * cos ( latMid );

deltaLat = fabs(Lat1 - Lat2);
deltaLon = fabs(Lon1 - Lon2);

dist_m = sqrt (  pow( deltaLat * m_per_deg_lat,2) + pow( deltaLon * m_per_deg_lon , 2) );

维基百科条目表明纵向100公里的距离计算精度在0.6米以内,横向100公里的距离计算精度在1厘米以内,但我并未验证这一精度是否足够满足我的使用需求。


3
请注意,2017年的维基百科页面上有另一个(似乎更精细的)公式。 - Gorka Llona
3
是的,维基百科中的公式略有不同,但似乎其他维基百科中的公式是基于这个不错的GIS Stack Exchange答案,那里面有人实际进行了计算。 - not2qubit
1
请注意,在这个方程中,“latMid”是以弧度为单位的,而“m_per_deg_lat”是以度为单位的。因此,如果您想要计算纬度为30N(例如)的值,请在方程中使用“latMid = pi*30/180”。 - Eli Holmes
我认为您在这里打错了:m_per_deg_lon,因为输入可能需要经度而不是纬度。 - EngrStudent
1
@EngrStudent 不,他是正确的,经度的转换系数取决于纬度,因为在极点相遇之前,子午线之间的距离会变小,因此每经度米数也会变小。 - André

9

这里是 b-h-的函数 的 R 版本,以防万一:

measure <- function(lon1,lat1,lon2,lat2) {
    R <- 6378.137                                # radius of earth in Km
    dLat <- (lat2-lat1)*pi/180
    dLon <- (lon2-lon1)*pi/180
    a <- sin((dLat/2))^2 + cos(lat1*pi/180)*cos(lat2*pi/180)*(sin(dLon/2))^2
    c <- 2 * atan2(sqrt(a), sqrt(1-a))
    d <- R * c
    return (d * 1000)                            # distance in meters
}

8
地球是一个非常不规则的表面,因此没有简单的公式可以完全解决这个问题。你必须使用地球的近似模型,并将你的坐标投影到它上面。我通常看到用于此的模型是WGS 84。这是GPS设备通常用来解决完全相同的问题的模型。
NOAA有一些软件可供下载,可帮助解决这个问题在他们的网站上

7
有许多工具可以轻松完成这个任务。请参考monjardin的回答,了解更多详细信息。
然而,这并不难。听起来您正在使用Java,因此建议您尝试使用GDAL等工具。它提供了Java包装器,其中包含将从纬度/经度(地理坐标)转换为UTM(投影坐标系)或其他合理的地图投影所需的所有工具。
UTM很好用,因为它是以米为单位的,易于操作。但是,您需要获取适当的UTM区域才能完成良好的工作。通过谷歌搜索,可以找到一些简单的代码来查找适当的纬度/经度对应的UTM区域。

3

2
一海里(1852米)被定义为赤道上一个经度 的长度。然而,你需要定义一个地图投影(另请参见UTM),以使转换真正有意义。

1
不,海里是由国际标准(参见http://en.wikipedia.org/wiki/Nautical_mile)定义为1852米。它与测量类似于地球这样的椭球体表面上的弧线的关系现在既有历史意义又是近似的。 - High Performance Mark

1

原帖问道:“如果我有一个标准NMEA格式的纬度或经度读数,是否有一种简单的方法/公式将该读数转换为米?”

我已经有一段时间没有使用Java了,所以我在“PARI”中提供了解决方案。只需将您的点的纬度和经度插入以下方程式中,即可获得每秒经度和每秒纬度的精确弧长和比例尺(以米为单位)。我为自由开源的Mac-PC数学程序“PARI”编写了这些方程式。您只需将以下内容粘贴到其中,然后我将展示如何将它们应用于两个虚构的点:

\\=======Arc lengths along Latitude and Longitude and the respective scales:
\p300
default(format,"g.42")
dms(u)=[truncate(u),truncate((u-truncate(u))*60),((u-truncate(u))*60-truncate((u-truncate(u))*60))*60];
SpinEarthRadiansPerSec=7.292115e-5;\
GMearth=3986005e8;\
J2earth=108263e-8;\
re=6378137;\
ecc=solve(ecc=.0001,.9999,eccp=ecc/sqrt(1-ecc^2);qecc=(1+3/eccp^2)*atan(eccp)-3/eccp;ecc^2-(3*J2earth+4/15*SpinEarthRadiansPerSec^2*re^3/GMearth*ecc^3/qecc));\
e2=ecc^2;\
b2=1-e2;\
b=sqrt(b2);\
fl=1-b;\
rfl=1/fl;\
U0=GMearth/ecc/re*atan(eccp)+1/3*SpinEarthRadiansPerSec^2*re^2;\
HeightAboveEllipsoid=0;\
reh=re+HeightAboveEllipsoid;\
longscale(lat)=reh*Pi/648000/sqrt(1+b2*(tan(lat))^2);
latscale(lat)=reh*b*Pi/648000/(1-e2*(sin(lat))^2)^(3/2);
longarc(lat,long1,long2)=longscale(lat)*648000/Pi*(long2-long1);
latarc(lat1,lat2)=(intnum(th=lat1,lat2,sqrt(1-e2*(sin(th))^2))+e2/2*sin(2*lat1)/sqrt(1-e2*(sin(lat1))^2)-e2/2*sin(2*lat2)/sqrt(1-e2*(sin(lat2))^2))*reh;
\\=======

为了将这个应用到您的问题类型上,我会假设您的一个数据点位于

[纬度,经度]=[+30, 30]

而另一个数据点位于

[纬度,经度]=[+30:00:16.237796,30:00:18.655502]。

为了将这些点转换为两个坐标系中的米:

我可以建立一个以第一个点为原点的米制坐标系:[0,0] 米。 然后我可以定义 x 轴坐标为东西方向,y 轴坐标为南北方向。

那么第二个点的坐标就是:

? [longarc(30*Pi/180,30*Pi/180,((18.655502/60+0)/60+30)*Pi/180),latarc(30*Pi/180,((16.237796/60+0)/60+30)*Pi/180)]
%9 = [499.999998389040060103621525561027349597207, 499.999990137812119668486524932382720606325]

精度警告: 需要注意的是: 由于地球表面是弯曲的, 在其上获得的二维坐标不能遵循 与笛卡尔坐标系完全相同的规则, 例如勾股定理。 此外,指向正北-正南的线条 在北半球会汇聚。 在北极,显然 南北线不适用于 地图上平行于y轴的线。

在30度纬度和500米长度下, 如果比例尺从[0,+500]而不是[0,0]设置, x坐标将变化1.0228英寸:

? [longarc(((18.655502/60+0)/60+30)*Pi/180,30*Pi/180,((18.655502/60+0)/60+30)*Pi/180),latarc(30*Pi/180,((16.237796/60+0)/60+30)*Pi/180)]
%10 = [499.974018595036400823218815901067566617826, 499.999990137812119668486524932382720606325]
? (%10[1]-%9[1])*1000/25.4
%12 = -1.02282653557713702372872677007019603860352
? 


500米/1英寸的误差大约只有1/20000,对于大多数图表来说已经足够好了,但是你可能想要减少1英寸的误差。如果要完全通用地将纬度、经度转换为任意点的正交x、y坐标,我会选择放弃将坐标线与东西方向和南北方向对齐,而仍然保持中心y轴指向正北。例如,您可以围绕极点(围绕3D Z轴)旋转地球,使地图上的中心点位于经度零度。然后倾斜地球(围绕3D y轴),将您的中心点带到纬度、经度=[0,0]。在地球上,纬度、经度=[0,0]的点距离极点最远,并且它们周围的纬度、经度网格最正交,因此您可以使用这些新的“南北”、“东西”线作为坐标x、y线,而不会在将中心点从极点旋转之前发生拉伸。展示一个明确的例子需要更多的空间。

1

为什么要局限于一个学位?

这个公式是基于比例计算的:

distance[m] : distance[deg] = max circumference[m] : 360[deg]

假设你已经得到了一个纬度和经度的角度值:(longitude[deg], latitude[deg]) 对于纬度来说,最大周长总是经过两极的那一条。在球形模型中,半径为R(以米为单位),最大周长为2 * pi * R,比例可表示为:
latitude[m] = ( 2 * pi * R[m] * latitude[deg] ) / 360[deg]

(请注意,度数和度简化了,剩下的两边都是米。)
对于经度最大周长与纬度的余弦成比例(想象一下在北极圈内循环比在赤道附近循环要短),因此它是2 * pi * R * cos(latitude[rad])。因此,
longitude distance[m] = ( 2 * pi * R[m] * cos(latitude[rad]) * longitude[deg] ) / 360[deg]

请注意,在计算余弦值之前,您需要将纬度从度转换为弧度。
省略为那些只寻找公式的人提供的细节:
lat_in_m = 111132.954 * lat_in_degree / 360
lon_in_m = 111132.954 * cos(lat_in_radians) * lon_in_deg ) / 360

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接