2

我需要帮助编写以下方法:

def get_new_location(current_location, target_location, distance_travelled):
    ...
    ...
    return new_location

所有位置都在哪里(纬度,经度)

我意识到地球有不同的模型(WGS-84,GRS-80,...),考虑到地球是椭球体这一事实。就我的目的而言,假设一个完美的球体足够好,这种精度水平是不必要的。

更新

考虑到一些回应,我正在微调我的问题。

benjismith认为我的问题无法回答,因为地球上的点之间有不止一条最短路径。他以选票的形式得到了很多支持,所以我想我有些不明白,因为我不同意。

球体上任意两个位置的中点是圆弧。

我承认当两点完全相反时这是真的。我的意思是这两个点虽然都留在球体的表面上,但彼此之间的距离不能再远了。在这种情况下,有无限数量的等距路径连接两个点。然而,这是一个极端情况,而不是规则。在所有其他情况下,绝大多数情况下,只有一条最短路径。

举例说明:如果你握住一根穿过两点的绳子,并把它拉紧,绳子会不会只有一个可能的路径(除了已经讨论过的边缘情况)?

现在,在问这个问题之前,获得两点和航向之间的距离不是问题。

我想我应该问的是以下是否有效:

def get_new_location(current_location, target_location, percent_traveled):
    new_location.lon = (1-percent_traveled)*current_location.lon+percent_traveled*target_location.lon
    new_location.lat = (1-percent_traveled)*current_location.lat+percent_traveled*target_location.lat
    return new_location

如果我沿着这条路走,我会沿着大圆、恒向线……还是完全偏离?(我现在知道这些术语是因为 Drew Hall 的回答。)

4

4 回答 4

3

正如 BenjiSmith 所说,连接全球任何 A 和 B 的路径可能有好几条,但最流行的两条(到目前为止!)是“大圆”和“恒向线”路径。

一个大圆给出了最短的距离(通过从两点和地球中心构造一个平面并在该平面上沿着圆弧)。

恒向线保持恒定的航向,为了便于使用而交换一些距离(在高纬度地区可能是极端的)。也就是说,在船或飞机上,您只需指向所需的航向并继续前进,直到到达目的地(而大圆圈则航向不断变化)。在中纬度地区,距离惩罚不是太严重。

请注意,两种路径类型在处理对映点(球体上彼此相对的点)时都存在涉及极点和模糊性的不连续性。


要构建一个大圆,您需要将这些点转换为 3D 笛卡尔坐标(我将省略这一步,但这对于球形地球来说是微不足道的,并且对于扁地球模型(如 WGS-84)反复发现)。

a为从地球中心指向起点的单位向量。

b为从地心指向终点的单位向量。

r为地球的半径。

d为(给定的)行驶距离。

通过取单位向量ab的叉积来构造垂直于 GC 平面的单位向量。也就是说,让n = axb

行进的(给定)距离是通过将向量 *r***a** 围绕n扫过某个角度theta形成的弧的长度。回想整个大圆的周长是 2 * pi * r,我们发现theta = d / r

因此,通过将 *r***a** 围绕n旋转theta弧度来找到对应于新位置的笛卡尔点。将该笛卡尔点转换为纬度/经度,您就完成了。

我不会在这里推导恒向线数学,但会说墨卡托地图投影具有恒向线是直的特性。您可以使用墨卡托投影公式轻松构建恒向线,但您必须定义一些误差容限,以便将路径分成短而直的段。

祝你好运!

于 2008-11-12T05:53:19.307 回答
2

关于您更新的问题:

您似乎在做的是纬度/经度坐标的线性插值。这是一条有效的路径,但它既不是大圆也不是恒向线。事实上,由于经线会随着纬度的增加而收敛(至少在北半球),因此在纬度/经度意义上的平滑插值会导致地面上出现奇怪的加速路径。

如果您在笛卡尔坐标中描述插值,那么您至少会在正确的平面上移动,但路径会穿过地球表面(即,它将是大圆上的弦,而不是圆弧)。

于 2008-11-12T20:42:39.683 回答
2

这是一些应该可以解决问题的示例代码。该算法适用于所有情况,并且始终遵循两个位置之间的最短大圆路径。数学与 Drew Hall 的答案基本相同,但使用 percent_traveled 并忽略了地球的半径。

为简单起见,此代码假定纬度和经度以弧度存储。

def get_new_location(current_location, target_location, percent_traveled):
# convert locations into cartiesian co-ordinates current_vector = location_to_vector(current_location) target_vector = location_to_vector(target_location) # compute the angle between current_vector and target_vector complete_angle = acos(vector_dot_product(current_vector, target_vector)) # determine the current partial angle, based on percent_traveled partial_angle = percent_traveled*complete_angle # compute a temporary vector to simplify calculation temporary_vector = vector_cross_product(current_vector, target_vector) temporary_vector = vector_cross_product(current_vector, temporary_vector) # calculate new_vector scalar_one = cos(partial_angle) scalar_two = -sin(partial_angle)/sin(complete_angle) vector_one = vector_multiply_by_scalar(scalar_one, current_vector) vector_two = vector_multiply_by_scalar(scalar_two, temporary_vector) new_vector = vector_sum(vector_one, vector_two) # convert new_vector back into latitude & longitude and return new_location = vector_to_location(new_vector) return new_location
将纬度和经度转换为笛卡尔坐标的函数:
def location_to_vector(location)
    vector.x = cos(location.lat)*sin(location.lon)
    vector.y = sin(location.lat)
    vector.z = cos(location.lat)*cos(location.lon)
    return vector
将笛卡尔坐标转换为纬度和经度的函数:
def vector_to_location(vector)
    location.lat = asin(vector.y)
    if (vector.z == 0):
        if (vector.x < 0):
            location.lon = -pi/2
        else:
            location.lon = pi/2
    else:
        if (vector.z < 0):
            if (vector.x < 0):
                location.lon = atan(vector.x/vector.z) - pi
            else:
                location.lon = pi - atan(-vector.x/vector.z)
        else:
            if (vector.x < 0):
                location.lon = -atan(-vector.x/vector.z)
            else:
                location.lon = atan(vector.x/vector.z)
    return location
计算两个向量的点积的函数:
def vector_dot_product(A, B):
    dot_product = A.x*B.x + A.y*B.y + A.z*B.z
    return dot_product
计算两个向量的叉积的函数:
def vector_cross_product(A, B):
    cross_product.x = A.y*B.z - A.z*B.y
    cross_product.y = A.z*B.x - A.x*B.z
    cross_product.z = A.x*B.y - A.y*B.x
    return cross_product
将向量乘以标量的函数:
def vector_multiply_by_scalar(scalar, vector)
    scaled_vector.x = scalar*vector.x
    scaled_vector.y = scalar*vector.y
    scaled_vector.z = scalar*vector.z
    return scaled_vector
计算两个向量之和的函数:
def vector_sum(A, B)
    sum.x = A.x + B.x
    sum.y = A.y + B.y
    sum.z = A.z + B.z
    return sum

于 2008-11-14T16:35:48.283 回答
-1

您更新的示例代码并不总是遵循正确的路径。

举个简单的例子,考虑太平洋中部赤道上的以下两点:

  • 当前位置:纬度 = 0,经度 = -179
  • 目标位置:纬度 = 0,经度 = 179

这两个点非常靠近(仅相隔两度经度),但当 percent_traveled 为 0.5 时,new_location 将是:lat = 0, lon = 0,即地球另一侧的一个点。

编辑:它变得更糟

考虑北半球的以下两点:

  • 当前位置:纬度 = 80,经度 = 0
  • 目标位置:纬度 = 80,经度 = 180

这两点之间的大圆路径直接越过北极,但 new_location 将全球范围内移动,保持与赤道平行。

于 2008-11-12T23:17:22.367 回答