当经度>时,Python lat / long中点计算给出错误的结果。 90

时间:2011-05-05 10:00:31

标签: python latitude-longitude

当给定每端点的纬度和经度时,我有一个短函数来计算线的中点。简单来说,当经度大于-90度或小于90度时,它可以正常工作。对于地球的另一半,它提供了一些随机的结果。

该代码是http://www.movable-type.co.uk/scripts/latlong.html提供的javascript的python转换,似乎符合更正的版本herehere。与两个stackoverflow版本进行比较时,我承认我不用C#或Java编写代码,但我无法发现我的错误。

代码如下:

#!/usr/bin/python

import math

def midpoint(p1, p2):
   lat1, lat2 = math.radians(p1[0]), math.radians(p2[0])
   lon1, lon2 = math.radians(p1[1]), math.radians(p2[1])
   dlon = lon2 - lon1
   dx = math.cos(lat2) * math.cos(dlon)
   dy = math.cos(lat2) * math.sin(dlon)
   lat3 = math.atan2(math.sin(lat1) + math.sin(lat2), math.sqrt((math.cos(lat1) + dx) * (math.cos(lat1) + dx) + dy * dy))
   lon3 = lon1 + math.atan2(dy, math.cos(lat1) + dx)
   return(math.degrees(lat3), math.degrees(lon3))

p1 = (6.4, 45)
p2 = (7.3, 43.5)
print "Correct:", midpoint(p1, p2)

p1 = (95.5,41.4)
p2 = (96.3,41.8)
print "Wrong:", midpoint(p1, p2)

有什么建议吗?

3 个答案:

答案 0 :(得分:4)

将您的arg设置代码替换为:

lat1, lon1 = p1
lat2, lon2 = p2
assert -90 <= lat1 <= 90
assert -90 <= lat2 <= 90
assert -180 <= lon1 <= 180
assert -180 <= lon2 <= 180
lat1, lon1, lat2, lon2 = map(math.radians, (lat1, lon1, lat2, lon2))

再次运行您的代码。

更新关于纬度/经度计算的一些有希望的一般性建议:

  1. 以度或弧度输入lat / lon?
  2. 检查输入lat / lon的有效范围
  3. 检查OUTPUT lat / lon的有效范围。经度在国际日期线上有不连续性。
  4. 中点例程的最后一部分可以有效地改变,以避免长途使用的潜在问题:

    lon3 = lon1 + math.atan2(dy, math.cos(lat1) + dx)
    # replacement code follows:
    lon3d = math.degrees(lon3)
    if lon3d < -180:
        print "oops1", lon3d
        lon3d += 360
    elif lon3d > 180:
        print "oops2", lon3d
        lon3d -= 360
    return(math.degrees(lat3), lon3d)
    

    例如,找到奥克兰,新西兰(-36.9,174.8)和帕皮提,大溪地(-17.5,-149.5)之间的中点,在获得有效答案oops2 194.270430902 <的途中产生(-28.355951246746923, -165.72956909809082) / p>

答案 1 :(得分:1)

首先,道歉,我要留下另一个答案。我对该答案中提到的问题有一个解决方案,涉及如何找到日期线两侧的两点的中点。我想简单地在现有答案中添加评论,但我没有这样做的声誉。

通过查看http://www.movable-type.co.uk/scripts/latlong.html处为该工具提供支持的Javascript文件,找到了该解决方案。我正在使用shapely.geometry.Point。如果你不想安装这个软件包,那么使用元组代码就可以了。

def midpoint(pointA, pointB):
    lonA = math.radians(pointA.x)
    lonB = math.radians(pointB.x)
    latA = math.radians(pointA.y)
    latB = math.radians(pointB.y)

    dLon = lonB - lonA

    Bx = math.cos(latB) * math.cos(dLon)
    By = math.cos(latB) * math.sin(dLon)

    latC = math.atan2(math.sin(latA) + math.sin(latB),
                  math.sqrt((math.cos(latA) + Bx) * (math.cos(latA) + Bx) + By * By))
    lonC = lonA + math.atan2(By, math.cos(latA) + Bx)
    lonC = (lonC + 3 * math.pi) % (2 * math.pi) - math.pi

    return Point(math.degrees(lonC), math.degrees(latC))

我希望这是有帮助的,不应被视为不恰当的看法,因为它是对前一个答案中提出的问题的回答。

答案 2 :(得分:0)

  

不能直接回答&gt; 90问题,但它在我的情况下有所帮助,所以我把它留在这里以防它可以帮助其他人。

我只需要将中点放在带有纬度的地图中,长度为度。我没有使用转换为弧度,并且通过使用简单的欧几里德距离在地图中正确地描绘了它。示例功能:

def midpoint_euclidean(x1,y1,x2,y2):
    dist_x = abs(x1-x2) / 2.
    dist_y = abs(y1-y2) / 2.
    res_x = x1 - dist_x if x1 > x2 else x2 - dist_x
    res_y = y1 - dist_y if y1 > y2 else y2 - dist_y
    return res_x, res_y