Вычисление расстояния между точкой и виртуальной линией двух ширин / широт

14

Пожалуйста, обратитесь к примеру и соответствующему изображению.

Я хотел бы добиться следующего: обеспечить два места (лат / LNG), которые показаны ниже как A и B . Из этого будет проведена виртуальная линия, а затем будет вычислено расстояние между этой линией и C (при любом измерении).

Рисование

Я достиг этого в настоящее время в Google Maps API v3, но хотел бы также иметь возможность выполнять это за кулисами на моем языке по своему выбору. Любые советы / идеи будут с благодарностью!

пленный
источник
Является ли AB линия большого круга ?
Кирк Куйкендалл
@Kirk, нет, АБ - это просто прямая линия
Заключенный
@ Майкл, это интересный момент. Мне придется взглянуть на это!
Заключенный
@Prisoner @Kirk Буквально, прямая линия пройдет под поверхностью земли. В общем, его радиальная проекция обратно на поверхность действительно будет сегментом большого круга (используя модель сферической земли).
whuber
1
@Prisoner Это очень полезная дополнительная информация! Да вы правы. Вы все еще должны компенсировать тот факт, что использование (широта, долгота) дифференциально искажает расстояния восток-запад по сравнению с севером-югом. Как советует @Jose, спроецируйте координаты. Это может быть так же просто, как предварительное умножение долготы на косинус средней широты и затем притворство, что вы находитесь на евклидовой плоскости.
whuber

Ответы:

6
def get_perp( X1, Y1, X2, Y2, X3, Y3):
    """************************************************************************************************ 
    Purpose - X1,Y1,X2,Y2 = Two points representing the ends of the line segment
              X3,Y3 = The offset point 
    'Returns - X4,Y4 = Returns the Point on the line perpendicular to the offset or None if no such
                        point exists
    '************************************************************************************************ """
    XX = X2 - X1 
    YY = Y2 - Y1 
    ShortestLength = ((XX * (X3 - X1)) + (YY * (Y3 - Y1))) / ((XX * XX) + (YY * YY)) 
    X4 = X1 + XX * ShortestLength 
    Y4 = Y1 + YY * ShortestLength
    if X4 < X2 and X4 > X1 and Y4 < Y2 and Y4 > Y1:
        return X4,Y4
    return None

Самая короткая длина - это расстояние, которое вам нужно, если я не ошибаюсь?

волосатый
источник
Да, я ищу кратчайшее расстояние от C до отрезка. Это то, что вычисляет эта математика?
Заключенный
1
Он действительно работал нормально, я прошел три пункта (A, B, C) в следующем: i.imgur.com/bK9oB.jpg и вернулся с широтой / долготой X. Отличная работа!
Заключенный
1
@Hairy, И последнее, как бы я изменил это, чтобы перейти к ближайшей точке (не только к линии), так что, если бы я поставил точку выше точки соединения с линией, как я мог получить ее, чтобы проверить расстояние до точка?
Заключенный
1
@Hairy Хорошее начало, но кажется, что слишком часто этот код возвращается, Noneкогда существует законное решение. Проблема состоит в том, что последнее условие предполагает X1 <X2 и Y1 <Y2, что не всегда может быть гарантировано. Необходим лучший тест на промежуточность.
whuber
1
@Hairy Похоже, что этот обмен между вами и @prisoner был продуктивным. Я хотел бы подчеркнуть, что я не имел никакого отношения (или даже никакого контроля) к каким-либо изменениям в голосовании или пунктам, которые могли произойти, и что мой комментарий был предназначен только для того, чтобы помочь вам улучшить свой ответ.
whuber
11

Может быть, я делаю это слишком сложным, но вам нужно расстояние от точки до прямой. Это расстояние от точки вдоль AB, которая связывает AB с C линией, ортогональной к AB. Этот вектор, перпендикулярный AB, определяется как

v=[x2-x1, -(y2-y1)] # Point A is [x1,y1] Point B is [x2,y2]

(Я использовал квадратные скобки, чтобы определить вектор или массив из двух элементов). Расстояние между C [xp, yp] и точкой A

u=[x1-xp, y1-xp]

Расстояние между линией и C - это просто проекция u на v. Если предположить, что mod (v) = 1 (просто нормализовать его), то

distance = u*v = abs( (x2-x1)*(y1-yp) - (x1-xp)*(y2-y1) )

Единственное осложнение заключается в том, что вы, вероятно, хотите убедиться, что ваши координаты не являются парами WGS84 lat / log, а спроецированы (или используются геодезические координаты). Вы можете использовать OGR или Proj4 для этого.

Хосе
источник
3
Кстати, несколько миллионов псевдоточек за неиспользование тригонометрических функций. Слишком много людей вытаскивают ArcTan, когда они должны смотреть на это: en.wikipedia.org/wiki/Dot_product
Herb
@ Хосе, спасибо за ответ! Я использую lat / long из Google Maps API. Математическая часть довольно нова для меня, поэтому я попробую и посмотрю, что я могу придумать. Какие-нибудь подсказки с математикой? Например, [x2-x1, - (y2-y1)], что это означает?
Заключенный
Я добавил короткую правку для этого. По сути, это запись массива, но если вы храните свои координаты в переменных x1, x2, y1, y2 и xp, yp, вам нужно только написать правую часть последнего уравнения, которое я предоставил. Это в значительной степени действительный код C, Java, JS, Python и т. Д. :)
Jose
1
@Jose Вы вычисляете расстояние от C до линии AB. Исходя из рисунка, я считаю, что ОП хочет расстояние от С до отрезка АВ. Это требует дополнительной работы, чтобы проверить, находится ли проекция C на линию AB между A и B или нет. В последнем случае используйте более короткую из двух длин CA и CB.
whuber
1
@Prisoner Основное отличие состоит в том, что линия продолжается вечно (она определяется только вектором направления и точкой или двумя точками), тогда как отрезок между A и B является битом бесконечной линии, проходящей между A и в (он имеет длину конечное)
Хосе
4

Будучи немного отвращенным ко всей этой математике, я бы подошел к этому с другой стороны. Я бы сделал это «реальной» строкой, а не виртуальной строкой, а затем использовал бы существующие инструменты.

Если A и B имеют общий атрибут, вы можете соединить их, нарисовав линию (в Kosmo GIS есть инструмент, который будет создавать линии из точек, и я считаю, что для этого есть также плагин QGIS). Если у вас есть линии, функция «ближний» на точечном слое «С» даст вам расстояние до линии. Пусть программное обеспечение справится с математикой для вас!

Даррен Коуп
источник
Спасибо за комментарий, но волосатый подошел козыри на этом!
Заключенный
1
(+1) Вы делаете превосходное замечание. Алгоритмы вычислительной геометрии общеизвестно непросто получить полностью правильные результаты на практике (как мы можем видеть из всего предложенного кода, который является полезным и иллюстративным, но еще не полностью работает). Использование высокоуровневой ГИС-процедуры часто является хорошим способом убедиться, что вы получаете ожидаемый ответ и что он правильный (при условии, что вы доверяете своей ГИС ;-).
whuber
1

Если вы использовали Java на Android, это только одна строка с библиотечной функцией

import static com.google.maps.android.PolyUtil.distanceToLine;

distanceToLine:

public static double distanceToLine(LatLng p, LatLng start,LatLng end)

Вычисляет расстояние на сфере между точкой p и отрезком от начала до конца.

Параметры: p - точка для измерения

начало - начало отрезка

конец - конец отрезка

Возвращает: расстояние в метрах (при условии сферической земли)

Просто добавьте библиотеку в свой

dependencies {
    compile 'com.google.maps.android:android-maps-utils:0.5+'
}
инди
источник