【问题标题】:If I am here and heading towards there and I've covered this much ground, where am I?如果我在这里并朝着那里前进并且我已经覆盖了这么多领域,那么我在哪里?
【发布时间】:2008-11-12 04:32:30
【问题描述】:

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

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 的回答。)

【问题讨论】:

  • 这可能是一个家庭作业问题吗?
  • 中间的某个地方?
  • @jacko 不,这不是作业问题。 :) 虽然我不介意回到学校。
  • 糟糕。我(显然)错了,我很高兴你注意到了。我已经删除了我的答案。
  • @carrier:我很好奇最终的解决方案。你让它工作了吗?

标签: great-circle dead-reckoning


【解决方案1】:

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

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

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

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


要构建一个大圆圈,您需要将这些点转换为 3D 笛卡尔坐标(我将省略这一步,但对于球形地球来说这很简单,并且对于 wGS-84 的扁地球模型迭代发现) .

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

b为单位向量指向 在距离中心的终点 地球。

r为地球的半径。

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

构造垂直于 G.C. 的单位向量。平面通过取单位向量 ab 的叉积。也就是说,让 n = a x b

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

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

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

祝你好运!

【讨论】:

    【解决方案2】:

    关于您更新的问题:

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

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

    【讨论】:

      【解决方案3】:

      这里有一些示例代码应该可以解决问题。该算法适用于所有情况,并且始终遵循两个位置之间的最短大圆路径。数学与 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

      【讨论】:

        【解决方案4】:

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

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

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

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

        编辑:变得更糟

        考虑北半球的以下两点:

        • current_location:纬度 = 80,经度 = 0
        • target_location:纬度 = 80,经度 = 180

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

        【讨论】:

        • 感谢您的输入。你提出了一个有效的观点。不过,我已经有了处理这个问题的策略,我只是不想弄乱示例代码,以便将重点放在我需要帮助的问题上。
        • 很公平。为了回答原始问题,我发布了一个带有一些示例代码的新答案。希望对您有所帮助!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-28
        • 1970-01-01
        • 1970-01-01
        • 2016-03-03
        相关资源
        最近更新 更多