Если я нахожусь здесь и направляюсь туда, и я прошел через это много, где я? - PullRequest
2 голосов
/ 12 ноября 2008

Мне нужна помощь в написании следующего метода:

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

где все местоположения (широта, длинна)

Я понимаю, что существуют разные модели Земли (WGS-84, GRS-80, ...), которые учитывают тот факт, что Земля является эллипсоидом. Для моих целей этот уровень точности не нужен, если предположить, что идеальная сфера достаточно хороша.

UPDATE

Я хорошо настраиваю свой вопрос, принимая во внимание некоторые ответы.

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

Если бы я следовал по этому пути, я бы пошел по большому кругу, по прямой линии ... или я был бы совершенно не в себе? (Я знаю эти термины сейчас из-за ответа Дрю Холла.)

Ответы [ 5 ]

3 голосов
/ 12 ноября 2008

Как сказал БенджиСмит, потенциально есть несколько путей, которые соединяют любые A & B на земном шаре, но два самых популярных (безусловно!) - это пути "большого круга" и "прямой линии".

Большой круг дает кратчайшее расстояние (путем построения плоскости из двух точек & центра Земли и следуя дуге окружности в этой плоскости).

Прямая линия поддерживает постоянный курс, торгуя на некотором расстоянии (может быть экстремальным в высоких широтах) для простоты использования. То есть в лодке или самолете вы просто указываете на желаемый курс и идете, пока не достигнете своего пункта назначения (тогда как при большом круге курс постоянно меняется). В средних широтах штраф за расстояние не слишком строг.

Имейте в виду, что при работе с антиподальными точками (точки противоположные друг другу на сфере) оба типа путей имеют разрывы с полюсами и неоднозначности.


Чтобы построить большой круг, вам нужно преобразовать точки в трехмерные декартовы координаты (я опущу этот шаг, но для сферической земли он тривиален и найден итеративно для модели сплюснутой земли в виде WGS-84) .

Пусть a будет указывать единичный вектор в начальной точке от центра Земля.

Пусть b будет указывать единичный вектор в конечной точке от центра земля.

Пусть r - радиус Земли.

Пусть d будет (заданным) расстоянием путешествовала.

Построить единичный вектор, нормальный к G.C. плоскость, взяв перекрестное произведение единичных векторов a и b . То есть пусть n = a x b .

(заданное) пройденное расстояние - это длина дуги, образованной сметанием вектора * r *** a ** вокруг n на некоторый угол theta . Вспоминая, что длина окружности полного большого круга равна 2 * пи * г , мы находим тета = д / г .

Таким образом, декартова точка, соответствующая новому местоположению, определяется вращением * r *** a ** вокруг n на тета радиан. Преобразуйте эту декартову точку в лат / долготу, и все готово.

Я не буду выводить здесь математику прямой линии, но скажу, что у проекции карты Меркатора есть свойство прямой линии прямой линии. Вы можете легко построить прямую линию с помощью формулы проекции Меркатора, но вам придется определить некоторую погрешность, чтобы разбить путь на короткие прямые отрезки.

Удачи!

2 голосов
/ 14 ноября 2008

Вот пример кода, который должен помочь. Алгоритм работает для всех случаев и всегда следует по кратчайшему пути большого круга между двумя точками. Математика по существу идентична ответу Дрю Холла, но использует процент_путешествия и игнорирует радиус Земли.

Для простоты в этом коде предполагается, что широта и долгота хранятся в радианах.

<code>def get_new_location(current_location, target_location, percent_traveled):<br>
    # 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
функция для перевода из широты и долготы в декартовые кооридинаты:
<code>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
функция для преобразования из декартовых кооридинатов в широту и долготу:
<code>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
функция для вычисления скалярного произведения двух векторов:
<code>def vector_dot_product(A, B):
    dot_product = A.x*B.x + A.y*B.y + A.z*B.z
    return dot_product
функция для вычисления перекрестного произведения двух векторов:
<code>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
функция для умножения вектора на скаляр:
<code>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
Функция для вычисления суммы двух векторов:
<code>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
2 голосов
/ 12 ноября 2008

По поводу вашего обновленного вопроса:

То, что вы, похоже, делаете, это линейная интерполяция координат широты / долготы. Это верный путь, но это не большой круг или прямолинейная линия. Фактически, поскольку меридианы сходятся по мере увеличения широты (по крайней мере, в северном полушарии), плавная интерполяция в широтном смысле может привести к странно ускоряющемуся пути на земле.

Если бы вы описывали интерполяцию в декартовых координатах, вы бы, по крайней мере, двигались в правильной плоскости, но путь прорезал бы поверхность Земли (т.е. это был бы аккорд на большом круге, а не дуга).

0 голосов
/ 13 ноября 2008

Ваш обновленный пример кода не всегда будет следовать по правильному пути.

Для быстрого примера рассмотрим следующие две точки на экваторе в середине Тихого океана:

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

Эти две точки расположены очень близко друг к другу (на расстоянии всего двух градусов долготы), но когда процент_путешествия равен 0,5, значение new_location будет равно: lat = 0, lon = 0, то есть точка на противоположной стороне земного шара.

изменить: становится хуже

Рассмотрим следующие две точки в северном полушарии:

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

Траектория большого круга между этими двумя точками проходит непосредственно над северным полюсом, но new_location будет перемещаться вокруг земного шара, оставаясь параллельным экватору.

0 голосов
/ 12 ноября 2008

Вот онлайн-калькулятор , чтобы найти расстояние по кругу от долготы и широты. Все вычисления выполняются в клиентском JavaScript, поэтому вы можете просмотреть исходный код страницы, чтобы увидеть код. Кроме того, вот страница , выводящая уравнения , используемые в калькуляторе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...