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

如果我有一个标准 NMEA 格式的经度或纬度读数,是否有一个简单的方法/公式来将这个读数转换成米,然后我可以在 Java (J9)中实现它?

编辑: 好吧,看起来我想做的是不可能的 很容易,但是我真正想做的是:

假设我有一个路径点和一个用户的路径点,有没有一种简单的方法来比较它们,以决定什么时候告诉用户它们在距离路径点很近的 合情合理范围内?我意识到合理是一门学科,但这是容易做到的,还是仍然过于数学化?

415218 次浏览

一海里(1852米)被定义为赤道上经度的 弧分钟。但是,您需要定义一个 地图投影(另请参阅 UTM) ,在这个 地图投影中进行转换才能真正有意义。

有许多工具可以使这个过程变得简单。请参阅 Monjardin 的回答了解更多相关细节。

然而,这样做并不一定困难。听起来像是在使用 Java,所以我建议您查看类似于 GDAL的内容。它为它们的例程提供了 java 包装器,并且它们拥有从 Lat/Lon (地理坐标)到 UTM (投影坐标系)或其他合理的映射投影所需的所有工具。

UTM 很好,因为它是米,所以很容易使用。但是,您需要获得适当的 UTM 区才能做好工作。有一些简单的代码可以通过谷歌来找到一个适合 lat/long 对的区域。

    'below is from
'http://www.zipcodeworld.com/samples/distance.vbnet.html
Public Function distance(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal lat2 As Double, ByVal lon2 As Double, _
Optional ByVal unit As Char = "M"c) As Double
Dim theta As Double = lon1 - lon2
Dim dist As Double = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + _
Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * _
Math.Cos(deg2rad(theta))
dist = Math.Acos(dist)
dist = rad2deg(dist)
dist = dist * 60 * 1.1515
If unit = "K" Then
dist = dist * 1.609344
ElseIf unit = "N" Then
dist = dist * 0.8684
End If
Return dist
End Function
Public Function Haversine(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal lat2 As Double, ByVal lon2 As Double, _
Optional ByVal unit As Char = "M"c) As Double
Dim R As Double = 6371 'earth radius in km
Dim dLat As Double
Dim dLon As Double
Dim a As Double
Dim c As Double
Dim d As Double
dLat = deg2rad(lat2 - lat1)
dLon = deg2rad((lon2 - lon1))
a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(deg2rad(lat1)) * _
Math.Cos(deg2rad(lat2)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2)
c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a))
d = R * c
Select Case unit.ToString.ToUpper
Case "M"c
d = d * 0.62137119
Case "N"c
d = d * 0.5399568
End Select
Return d
End Function
Private Function deg2rad(ByVal deg As Double) As Double
Return (deg * Math.PI / 180.0)
End Function
Private Function rad2deg(ByVal rad As Double) As Double
Return rad / Math.PI * 180.0
End Function

有很多方法可以计算这个。它们都使用半径为地球半径的近似球面三角学。

尝试使用 http://www.movable-type.co.uk/scripts/latlong.html来获得一些不同语言的方法和代码。

地球是一个令人讨厌的不规则表面,所以没有简单的公式可以做到这一点。你必须生活在一个地球的近似模型中,并将你的坐标投射到它上面。我通常看到的用于此的模型是 WGS 84。这是 GPS 设备通常用来解决完全相同的问题。

NOAA 有一些软件,你可以下载来帮助这个 在他们的网站上

你需要把坐标转换成弧度来完成球面几何学。一旦转换,然后你可以计算两点之间的距离。然后,距离可以转换为任何您想要的测量。

如果它足够近,你可以把它们当作平面上的坐标。比如说,如果不需要完美的精确度,你所需要的只是粗略地猜测所涉及的距离,以便与任意的限制进行比较,那么这种方法在街道或城市水平上都可以起作用。

下面是一个 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

根据经度和纬度,半正矢公式决定了球面上两点之间的大圆距离。

要转换 x 和 y 表示的经纬度,你需要决定使用哪种类型的地图投影。对我来说,椭圆墨卡托看起来很不错。您可以找到一个实现(也是在 Java 中)。

根据地球上的平均距离。

1 ° = 111公里;

转换为弧度和除以米,取为 RAD 的神奇数字,以米为单位: 0.000008998719243599958;

然后:

const RAD = 0.000008998719243599958;
Math.sqrt(Math.pow(lat1 - lat2, 2) + Math.pow(long1 - long2, 2)) / RAD;

以下是 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
}

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

以公里为单位的长度(纬度1 °) = 总是111.32公里

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

如果您想要一个简单的解决方案,那么使用其他注释中概述的 半正矢公式。如果你有一个精度敏感的应用程序请记住,半正矢公式不能保证比0.5% 更好的精度,因为它假设地球是一个球体。考虑到地球是一个扁球体考虑使用 文森特的公式。 此外,我不确定我们应该使用什么半径的半正矢公式: {赤道: 6378.137 km,极地: 6356.752 km,体积: 6371.0088 km }。

下面是一个 MySQL 函数:

SET @radius_of_earth = 6378.137; -- In kilometers


DROP FUNCTION IF EXISTS Measure;
DELIMITER //
CREATE FUNCTION Measure (lat1 REAL, lon1 REAL, lat2 REAL, lon2 REAL) RETURNS REAL
BEGIN
-- Multiply by 1000 to convert millimeters to meters
RETURN 2 * @radius_of_earth * 1000 * ASIN(SQRT(
POW(SIN((lat2 - lat1) / 2 * PI() / 180), 2) +
COS(lat1 * PI() / 180) *
COS(lat2 * PI() / 180) *
POW(SIN((lon2 - lon1) / 2 * PI() / 180), 2)
));
END; //
DELIMITER ;

下面是 Swift的一个版本:

func toDegreeAt(point: CLLocationCoordinate2D) -> CLLocationDegrees {
let latitude = point.latitude
let earthRadiusInMetersAtSeaLevel = 6378137.0
let earthRadiusInMetersAtPole = 6356752.314
    

let r1 = earthRadiusInMetersAtSeaLevel
let r2 = earthRadiusInMetersAtPole
let beta = latitude


let earthRadiuseAtGivenLatitude = (
( pow(pow(r1, 2) * cos(beta), 2) + pow(pow(r2, 2) * sin(beta), 2) ) /
( pow(r1 * cos(beta), 2) + pow(r2 * sin(beta), 2) )
)
.squareRoot()
      

let metersInOneDegree = (2 * Double.pi * earthRadiuseAtGivenLatitude * 1.0) / 360.0
let value: CLLocationDegrees = self / metersInOneDegree
return value
}

原版海报问道 如果我有一个标准 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英寸的误差。 一种完全通用的转换方法 Lat,long 到正交的 x,y 坐标 在地球上的任何一个地方,我都会选择放弃 对准东西方向的坐标线 和南北,除了仍然保持中心 Y 轴指向正北。例如,你可以 围绕两极旋转地球仪(围绕三维 Z 轴)
所以地图的中心点在经度0。 然后将地球仪(围绕3-D y 轴)倾斜至 把中心点移到 lat,long = [0,0]。 在 lat 的地球点上,long = [0,0]是 离两极最远,有一个拉特,长 围绕它们的网格是最正交的 所以你可以用这些新的“南北”“东西” 直线作为坐标 x,y 直线而不引起 本来会发生的拉伸 在旋转中心点远离极点之前。 显示一个明确的例子将需要更多的空间。

为什么限制在一度?

这个公式是基于以下比例得出的:

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

假设给你一个纬度角和一个经度角,都是以度数表示的: (longitude[deg], latitude[deg])

对于 纬度max circumference总是传给极点。在半径为 R (米)的球形模型中,最大周长为 2 * pi * R,比例分解为:

latitude[m] = ( 2 * pi * R[m] * latitude[deg] ) / 360[deg]

(注意 deg 和 deg 简化了,剩下的是两边的米)。

对于 经度max circumference与纬度的余弦成正比(正如你可以想象的那样,绕圈跑的话,北极比绕赤道跑的时候短) ,所以它是 2 * pi * R * cos(latitude[rad])。 因此

longitude distance[m] = ( 2 * pi * R[m] * cos(latitude[rad]) * longitude[deg] ) / 360[deg]

注意,在计算 cos. 之前,必须将纬度从 deg 转换为 rad。


省略了谁只是在寻找公式的细节:

lat_in_m = 111132.954 * lat_in_degree / 360
lon_in_m = 111132.954 * cos(lat_in_radians) * lon_in_deg ) / 360