OSMnxの道路とノードはshapely.geometry.LineString
とshapely.geometry.Point
オブジェクトなので、カーブはなく、座標のシーケンスだけです。あなたが記述した技術用語はMap Matching
です。地図マッチングにはさまざまな方法があります。最も単純なものは、GPSポイントに対して最も近いジオメトリ(ノードまたはエッジ)を見つけるジオメトリマップマッチングです。 point to point
マップマッチングは、組み込みのosmnx関数ox.get_nearest_node()
を使用すると簡単に実現できます。高密度のGPSトラックがある場合は、このアプローチは合理的にうまくいく可能性があります。 point to line
地図マッチングでは、整然とした機能を使用する必要があります。このアプローチの問題は、それが非常に遅いことです。空間インデックスを使用してアルゴリズムの速度を上げることはできますが、ほとんどの場合、十分に高速ではありません。ジオメトリマップマッチングは、すべてのアプローチの中で最も正確ではないことに注意してください。私は数週間前に、OSMnxから得ることができるエッジGeoDataFrameとノードGeoDataFrameを使用した単純なポイント・ツー・ライン・マッチングを行う関数を書いた。私はこのアイデアを放棄しましたが、完成したらGitHubで公開する新しいアルゴリズムに取り組んでいます。一方、これはあなたや他の人のために役立つかもしれないので、私はここに投稿します。これは放棄されたコードの初期バージョンであり、十分にテストされておらず、最適化されていません。試してみて、それがあなたのために働くかどうか私に知らせてください。
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
GitHubにプッシュすると、新しいアルゴリズムが表示されるのを楽しみにしています。 – gboeing
私は何かがあるとすぐにお知らせします。 –