def cut_points_by_distance(scs, n=10, max_distance=45, \ min_distance=1.0, min_length=10): """ Cuts points into tracks according to some distance criterion. Arguments: - scs: a list of StateCollection items corresponding to a run - n: index shift, > 0. The algorithm will compare the distance between sc[i] and sc[i+n]. If this distance is found to be greater than n * max_distance, the trjactory is cut at i. - max_distance: the maximum distance between two points. Two points separated by more than this distance are cut. - min_distance: minimum distance between two point. Below this distance, the new point is discard for beeing too close. - min_length: the minimum length of a track. n: """ # Meters, corresponds to 1-second probe data N = len(scs) # Compute the n-cut distance first to get an idea of long-terms cuts dsn = [mm_dis(scs[i].gps_pos, scs[i+n].gps_pos) for i in xrange(N-n)] # Distance cuts: d_cuts = [i for i in xrange(N-n) if dsn[i] > n*max_distance] points = [0] + d_cuts + [N] res = [] for (start, end) in zip(points[:-1], points[1:]): all_points = scs[start:end] all_points.reverse() l = [all_points[-1]] while all_points: x = all_points.pop() if mm_dis(x.gps_pos, l[-1].gps_pos) > min_distance: l.append(x) if len(l) >= min_length: res.append(l) return res
def remove_spurious_points(scs, n=3, max_distance=45, \ min_distance=1.0, min_length=10): """ Removes a number of points that are of no interest or may cause trouble: - points that correspond to no move (stationary vehicle) - far points that correspond to GPS errors that make the trajectory jump Arguments: scs: a list of StateCollection items corresponding to a run n: the maximum number of points that may group as a GPS error max_distance: that maximum distance between points corresponding to a valid travel. Over this distance, the point is assumed to be disconnected. min_distance: under this distance, the vehicle is assumed to be stationary min_length: minimum size of groups of points to correspond to a valid trajectory chunk. Returns: a list of list of valid tracks. """ res = [] # This is a queue that will contain the points # Each point will be popped out and compared to the head of the # current track. all_scs = list(scs) all_scs.reverse() # Need to reverse, since we will pop() from the start. current_track = [] current_junk = [] while all_scs: current_sc = all_scs.pop() if not current_track: current_track = [current_sc] else: last_sc = current_track[-1] assert last_sc.time < current_sc.time # Compare the distance d = mm_dis(last_sc.gps_pos, current_sc.gps_pos) # If too far, add to the junk if d < min_distance: continue if d > max_distance: current_junk.append(current_sc) # If junk if full, discard it, cut the track and start again if len(current_junk) > n: current_junk = [] # If the cut track is long enough, keep it if len(current_track) >= min_length: res.append(current_track) current_track = [] else: current_track.append(current_sc) # And take care of the last track if len(current_track) >= min_length: res.append(current_track) return res