如何将经纬度转换为x和y坐标系统?

9 投票
6 回答
42637 浏览
提问于 2025-04-18 12:23

我有一个文件,里面有一些经纬度的数值,我想用Python把这些经纬度转换成以公里为单位的x和y坐标。我想测量每个点之间的距离。

比如说,我把第一个经纬度点(51.58, -124.6)设定为我的坐标系中的(0,0)。接下来,我想找出其他点相对于这个原点的位置。比如,我想知道经纬度为51.56(纬度)和-123.64(经度)的点在(x,y)坐标系中对应的值,以公里为单位,依此类推处理文件中的其他点。

我想用Python来完成这个任务,有没有什么代码可以参考?

我在网上找到了一些网站,比如这个:

http://www.whoi.edu/marine/ndsf/cgi-bin/NDSFutility.cgi?form=0&from=LatLon&to=XY

这个网站正好可以做到我想做的事情,只是我不知道他们是怎么实现的。

6 个回答

0

你可以使用UTM:

pip install utm

这里有一个例子:

>>> import utm
>>> utm.from_latlon(51.2, 7.5)
(395201.3103811303, 5673135.241182375, 32, 'U')

返回的结果格式是 (东坐标, 北坐标, 区域编号, 区域字母)

注意事项

它也可以和NumPy数组一起使用:

>>> utm.from_latlon(np.array([51.2, 49.0]), np.array([7.5, 8.4]))
(array([395201.31038113, 456114.59586214]),
 array([5673135.24118237, 5427629.20426126]),
 32,
 'U')

而且可以反向操作:

>>> utm.to_latlon(340000, 5710000, 32, 'U')
(51.51852098408468, 6.693872395145327)
2

你可以通过大圆距离公式来计算GPS点之间的距离。纬度和经度是用一种叫做大地坐标系统的方式表示的,所以你不能简单地把它们转换成平面的2D网格,然后用普通的直线距离来计算。你可以把足够近的点转换成一个大致的网格,方法是选择一个任意的点,比如你的(X,Y),把它当作原点(就像你做的那样),然后结合大圆距离和方位角来在平面上绘制这些点之间的关系,但这只是一个近似值。

3

如果你要使用一个三维系统,这些函数会起到以下作用:

def arc_to_deg(arc):
    """convert spherical arc length [m] to great circle distance [deg]"""
    return float(arc)/6371/1000 * 180/math.pi

def deg_to_arc(deg):
    """convert great circle distance [deg] to spherical arc length [m]"""
    return float(deg)*6371*1000 * math.pi/180

def latlon_to_xyz(lat,lon):
    """Convert angluar to cartesian coordiantes

    latitude is the 90deg - zenith angle in range [-90;90]
    lonitude is the azimuthal angle in range [-180;180] 
    """
    r = 6371 # https://en.wikipedia.org/wiki/Earth_radius
    theta = math.pi/2 - math.radians(lat) 
    phi = math.radians(lon)
    x = r * math.sin(theta) * math.cos(phi) # bronstein (3.381a)
    y = r * math.sin(theta) * math.sin(phi)
    z = r * math.cos(theta)
    return [x,y,z]

def xyz_to_latlon (x,y,z):
    """Convert cartesian to angular lat/lon coordiantes"""
    r = math.sqrt(x**2 + y**2 + z**2)
    theta = math.asin(z/r) # https://stackoverflow.com/a/1185413/4933053
    phi = math.atan2(y,x)
    lat = math.degrees(theta)
    lon = math.degrees(phi)
    return [lat,lon]
4

UTM投影是以米为单位的。所以你可以使用这个链接中的utm库:

https://pypi.python.org/pypi/utm

如果你在网上搜索“python 纬度 经度 转 UTM”,会找到好几个选项。

UTM区域的宽度是6度经度,从本初子午线的0度开始。每个UTM区域的起点在赤道(x轴),而y轴则在最西边的经度上。这使得坐标网格向北和向东都是正值。你可以根据这些结果计算你的距离。数值在UTM区域的中间位置最准确。

你还需要知道你原始的纬度和经度值是基于哪个基准面,并在转换时使用相同的基准面。

13

下面的内容可以让你接近答案(结果以公里为单位)。如果你想要更精确的结果,就需要在数学上多花点功夫,比如可以参考一些给出的链接。

import math
dx = (lon1-lon2)*40000*math.cos((lat1+lat2)*math.pi/360)/360
dy = (lat1-lat2)*40000/360

变量名应该很明显。这段代码会给你

dx = 66.299 km (your link gives 66.577)
dy = 2.222 km (link gives 2.225)

一旦你选择了坐标(比如 lon1, lat1)作为起点,计算其他的XY坐标应该就很简单了。

需要注意的是,40,000这个数字是地球的周长,单位是公里(从极地测量)。这个计算能让你接近真实值。如果你查看你提供的链接的源代码(你可能需要多找找才能找到那个在单独文件中的javascript),你会发现他们使用了一个更复杂的公式:

function METERS_DEGLON(x)
{  
   with (Math)
   {
      var d2r=DEG_TO_RADIANS(x);
      return((111415.13 * cos(d2r))- (94.55 * cos(3.0*d2r)) + (0.12 * cos(5.0*d2r)));
   }
}

function METERS_DEGLAT(x)
{
   with (Math)
   {
      var d2r=DEG_TO_RADIANS(x);
      return(111132.09 - (566.05 * cos(2.0*d2r))+ (1.20 * cos(4.0*d2r)) - (0.002 * cos(6.0*d2r)));
   }
}

我觉得他们实际上考虑到了地球并不是一个完美的球体……不过即使如此,当你假设地球的某一部分可以看作平面时,还是会有一些误差。我相信他们的公式能让误差更小……

撰写回答