def test_path3(): path = [(3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] path_sol = ['E', 'F'] mapdb = InMemMap("map", graph={ "E": ((3, 3), ["F"]), "F": ((3, 5), ["E"]), }, use_latlon=False) matcher = SimpleMatcher(mapdb, max_dist=None, min_prob_norm=0.0001, max_dist_init=1, obs_noise=0.25, obs_noise_ne=10, non_emitting_states=True) matcher.match(path, unique=True) path_pred = matcher.path_pred_onlynodes if directory: matcher.print_lattice_stats() matcher.print_lattice() from leuvenmapmatching import visualization as mmviz with (directory / 'lattice.gv').open('w') as ofile: matcher.lattice_dot(file=ofile) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_path3.png")) print("Path through lattice:\n" + "\n".join(m.label for m in matcher.lattice_best)) assert path_pred == path_sol, "Nodes not equal:\n{}\n{}".format( path_pred, path_sol)
def test_path1(): mapdb, path1, path2, path_sol = setup_map() matcher = SimpleMatcher(mapdb, max_dist_init=1, min_prob_norm=0.5, obs_noise=0.5, non_emitting_states=True, only_edges=False) matcher.match(path1, unique=True) path_pred = matcher.path_pred_onlynodes if directory: from leuvenmapmatching import visualization as mmviz matcher.print_lattice_stats() matcher.print_lattice() with (directory / 'lattice_path1.gv').open('w') as ofile: matcher.lattice_dot(file=ofile) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, show_graph=True, filename=str(directory / "test_nonemitting_test_path1.png")) assert path_pred == path_sol, f"Nodes not equal:\n{path_pred}\n{path_sol}"
def test_path_outlier(): path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.1, 3.3), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] path_sol = ['A', 'B', 'D', 'C', 'D', 'E', 'F'] path.insert(13, (2.3, 1.8)) mapdb = InMemMap("map", graph={ "A": ((1, 1), ["B", "C", "X"]), "B": ((1, 3), ["A", "C", "D", "K"]), "C": ((2, 2), ["A", "B", "D", "E", "X", "Y"]), "D": ((2, 4), ["B", "C", "F", "E", "K", "L"]), "E": ((3, 3), ["C", "D", "F", "Y"]), "F": ((3, 5), ["D", "E", "L"]), "X": ((2, 0), ["A", "C", "Y"]), "Y": ((3, 1), ["X", "C", "E"]), "K": ((1, 5), ["B", "D", "L"]), "L": ((2, 6), ["K", "D", "F"]) }, use_latlon=False) matcher = SimpleMatcher(mapdb, max_dist=None, min_prob_norm=0.0001, max_dist_init=1, obs_noise=0.5, obs_noise_ne=10, non_emitting_states=True) matcher.match(path, unique=True) path_pred = matcher.path_pred_onlynodes if directory: matcher.print_lattice_stats() matcher.print_lattice() from leuvenmapmatching import visualization as mmviz with (directory / 'lattice.gv').open('w') as ofile: matcher.lattice_dot(file=ofile) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_path_outlier.png")) print("Path through lattice:\n" + "\n".join(m.label for m in matcher.lattice_best)) assert path_pred == path_sol, "Nodes not equal:\n{}\n{}".format(path_pred, path_sol)
def test_path3_few_obs_e(): path = [(1, 0), (7.5, 0.65), (10.1, 1.9)] path_sol = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] mapdb = InMemMap("map", graph={ "A": ((1, 0.00), ["B"]), "B": ((3, 0.00), ["A", "C"]), "C": ((4, 0.70), ["B", "D"]), "D": ((5, 1.00), ["C", "E"]), "E": ((6, 1.00), ["D", "F"]), "F": ((7, 0.70), ["E", "G"]), "G": ((8, 0.00), ["F", "H"]), "H": ((10, 0.0), ["G", "I"]), "I": ((10, 2.0), ["H"]) }, use_latlon=False) matcher = SimpleMatcher(mapdb, max_dist_init=0.2, obs_noise=1, obs_noise_ne=10, non_emitting_states=True, only_edges=True) matcher.match(path) path_pred = matcher.path_pred_onlynodes if directory: matcher.print_lattice_stats() matcher.print_lattice() from leuvenmapmatching import visualization as mmviz mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, linewidth=10, filename=str(directory / "test_test_path_e_3_fo.png")) assert path_pred == path_sol, f"Nodes not equal:\n{path_pred}\n{path_sol}"
def test_path_duplicate(): from datetime import datetime # A path with two identical points path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.1, 3.3), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] mapdb = InMemMap("map", graph={ "A": ((1, 1), ["B", "C"]), "B": ((1, 3), ["A", "C", "D"]), "C": ((2, 2), ["A", "B", "D", "E"]), "D": ((2, 4), ["B", "C", "D", "E"]), "E": ((3, 3), ["C", "D", "F"]), "F": ((3, 5), ["D", "E"]) }, use_latlon=False) matcher = SimpleMatcher(mapdb, max_dist=None, min_prob_norm=None, non_emitting_states = True, only_edges=False) #Matching with and without timestamps signed to the points path_pred = matcher.match(path, unique=False) path = [(p1, p2, datetime.fromtimestamp(i)) for i, (p1, p2) in enumerate(path)] path_pred_time = matcher.match(path, unique=False) if directory: from leuvenmapmatching import visualization as mmviz matcher.print_lattice_stats() matcher.print_lattice() mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_nonemitting_test_path_duplicate.png")) # The path should be identical regardless of the timestamps assert path_pred == path_pred_time, f"Nodes not equal:\n{path_pred}\n{path_pred_time}"
def test_path2(): path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.1, 3.3), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] # path_sol = ['A', ('A', 'B'), 'B', ('B', 'D'), 'D', ('D', 'E'), 'E', ('E', 'F')] path_sol_nodes = ['A', 'B', 'D', 'E', 'F'] mapdb = InMemMap("map", graph={ "A": ((1, 1), ["B", "C", "X"]), "B": ((1, 3), ["A", "C", "D", "K"]), "C": ((2, 2), ["A", "B", "D", "E", "X", "Y"]), "D": ((2, 4), ["B", "C", "F", "E", "K", "L"]), "E": ((3, 3), ["C", "D", "F", "Y"]), "F": ((3, 5), ["D", "E", "L"]), "X": ((2, 0), ["A", "C", "Y"]), "Y": ((3, 1), ["X", "C", "E"]), "K": ((1, 5), ["B", "D", "L"]), "L": ((2, 6), ["K", "D", "F"]) }, use_latlon=False) matcher = SimpleMatcher(mapdb, max_dist=None, min_prob_norm=0.001, non_emitting_states=False, only_edges=False) path_pred, _ = matcher.match(path, unique=True) if directory: matcher.print_lattice_stats() matcher.print_lattice() from leuvenmapmatching import visualization as mmviz mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_path2.png")) # assert path_pred == path_sol, "Nodes not equal:\n{}\n{}".format(path_pred, path_sol) nodes_pred = matcher.path_pred_onlynodes assert nodes_pred == path_sol_nodes, f"Nodes not equal:\n{nodes_pred}\n{path_sol_nodes}"
def test_bug1(): dist = 10 nb_steps = 20 map_con = InMemMap("map", graph={ "A": ((1, dist), ["B"]), "B": ((2, dist), ["A", "C", "CC"]), "C": ((3, 0), ["B", "D"]), "D": ((4 + dist, 0), ["C", "E"]), "CC": ((3, 2 * dist), ["B", "DD"]), "DD": ((4 + dist, 2 * dist), ["CC", "E"]), "E": ((5 + dist, dist), ["F", "D", "DD"]), "F": ((6 + dist, dist), ["E", ]), }, use_latlon=False) i = 10 path = [(1.1, 2*dist*i/nb_steps), (2.1, 2*dist*i/nb_steps), (5.1+dist, 2*dist*i/nb_steps), (6.1+dist, 2*dist*i/nb_steps) # (1, len*i/nb_steps), # (2, len*i/nb_steps), # (3, len*i/nb_steps) ] matcher = SimpleMatcher(map_con, max_dist=dist + 1, obs_noise=dist + 1, min_prob_norm=None, non_emitting_states=True) nodes = matcher.match(path, unique=False) print("Solution: ", nodes) if directory: import leuvenmapmatching.visualization as mm_vis matcher.print_lattice() matcher.print_lattice_stats() mm_vis.plot_map(map_con, path=path, nodes=nodes, counts=matcher.node_counts(), show_labels=True, filename=str(directory / "test_bugs_1.png"))
def test_path2_incremental(): mapdb, path1, path2, path_sol = setup_map() matcher = SimpleMatcher(mapdb, max_dist_init=1, min_prob_norm=0.5, obs_noise=0.5, non_emitting_states=True, only_edges=False) matcher.match_incremental(path2[:2]) path_pred_1 = matcher.path_pred_onlynodes matcher.match_incremental(path2[2:], backtrace_len=len(path2)) path_pred = matcher.path_pred_onlynodes if directory: from leuvenmapmatching import visualization as mmviz matcher.print_lattice_stats() matcher.print_lattice() with (directory / 'lattice_path2.gv').open('w') as ofile: matcher.lattice_dot(file=ofile) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, filename=str(directory / "test_nonemitting_test_path2.png")) assert path_pred_1 == path_sol[:2], "Nodes not equal:\n{}\n{}".format(path_pred, path_sol) assert path_pred == path_sol, "Nodes not equal:\n{}\n{}".format(path_pred, path_sol)
def match(track, graph, streetmap, matcher_alg='DistanceMatcher', max_dist=200, max_dist_init=100, min_prob_norm=0.001, non_emitting_length_factor=0.75, obs_noise=50, obs_noise_ne=75, dist_noise=50, non_emitting_edgeid=False): ''' This function match the floating car track. Parameters: ___________ track: np.array of tuples (x,y) Array of the floating car track coordinates. graph: OSMNX road network Osmnx road network of the area of study streetmap: InMem map LeuvenMapMatching InMem map of the graph mather_alg: string Name of the matcher algorithm of choice max_dist: int maximum distance from the track max_dist_init: int initial maximum distance min_prob_norm: float Minmum normalized probability non_emitting_length_factor: float The factor no emmiting state that it takes obs_noise: int Standard Deviation of noise obs_noise_ne: int Standard Deviation of noise in non emitting state dist_noise: int distance of the noise non_emitting_edgeid: boolean If allow on-emitting states Returns: __________ edge_id: np.array of tuples An array consisting tuples, (start node id, end node id) last_idx: int Last index of the point mapped track_corr: np.array array of map matched coordinates route: np.array array of computed route of the map matched track ''' # get leuvenmapmatching InMem mam from the road network #streetmap = get_InMemMap(graph) # select the matcher of choise if (matcher_alg == 'DistanceMatcher'): matcher = DistanceMatcher( streetmap, max_dist=max_dist, max_dist_init=max_dist_init, min_prob_norm=min_prob_norm, non_emitting_length_factor=non_emitting_length_factor, obs_noise=obs_noise, obs_noise_ne=obs_noise_ne, dist_noise=dist_noise, non_emitting_edgeid=non_emitting_edgeid) elif (matcher_alg == 'NewsonKrummMatcher'): matcher = NewsonKrummMatcher( streetmap, max_dist=max_dist, max_dist_init=max_dist_init, min_prob_norm=min_prob_norm, non_emitting_length_factor=non_emitting_length_factor, obs_noise=obs_noise, obs_noise_ne=obs_noise_ne, dist_noise=dist_noise, non_emitting_edgeid=non_emitting_edgeid) elif (matcher_alg == 'SimpleMatcher'): matcher = SimpleMatcher( streetmap, max_dist=max_dist, max_dist_init=max_dist_init, min_prob_norm=min_prob_norm, non_emitting_length_factor=non_emitting_length_factor, obs_noise=obs_noise, obs_noise_ne=obs_noise_ne, dist_noise=dist_noise, non_emitting_edgeid=non_emitting_edgeid) else: print('No matcher selected') return # Perform the mapmatching edge_ids, last_idx = matcher.match(track) # Reference ellipsoid for distance geod = Geod(ellps='WGS84') proj_dist = np.zeros(len(track)) # edgeid refers to edges id (node1_id, node2_id) where the GPS point is projected lat_corr, lon_corr = [], [] lat_nodes = matcher.lattice_best for idx, m in enumerate(lat_nodes): if (idx == len(track)): break lat, lon = m.edge_m.pi[:2] lat_corr.append(lat) lon_corr.append(lon) # print(idx) _, _, distance = geod.inv(track[idx][1], track[idx][0], lon, lat) proj_dist[idx] += distance # construct array of cordinates track_corr = np.column_stack((lat_corr, lon_corr)) # get the route from the projected cordinates route = compute_route(streetmap, track_corr, edge_ids) # returns return edge_ids, last_idx, track_corr, route
def test_path2_inc(): path = [(0.8, 0.7), (0.9, 0.7), (1.1, 1.0), (1.2, 1.5), (1.2, 1.6), (1.1, 2.0), (1.1, 2.3), (1.3, 2.9), (1.2, 3.1), (1.5, 3.2), (1.8, 3.5), (2.0, 3.7), (2.1, 3.3), (2.4, 3.2), (2.6, 3.1), (2.9, 3.1), (3.0, 3.2), (3.1, 3.8), (3.0, 4.0), (3.1, 4.3), (3.1, 4.6), (3.0, 4.9)] # path_sol = ['A', ('A', 'B'), 'B', ('B', 'D'), 'D', ('D', 'E'), 'E', ('E', 'F')] path_sol_nodes = ['A', 'B', 'D', 'E', 'F'] mapdb = InMemMap("map", graph={ "A": ((1, 1), ["B", "C", "X"]), "B": ((1, 3), ["A", "C", "D", "K"]), "C": ((2, 2), ["A", "B", "D", "E", "X", "Y"]), "D": ((2, 4), ["B", "C", "F", "E", "K", "L"]), "E": ((3, 3), ["C", "D", "F", "Y"]), "F": ((3, 5), ["D", "E", "L"]), "X": ((2, 0), ["A", "C", "Y"]), "Y": ((3, 1), ["X", "C", "E"]), "K": ((1, 5), ["B", "D", "L"]), "L": ((2, 6), ["K", "D", "F"]) }, use_latlon=False) ## Phase 1 print('=== PHASE 1 ===') matcher = SimpleMatcher(mapdb, max_dist=None, min_prob_norm=0.001, non_emitting_states=False, only_edges=False, max_lattice_width=1) path_pred, _ = matcher.match(path, unique=True) if directory: matcher.print_lattice_stats() matcher.print_lattice() from leuvenmapmatching import visualization as mmviz with (directory / 'test_path2_inc_1.gv').open('w') as ofile: matcher.lattice_dot(file=ofile, precision=2, render=True) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, show_lattice=True, show_graph=True, filename=str(directory / "test_path2_inc_1.png")) ## Next phases for phase_nb, phase_width in enumerate([2, 3]): print(f'=== PHASE {phase_nb + 2} ===') path_pred, _ = matcher.increase_max_lattice_width(phase_width, unique=True) if directory: matcher.print_lattice_stats() matcher.print_lattice() from leuvenmapmatching import visualization as mmviz with (directory / f'test_path2_inc_{phase_nb + 2}.gv').open('w') as ofile: matcher.lattice_dot(file=ofile, precision=2, render=True) mmviz.plot_map(mapdb, matcher=matcher, show_labels=True, show_matching=True, show_lattice=True, show_graph=True, filename=str(directory / f"test_path2_inc_{phase_nb + 2}.png")) # assert path_pred == path_sol, "Nodes not equal:\n{}\n{}".format(path_pred, path_sol) nodes_pred = matcher.path_pred_onlynodes assert nodes_pred == path_sol_nodes, f"Nodes not equal:\n{nodes_pred}\n{path_sol_nodes}"