Найти расстояние между точками и линией и получить проекционное расстояние, которое точка берет на линии - PullRequest
1 голос
/ 17 июня 2019

Я новичок в питоне.Но передо мной стоит сложная задача: у меня есть CSV-файлы с GPS-координатами и 1 файл с эталонной траекторией (точками координат), которые представляют трек транспортного средства.

Таким образом, задача состоит в том, чтобы все точки рассчитали перпендикуляррасстояние до эталонной траектории и определить, в каком километре эта точка находится на эталонной траектории

The task looks like this

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

Таким образом, данные эталонной траектории выглядят так:

    datetime            lon_deg     lat_deg     ki1ometers  
0   27.03.2018 15:07    14.34559621 48.28282695 0   
1   27.03.2018 15:07    14.34539589 48.283579   0.08492765648897423 
2   27.03.2018 15:08    14.34509878 48.28437137 0.17573647034625345 
3   27.03.2018 15:08    14.34476681 48.28520735 0.2718837851891085  
4   27.03.2018 15:09    14.34440297 48.28607467 0.372012272777317   
5   27.03.2018 15:10    14.34355387 48.28785601 0.5798125761498747  
6   27.03.2018 15:10    14.34312139 48.28876254 0.6855708866782635  
7   27.03.2018 15:11    14.34267986 48.28966368 0.7909635418697577  
8   27.03.2018 15:11    14.34235909 48.29057934 0.895509507334529   
9   27.03.2018 15:12    14.34193015 48.29147634 1.000178064181187   
10  27.03.2018 15:12    14.34158939 48.2923968  1.1055875957864745  
11  27.03.2018 15:13    14.34125444 48.29332421 1.2116463089787737  
12  27.03.2018 15:13    14.34084938 48.29424082 1.31788253222638    
13  27.03.2018 15:14    14.34041673 48.29515665 1.4246295164890292  
14  27.03.2018 15:14    14.34001362 48.29608703 1.532295241219843   
15  27.03.2018 15:15    14.33959522 48.29702238 1.6408091272201002  
16  27.03.2018 15:15    14.33917898 48.29796904 1.7504838454702525  
17  27.03.2018 15:16    14.33875624 48.29892358 1.8611345768980705  
18  27.03.2018 15:16    14.33832484 48.29988211 1.9723928345544686  
19  27.03.2018 15:17    14.337844699999998  48.30083163 2.083788039109954   
20  27.03.2018 15:17    14.33733187 48.30177414 2.1952441083077696  
21  27.03.2018 15:18    14.33680756 48.30271439 2.3067561380904458  
22  27.03.2018 15:18    14.33637327 48.30366977 2.4177398933361665  
23  27.03.2018 15:19    14.33579109 48.30456609 2.5263104564169723  

И данные, которые мне нужны для расчета расстояния и положения на моей эталонной траектории:

datetime                lon_deg             lat_deg
2018-01-29 00:00:00.000 13.535165989333333  48.58077572716667
29.01.2018 0:00         13.535166009        48.580775726166664
2018-01-29 00:00:01.000 13.535165977166667  48.580775749
29.01.2018 0:00         13.5351658175       48.58077575
2018-01-29 00:00:02.000 13.535165976833333  48.58077567466667
29.01.2018 0:00         13.535165988166666  48.58077563316667
2018-01-29 00:00:03.000 13.535165978333334  48.580775599
29.01.2018 0:00         13.535166127833334  48.5807756575
2018-01-29 00:00:04.000 13.535166430833334  48.5807757935
29.01.2018 0:00         13.535166510166666  48.580775819
2018-01-29 00:00:05.000 13.5351665845       48.5807758835
29.01.2018 0:00         13.5351665215       48.580775906
2018-01-29 00:00:06.000 13.535166549166666  48.58077594583333
29.01.2018 0:00         13.535166521333334  48.58077594466667
2018-01-29 00:00:07.000 13.535166487        48.580775927666664
29.01.2018 0:00         13.5351670905       48.58077611433333
2018-01-29 00:00:08.000 13.5351669075       48.5807760195
29.01.2018 0:00         13.535166444166666  48.580775919

Таким образом, ожидаемый результат - это рассчитанное расстояние до траектории линии и в каком конкретном километре траектории эта точка есть.

Я был бы рад услышать любые идеи, потому что я действительно застрял в этой проблеме

1 Ответ

0 голосов
/ 17 июня 2019

В случае таких небольших расстояний (например, расстояние в 2,5 км) вы, вероятно, можете жить в плоском приближении и использовать очень простые вещи: для расстояния вы можете использовать формулы для расчета высоты треугольника, напримерработа с полупериметром .Тогда вам все равно придется вычислять, находится ли точка «в» заданном отрезке (часть построенной на нем перпендикулярной полосы), где вы можете использовать свойство проекции скалярного (точечного) произведения векторов.

Таким образом, для отрезка AB и точки C (все точки являются кортежами / списками) вам потребуется что-то вроде этого:

pdist=lambda A,B:((A[0]-B[0])**2+(A[1]-B[1])**2)**(1/2)

def dist(A,B,C):
  c=pdist(A,B)
  rat=((C[0]-A[0])*(B[0]-A[0])+(C[1]-A[1])*(B[1]-A[1]))/c/c
  if rat<0 or rat>1:
    return None,None
  a=pdist(B,C)
  b=pdist(A,C)
  s=(a+b+c)/2
  alt=2*(s*(s-a)*(s-b)*(s-c))**(1/2)/c
  return alt,rat

Возвращает None,None, еслиПерпендикулярная базовая точка для C находится за пределами AB, или кортеж перпендикулярного расстояния (от C до сегмента AB) и отношения между 0 ... 1, которое вы можете использовать в качестве веса для расчета "положения путешествия" между двумя соседними точками.

Затем выполняется анализ данных вашего примера:

import re
rawtour='''0   27.03.2018 15:07    14.34559621 48.28282695 0   
1   27.03.2018 15:07    14.34539589 48.283579   0.08492765648897423 
2   27.03.2018 15:08    14.34509878 48.28437137 0.17573647034625345 
3   27.03.2018 15:08    14.34476681 48.28520735 0.2718837851891085  
4   27.03.2018 15:09    14.34440297 48.28607467 0.372012272777317   
5   27.03.2018 15:10    14.34355387 48.28785601 0.5798125761498747  
6   27.03.2018 15:10    14.34312139 48.28876254 0.6855708866782635  
7   27.03.2018 15:11    14.34267986 48.28966368 0.7909635418697577  
8   27.03.2018 15:11    14.34235909 48.29057934 0.895509507334529   
9   27.03.2018 15:12    14.34193015 48.29147634 1.000178064181187   
10  27.03.2018 15:12    14.34158939 48.2923968  1.1055875957864745  
11  27.03.2018 15:13    14.34125444 48.29332421 1.2116463089787737  
12  27.03.2018 15:13    14.34084938 48.29424082 1.31788253222638    
13  27.03.2018 15:14    14.34041673 48.29515665 1.4246295164890292  
14  27.03.2018 15:14    14.34001362 48.29608703 1.532295241219843   
15  27.03.2018 15:15    14.33959522 48.29702238 1.6408091272201002  
16  27.03.2018 15:15    14.33917898 48.29796904 1.7504838454702525  
17  27.03.2018 15:16    14.33875624 48.29892358 1.8611345768980705  
18  27.03.2018 15:16    14.33832484 48.29988211 1.9723928345544686  
19  27.03.2018 15:17    14.337844699999998  48.30083163 2.083788039109954   
20  27.03.2018 15:17    14.33733187 48.30177414 2.1952441083077696  
21  27.03.2018 15:18    14.33680756 48.30271439 2.3067561380904458  
22  27.03.2018 15:18    14.33637327 48.30366977 2.4177398933361665  
23  27.03.2018 15:19    14.33579109 48.30456609 2.5263104564169723  '''
tour=list(map(lambda line:list(map(lambda x:float(x),re.match(r'[^\s]+\s+[^\s]+\s+[^\s]+\s+([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)\s*',line).groups())),rawtour.split('\n')))
rawmarks='''2018-01-29 00:00:00.000 13.535165989333333  48.58077572716667
29.01.2018 0:00         13.535166009        48.580775726166664
2018-01-29 00:00:01.000 13.535165977166667  48.580775749
29.01.2018 0:00         13.5351658175       48.58077575
2018-01-29 00:00:02.000 13.535165976833333  48.58077567466667
29.01.2018 0:00         13.535165988166666  48.58077563316667
2018-01-29 00:00:03.000 13.535165978333334  48.580775599
29.01.2018 0:00         13.535166127833334  48.5807756575
2018-01-29 00:00:04.000 13.535166430833334  48.5807757935
29.01.2018 0:00         13.535166510166666  48.580775819
2018-01-29 00:00:05.000 13.5351665845       48.5807758835
29.01.2018 0:00         13.5351665215       48.580775906
2018-01-29 00:00:06.000 13.535166549166666  48.58077594583333
29.01.2018 0:00         13.535166521333334  48.58077594466667
2018-01-29 00:00:07.000 13.535166487        48.580775927666664
29.01.2018 0:00         13.5351670905       48.58077611433333
2018-01-29 00:00:08.000 13.5351669075       48.5807760195
29.01.2018 0:00         13.535166444166666  48.580775919'''
marks=list(map(lambda line:list(map(lambda x:float(x),re.match(r'[^\s]+\s+[^\s]+\s+([\d\.]+)\s+([\d\.]+)\s*',line).groups())),rawmarks.split('\n')))

И [[dist(A,B,C) for A,B in zip(tour,tour[1:])] for C in marks] создает матрицу расстояний, которая в этом случае совершенно пуста, так как два набора координат слишком далеко связаны сузкие перпендикулярные полосы построены на отрезках линии.Один градус долготы составляет около 111 км-с на широте ~ 48 градусов.В то время как длина всего примера составляет всего 2,5 км.

Для ускорения объекта можно использовать https://docs.python.org/3/library/functools.html#functools.lru_cache на pdist или c -s (длина сегментов тура) может быть явно предварительно вычислен и сохранен где-то, деление /c/c может быть отложено, а temprat<0 or temprat>c**2 может быть использовано в if, где c**2 также может быть рассчитано заранее.Просто я потерял мотивацию, когда заметил проблему с расстоянием.


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

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

Для того, чтобы заставить его работать с широтными координатами, существует множество жутких формул, я быНе смей выбирать один для тебя на данный момент.https://en.wikipedia.org/wiki/Geographical_distance может быть хорошей отправной точкой.Одним из ярлыков, на который вы можете положиться, является то, что ваши траектории содержат расстояния в км-с, поэтому вы можете рассчитать расстояние в пути для точки в сегменте как взвешенную сумму расстояний в пути в его конечных точках (вместо того, чтобы вычислять расстояния непосредственно от широты).координаты)

...