如果我在这里并朝着那里前进并且我已经覆盖了这么多地方,那么我在哪里?

发布于 2024-07-08 22:38:52 字数 1164 浏览 3 评论 0原文

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

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

如果我要走这条路,我会遵循大圆、恒向线……还是会完全偏离? (由于德鲁·霍尔的回答,我现在知道了这些术语。)

I need help writing the following method:

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

where all locations are (lat,long)

I realize that there are different models for the earth (WGS-84, GRS-80, ...) which take into account the fact that the earth is an ellipsoid. For my purposes, this level of precision is not necessary, assuming a perfect sphere is good enough.

UPDATE

I'm fine tuning my question taking into account some of the responses.

benjismith argues that my question cannot be answered because there is more than one shortest path between points on the globe. He has a lot of backing in the form of votes, so I guess there's something I don't understand, because I disagree.

The midpoint between any two locations
on a sphere is a circular arc.

I concede that this is true when two points are at complete opposites. By this I mean that both points, while remaining on the surface of the sphere, could not be any further away from each other. In this case there are infinite number of equidistant paths joining both points. This, however, is an edge case, not the rule. In all other cases, the vast majority of cases, there is a single shortest path.

To illustrate: if you were to hold a string which passed through two points, and pulled it tight, would there not be only one possible path on which the string would settle (except the edge case already discussed)?

Now, prior to asking the question, obtaining the distance between two points and the heading was not a problem.

I guess what I should have asked is if the following is valid:

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

If I were to follow this path, would I be following the great-circle, the rhumb line, ... or would I be completely off?
(I know these terms now because of Drew Hall's answer.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

风吹短裙飘 2024-07-15 22:38:52

正如 BenjiSmith 所说,可能有几条路径连接任何 A 和 A 。 B 在地球仪上,但最受欢迎的两条(到目前为止!)是“大圆”和“恒向线”路径。

大圆给出最短距离(通过从两点和地球中心构建一个平面并遵循该平面中的圆弧)。

恒向线保持恒定的航向,牺牲一定距离(在高纬度地区可能会很远)以方便使用。 也就是说,在船上或飞机上,您只需指向所需的航向并一直行驶,直到到达目的地(而使用大圆圈时,航向会不断变化)。 在中纬度地区,距离损失并不太严重。

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


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

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

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

r为地球半径。

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

通过计算单位向量ab的叉积来构造垂直于GC平面的单位向量。 也就是说,令n = ax b

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

因此,通过围绕 n 旋转 *r***a** theta 弧度即可找到与新位置相对应的笛卡尔点。 将该笛卡尔点转换为纬度/经度和纬度 你完成了。

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

祝你好运!

As BenjiSmith said, there are potentially several paths that connect any A & B on the globe, but the two most popular (by far!) are the "great circle" and "rhumb line" paths.

A great circle gives the shortest distance (by constructing a plane from the two points & the center of the earth & following a circular arc in that plane).

A rhumb line maintains a constant heading, trading some distance (can be extreme at high latitudes) for ease of use. That is, in a boat or plane, you simply point at the desired heading and go until you arrive at your destination (whereas with a great circle the heading changes continuously). In mid latitudes the distance penalty isn't too severe.

Be warned, both path types have discontinuities involving the poles and ambiguities when dealing with antipodal points (pts opposite each other on the sphere).


To build a great circle, you'll want to convert the points to 3D cartesian coordinates (I'll leave this step out but it's trivial for a spherical earth & found iteratively for an oblate earth model a la WGS-84).

Let a be the unit vector pointing
at the start point from the center of
the earth.

Let b be the unit vector pointing
at the end point from the center of
the earth.

Let r be the radius of the earth.

Let d be the (given) distance
traveled.

Construct the unit vector normal to the G.C. plane by taking the cross product of the unit vectors a and b. That is, let n = a x b.

The (given) distance traveled is the length of the arc formed by sweeping the vector *r***a** around n by some angle theta. Recalling that the circumference of the full great circle is 2 * pi * r, we find theta = d/r.

The cartesian point corresponding to the new location is thus found by rotating *r***a** around n by theta radians. Convert that cartesian point to lat/long & you're done.

I won't derive the rhumb line math here, but will say that the Mercator map projection has the property that rhumb lines are straight. You can easily construct a rhumb line with the mercator projection formula, but you'll have to define some error tolerance so you can break the path up into short, straight segments.

Good luck!

猫弦 2024-07-15 22:38:52

关于您更新的问题:

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

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

Regarding your updated question:

What you seem to be doing is a linear interpolation of lat/lon coordinates. This is a valid path, but it's neither the great circle or the rhumb line. In fact, because meridians converge as latitude increases (in the northern hemisphere, at least), a smooth interpolation in the lat/lon sense would result in an oddly accelerating path on the ground.

If you were describing interpolation in cartesian coordinates, you'd at least be moving in the right plane but the path would cut through the surface of the earth (i.e. it'd be a chord on the great circle, rather than an arc).

最好是你 2024-07-15 22:38:52

这是一些应该可以解决问题的示例代码。 该算法适用于所有情况,并且始终遵循两个位置之间的最短大圆路径。 数学本质上与德鲁·霍尔的答案相同,但使用了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

function to convert from latitude and longitude to cartesian co-oridinates:

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

function to convert from cartesian co-oridinates to latitude and longitude:

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

function to compute the dot-product of two vectors:

def vector_dot_product(A, B):
    dot_product = A.x*B.x + A.y*B.y + A.z*B.z
    return dot_product

function to compute the cross-product of two vectors:

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

function to multiply a vector by a scalar:

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

function to compute the sum of two vectors:

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

Here is some sample code that should do the trick. The algorithm works for all cases and always follows the shortest great-circle path between the two locations. The math is essentially identical to Drew Hall's answer, but using percent_traveled and ignoring the radius of the earth.

For the sake of simplicity, this code assumes that latitude and longitude are stored in radians.

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


function to convert from latitude and longitude to cartesian co-oridinates:

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


function to convert from cartesian co-oridinates to latitude and longitude:

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


function to compute the dot-product of two vectors:

def vector_dot_product(A, B):
    dot_product = A.x*B.x + A.y*B.y + A.z*B.z
    return dot_product


function to compute the cross-product of two vectors:

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


function to multiply a vector by a scalar:

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


function to compute the sum of two vectors:

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

满地尘埃落定 2024-07-15 22:38:52

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

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

  • current_location: lat = 0, lon = -179
  • target_location: lat = 0, lon = 179

这两个点非常接近(只有两个点)经度分开),但当percent_traveled为0.5时,new_location将为:lat = 0,lon = 0,这是地球另一侧的点。

编辑:情况变得更糟

考虑北半球的以下两点:

  • current_location: lat = 80, lon = 0
  • target_location: lat = 80, lon = 180

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

Your updated sample code would not always follow the correct path.

For a quick example, consider the following two points on the equator in the middle of the pacific ocean:

  • current_location: lat = 0, lon = -179
  • target_location: lat = 0, lon = 179

These two points are very close together (only two degrees of longitude apart), but when percent_traveled is at 0.5, new_location would be: lat = 0, lon = 0, which is a point on the opposite side of the globe.

edit: it gets worse

Consider the follwing two points in the northern hemisphere:

  • current_location: lat = 80, lon = 0
  • target_location: lat = 80, lon = 180

The great circle path between these two points goes directly over the north pole, but new_location would move around the globe, remaining parallel to the equator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文