Is it possible to set coordinate to street in OSMnx?

OSMnx provides a solution for calculating the shortest path between two nodes, but I would like it to be with points on the streets (I have GPS coordinates recorded from vehicles). I know there is a method to get the nearest node, but I have two questions on this issue.

i) When is the nearest node street calculated where point is also taken into account? (I assume not) ii) If I wanted to implement something like this, I like to know how the street (edge) is represented by a curve (a Bezier curve maybe?). Can you get a curve (or curve equation) of an edge?

I asked this question here because its suggested guidelines for promoting OSMnx.

+3


source to share


1 answer


Streets and nodes in OSMnx are objects shapely.geometry.LineString

and shapely.geometry.Point

therefore there is no curve, only a sequence of coordinates. The technical term for what you described is Map Matching

. There are various ways to map maps, the simplest of which is geometric map matching, in which you will find the closest geometry (node ​​or edge) to the GPS point. point to point

map matching can be easily achieved with the built-in osmnx function ox.get_nearest_node()

. If you have the luxury of dense GPS tracks, this approach might work well enough. For matching cardspoint to line

you have to use nice functions. The problem with this approach is that it is very slow. you can speed up the algorithm using a spatial index, but it will still not be fast enough for most purposes. Note that geometric map matching is the least accurate of all approaches. A few weeks ago I wrote a function that makes a simple approach to row matching using edge GeoDataFrame and node GeoDataFrame which you can get from OSMnx. I gave up on this idea and now I am working on a new algorithm (hopefully much faster), which I will post on GitHub when completed. In the meantime, this might help you or someone else, so I am posting it here. This is an early version of the failed code, insufficiently tested and not optimized.try it and let me know if it works for you.



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

      

+2


source







All Articles