使用Python将纬度和经度转换为X和Y网格系统

9
我有一个包含纬度和经度值的文件,我想将x和y转换为公里,并测量每个点之间的距离。
例如,我将第一个纬度和经度点(分别为51.58,-124.6)设置为(0,0),因此我想找出其他点及其相对于原点的位置,以便查找51.56(lat)-123.64(long)在(x,y)中的距离(km),以及文件中其余部分的距离。
我想在Python中完成所有这些操作,是否有相应的代码?
我找到了一些在线网站,例如:

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

它正好做我想做的事情,只是我不知道他们是如何做到的。


你应该意识到地球是一个球体,因此没有通用解决方案来解决你的问题(换句话说,世界不能被映射到二维表面而不进行一些近似/扭曲)。你可以在http://www.movable-type.co.uk/scripts/latlong.html找到所需的公式。 - Floris
如果你想尝试自己解决问题,那么应该开始编码,并在你有明确且具体的问题时再回来。如果你只想要现成的答案,那么这可能不是寻找答案的网站。 - Mark Reed
@Floris 技术上是一个扁球体,但你的观点依然正确 :) - dabhaid
1
该网站使用HTML和js编写,您能将其翻译成Python吗? - Noelkd
@Floris 在这种情况下,我假设与我的数据对应的特定位置是平坦的,仅用于将纬度、经度转换为x和y。 - learner
6个回答

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)));
   }
}

在我看来,他们实际上考虑到了地球不完全是一个球体的事实......但即便如此,在你做出这个假设并将地球的一部分视为平面时,你仍然会有一些误差。我相信使用他们的公式可以减小这些误差...


为什么需要乘以40000? - learner
@learner 可能是因为地球的赤道周长为40075.017公里,而子午线周长为40007.86公里。 - Virgiliu
1
@yoshi 确实 - 我在我的回答中也这样说了。我似乎记得有一段时间米的定义是极地周长的1/40000000。 - Floris
我不得不将 lon2-lon1 更改为 lon1-lon2 才能得到正确的结果。美国人省略他们经度的负数吗? - R2-D2
@R2-D2 看起来像是我的笔误...显然 dxdy 的顺序应该相同! - Floris

4

UTM(通用横轴墨卡托投影)投影是以米为单位的。所以您可以使用此链接中的 utm 库:

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

通过搜索Python的经纬度转UTM,您可以找到几个选项。

UTM分区每 6 度经度为一带,从本初子午线 0 度开始。每个UTM带的原点位于赤道上(x轴),y轴位于最西端的经度。这使得网格朝北和东方为正。您可以从这些结果计算距离。数值在UTM带的中央最准确。

您还应该知道原始经纬度值基于什么基准面,并在转换过程中使用相同的基准面。


3

如果您使用3D系统,这些功能将会实现:

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://dev59.com/LnM_5IYBdhLWcg3w4nfb#1185413
    phi = math.atan2(y,x)
    lat = math.degrees(theta)
    lon = math.degrees(phi)
    return [lat,lon]

2
您可以使用大圆距离公式获取GPS点之间的距离。纬度和经度位于一个大地测量坐标系中,因此不能仅将其转换为平面二维网格并使用欧几里得距离。您可以通过将足够接近的点转换为近似网格来在平面上相对于彼此绘制点,方法是取一个任意点(如您的(X,Y)),将其设置为原点(就像您所做的那样),然后使用大圆距离以及方位角,但这只是一个近似值。


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)

0
import pyproj

P = pyproj.Proj(proj='utm', zone=32, ellps='WGS84', preserve_units=True) # You can modify your zone

XY=P(your_long, your_lat)

虽然这段代码可能回答了问题,但我建议您还要提供一下您的代码是如何解决问题的以及它是如何工作的。带有解释的答案通常更有帮助、质量更高,并且更有可能吸引赞同。 - undefined

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