I am new in python. But I have a challenging task for me: I have CSV files with GPS coordinates and 1 file with reference trajectory (coordinates points) which represent the track of the vehicle.
So the task is to all points calculate the perpendicular distance to reference trajectory and define in which kilometer this point is in the reference trajectory
I was trying to solve it with QGIS but the problem is that it is too much data and QGIS all the time crashed. I was using the distance matrix.
So the reference trajectory data looks like this:
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
And the data that I need to calculate distance and position on my reference trajectory:
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
So the output I expect is calculated distance to the line trajectory and in which specific kilometer of trajectory this point is.
I would be happy to hear any ideas because I really stuck in this problem
In case of such small distances (like a trip of 2.5 km), you can probably live with a planar approximation and use very simple stuff: for the distance you can use formulas for calculating the height of a triangle, like the one working with semiperimeter . Then you will still have to calculate if the point is "in" the given line segment (part of the perpendicular strip built on it), where you can use the projection property of scalar (dot) product of vectors.
So for a line-segment AB, and a point C (all points are tuples/lists) you would need something like this:
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
It returns None,None
if the perpendicular base point for C is outside AB, or a tuple of perpendicular distance (of C from AB segment) and a ratio between 0...1 which you can use as weight for calculating "tour-position" between the two neighboring points.
Then some parsing on your example data:
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')))
And [[dist(A,B,C) for A,B in zip(tour,tour[1:])] for C in marks]
produces the distance matrix, which is totally empty in this case as the two coordinate sets are too far away related to the narrow perpendicular strips built on the line segments. One degree of longitude is around 111 km-s at latitude ~48 degrees. While the entire example tour is only 2.5 km long.
For speeding up the thing, https://docs.python.org/3/library/functools.html#functools.lru_cache could be used on pdist
, or the c
-s (length of tour-segments) could be explicitly pre-calculated and stored somewhere, the /c/c
division could be postponed and temprat<0 or temprat>c**2
could be used in the if
, where c**2
could be pre-calculated too. Just I lost motivation when noticed the distance issue.
However the lower part of the image is meant to illustrate that point-point distances can not be used as replacement, and it can not even really "drive" the orthogonal calculations either, as the red point being the closest corner-point to the blue one does not mean that a segment could not be closer, and the red one is not even an endpoint of that segment.
For making it work with lat-lon coordinates lots of creepy formulaes exist, I would not dare to choose one for you at the moment. https://en.wikipedia.org/wiki/Geographical_distance may be a good starting point. One shortcut you can rely on is that your trajectories contain distances in km-s, so you can calculate trip-distance of a point in a segment as a weighted sum of the trip-distances at its endpoints (instead of calculating distances directly from lat-lon coordinates).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.