Straßen und Knoten in OSMnx sind shapely.geometry.LineString
und shapely.geometry.Point
Objekte, so gibt es keine Kurve, nur Sequenz von Koordinaten. Der technische Ausdruck für das, was Sie beschrieben haben, ist Map Matching
. Es gibt verschiedene Arten des Kartenabgleichs. Der einfachste ist der geometrische Kartenabgleich, bei dem Sie die nächstgelegene Geometrie (Knoten oder Kante) zum GPS-Punkt finden. point to point
Kartenabgleich kann leicht mit eingebauter Osmnx-Funktion ox.get_nearest_node()
erreicht werden. Wenn Sie einen Luxus von dichten GPS-Tracks haben, könnte dieser Ansatz einigermaßen gut funktionieren. Für point to line
Kartenabgleich müssen Sie formschöne Funktionen verwenden. Das Problem bei diesem Ansatz ist, dass es sehr langsam ist. Sie können den Algorithmus mit dem räumlichen Index beschleunigen, aber für die meisten Zwecke ist es nicht schnell genug. Beachten Sie, dass die geometrische Kartenanpassung unter allen Ansätzen am wenigsten genau ist. Ich habe vor einigen Wochen eine Funktion geschrieben, die einen einfachen Punkt-zu-Zeile-Kartenabgleich mit der Kante GeoDataFrame und dem Knoten GeoDataFrame durchführt, die Sie von OSMnx erhalten können. Ich habe diese Idee aufgegeben und arbeite jetzt an einem neuen Algorithmus (hoffentlich viel schneller), den ich nach Fertigstellung auf GitHub veröffentlichen werde. In der Zwischenzeit kann dies für Sie oder jemand anderen hilfreich sein, also poste ich es hier. Dies ist eine frühe Version des aufgegebenen Codes, nicht ausreichend getestet und nicht optimiert. Probieren Sie es aus und lassen Sie mich wissen, ob es für Sie funktioniert.
def GeoMM(traj, gdfn, gdfe):
"""
performs map matching on a given sequence of points
Parameters
----------
Returns
-------
list of tuples each containing timestamp, projected point to the line, the edge to which GPS point has been projected, the geometry of the edge))
"""
traj = pd.DataFrame(traj, columns=['timestamp', 'xy'])
traj['geom'] = traj.apply(lambda row: Point(row.xy), axis=1)
traj = gpd.GeoDataFrame(traj, geometry=traj['geom'], crs=EPSG3740)
traj.drop('geom', axis=1, inplace=True)
n_sindex = gdfn.sindex
res = []
for gps in traj.itertuples():
tm = gps[1]
p = gps[3]
circle = p.buffer(150)
possible_matches_index = list(n_sindex.intersection(circle.bounds))
possible_matches = gdfn.iloc[possible_matches_index]
precise_matches = possible_matches[possible_matches.intersects(circle)]
candidate_nodes = list(precise_matches.index)
candidate_edges = []
for nid in candidate_nodes:
candidate_edges.append(G.in_edges(nid))
candidate_edges.append(G.out_edges(nid))
candidate_edges = [item for sublist in candidate_edges for item in sublist]
dist = []
for edge in candidate_edges:
# get the geometry
ls = gdfe[(gdfe.u == edge[0]) & (gdfe.v == edge[1])].geometry
dist.append([ls.distance(p), edge, ls])
dist.sort()
true_edge = dist[0][1]
true_edge_geom = dist[0][2].item()
pp = true_edge_geom.interpolate(true_edge_geom.project(p)) # projected point
res.append((tm, pp, true_edge, true_edge_geom))
return res
Wir freuen uns darauf, Ihren neuen Algorithmus zu sehen, wenn Sie ihn auf GitHub schieben. – gboeing
Ich werde Sie wissen lassen, sobald ich etwas vorzeigbar habe. –