def distance_geometry_signature(trajectory, num_control_points=4, normalize_distance=True): # Sets the distance increment for control points based on the number of control points # Calculates the fractions of the trajectory where control points should be # Gives the values where the control points are located control_point_increment = 1.0 / (num_control_points - 1) control_point_fractions = [ control_point_increment * i for i in range(num_control_points) ] control_points = [ point_at_length_fraction(trajectory, t) for t in control_point_fractions ] # A signature is a collection of the calculated distances that will be converted to a feature vector signature = [] # Calculate the list of distances for stepsize in range(num_control_points - 1, 0, -1): for start in range(0, num_control_points - stepsize): end = start + stepsize signature.append( distance(control_points[start], control_points[end])) # Normalize distances to compare trajectory shapes if normalize_distance: largest_distance = max(signature) signature = [ 0 if not largest_distance else d / largest_distance for d in signature ] # Convert distances to a feature vector return convert_to_feature_vector(signature)
def verify_base_point(expected, actual, test_name): if (geomath.distance(actual, expected) > .1): sys.stderr.write( 'ERROR: {} does not match. Expected {}, but returned {}.\n'.format( test_name, expected, actual)) return 1 return 0
def test_terrestrial_distance(): error_count = 0 albuquerque = TerrestrialTrajectoryPoint(-106.6504, 35.0844) dallas = TerrestrialTrajectoryPoint(-96.8716, 32.8205) el_paso = TerrestrialTrajectoryPoint(-106.4850, 31.7619) san_antonio = TerrestrialTrajectoryPoint(-98.6544, 29.4813) houston = TerrestrialTrajectoryPoint(-74.0060, 29.8168) ep_to_dal = TerrestrialTrajectory.from_position_list([el_paso, dallas]) sa_to_hou = TerrestrialTrajectory.from_position_list( [san_antonio, houston]) sa_to_abq = TerrestrialTrajectory.from_position_list( [san_antonio, albuquerque]) print("Testing Terrestrial Distance") expected = 369.764 actual = geomath.distance(albuquerque, el_paso) error_count += verify_result( actual, expected, "TerrestrialTrajectoryPoint to TerrestrialTrajectoryPoint") expected = 349.276 actual = geomath.distance(ep_to_dal, sa_to_hou) error_count += verify_result( actual, expected, "TerrestrialTrajectory to TerrestrialTrajectory") expected = 0.0 actual = geomath.distance(ep_to_dal, sa_to_abq) error_count += verify_result( actual, expected, "TerrestrialTrajectory to TerrestrialTrajectory Intersecting") expected = 975.674 actual = geomath.distance(albuquerque, sa_to_hou) error_count += verify_result( actual, expected, "TerrestrialTrajectoryPoint to TerrestrialTrajectory") actual = geomath.distance(sa_to_hou, albuquerque) error_count += verify_result( actual, expected, "TerrestrialTrajectory to TerrestrialTrajectoryPoint") return error_count
def verify_result(expected, actual, test): if (geomath.distance(actual, expected) > .1): sys.stderr.write( 'ERROR: {} does not match. Expected centroid {}, but returned {}.\n' .format(test, expected, actual)) return 1 return 0
def verify_trajectory_point(expected, actual, test_name): if (geomath.distance(actual, expected) > .1 or actual.timestamp != expected.timestamp or actual.property('speed') != expected.property('speed') or actual.property('heading') != expected.property('heading')): sys.stderr.write( 'ERROR: {} does not match. Expected {}, but returned {}.\n'.format( test_name, expected, actual)) return 1 return 0
def test_cartesian3d_distance(): error_count = 0 point000 = Cartesian3dTrajectoryPoint(0, 0, 0) point001 = Cartesian3dTrajectoryPoint(0, 0, 1) point111 = Cartesian3dTrajectoryPoint(1, 1, 1) point222 = Cartesian3dTrajectoryPoint(2, 2, 2) traj1 = Cartesian3dTrajectory.from_position_list([point000, point001]) traj2 = Cartesian3dTrajectory.from_position_list([point111, point222]) print("Testing Cartesian 3D Distance") expected = 1.0 actual = geomath.distance(point000, point001) error_count += verify_result( actual, expected, "Cartesian3dTrajectoryPoint to Cartesian3dTrajectoryPoint 1") expected = 1.732 actual = geomath.distance(point000, point111) error_count += verify_result( actual, expected, "Cartesian3dTrajectoryPoint to Cartesian3dTrajectoryPoint 2") #Does not work due to boost not implementing disjoint for dimensions > 3 which is called by the distance function. #expected = 1.414 #actual = geomath.distance(traj1, traj2) #error_count += verify_result(actual, expected, "Cartesian3dTrajectory to Cartesian3dTrajectory") expected = 1.732 actual = geomath.distance(point000, traj2) error_count += verify_result( actual, expected, "Cartesian3dTrajectoryPoint to Cartesian3dTrajectory") actual = geomath.distance(traj2, point000) error_count += verify_result( actual, expected, "Cartesian3dTrajectory to Cartesian3dTrajectoryPoint") return error_count
def test_cartesian2d_distance(): error_count = 0 point00 = Cartesian2dTrajectoryPoint(0, 0) point01 = Cartesian2dTrajectoryPoint(0, 1) point11 = Cartesian2dTrajectoryPoint(1, 1) point22 = Cartesian2dTrajectoryPoint(2, 2) traj1 = Cartesian2dTrajectory.from_position_list([point00, point01]) traj2 = Cartesian2dTrajectory.from_position_list([point11, point22]) print("Testing Cartesian 2D Distance") expected = 1.0 actual = geomath.distance(point00, point01) error_count += verify_result( actual, expected, "Cartesian2dTrajectoryPoint to Cartesian2dTrajectoryPoint 1") expected = 1.414 actual = geomath.distance(point00, point11) error_count += verify_result( actual, expected, "Cartesian2dTrajectoryPoint to Cartesian2dTrajectoryPoint 2") expected = 1.0 actual = geomath.distance(traj1, traj2) error_count += verify_result( actual, expected, "Cartesian2dTrajectory to Cartesian2dTrajectory") expected = 1.414 actual = geomath.distance(point00, traj2) error_count += verify_result( actual, expected, "Cartesian2dTrajectoryPoint to Cartesian2dTrajectory") actual = geomath.distance(traj2, point00) error_count += verify_result( actual, expected, "Cartesian2dTrajectory to Cartesian2dTrajectoryPoint") return error_count
def time_between_positions(start, end, desired_speed=800): """time_between_positions(start: position, end: position, desired_speed: float (km/h)) -> datetime.timedelta Given two points and a constant speed, calculate the amount of time (expressed in seconds as a timedelta) to travel from hither to yon. """ distance = geomath.distance(start, end) seconds = 3600.0 * (distance / desired_speed) return datetime.timedelta(seconds=seconds)
def get_features(trajectory): signature = [] signature.append(cha(trajectory)) signature.append(distance(trajectory[0], trajectory[len(trajectory)-1])) return convert_to_feature_vector(signature)
def trajectories(self): """Return trajectories assembled from input points. Once you have supplied a point source in the 'input' attribute (which can be any iterable but is commonly the output of a PointSource) you can call trajectories() to get an iterable of trajectories. All the computation happens on demand so the execution time between getting one trajectory and getting the next one is unpredictable. There are only loose guarantees on the order in which trajectories become available. Given trajectories A and B, if timestamp(A.end) < timestamp(B.end) then A will come up before B. The input sequence of trajectories will only be traversed once. Yields: Trajectories built from input points """ trajectory_class = None trajectories_in_progress = {} self.valid_trajectory_count = 0 self.invalid_trajectory_count = 0 self.points_processed_count = 0 print("INFO: Trajectory assembly: New trajectories will be " + "declared after a separation of {} units or {} seconds.".format( self.separation_distance, self.separation_time)) print("INFO: Trajectories with fewer than {} points will be rejected.". format(self.minimum_length)) for point in self.input: self.points_processed_count += 1 if trajectory_class is None: trajectory_class = point.domain_classes['Trajectory'] object_id = point.object_id if object_id not in trajectories_in_progress: trajectories_in_progress[object_id] = [point] else: updates_so_far = trajectories_in_progress[object_id] time_since_last_update = point.timestamp - updates_so_far[ -1].timestamp distance_since_last_update = distance(point, updates_so_far[-1]) if ((self.separation_time and time_since_last_update > self.separation_time) or (self.separation_distance and distance_since_last_update > self.separation_distance)): # We've passed our threshold for declaring a new # trajectory if len(updates_so_far) >= self.minimum_length: new_trajectory = trajectory_class.from_position_list( updates_so_far) yield (new_trajectory) self.valid_trajectory_count += 1 if self.valid_trajectory_count > 0 and self.valid_trajectory_count % 100 == 0: print( "(1) STATUS: {} trajectories announced and {} discarded for having fewer than {} points" .format(self.valid_trajectory_count, self.invalid_trajectory_count, self.minimum_length)) else: self.invalid_trajectory_count += 1 if self.invalid_trajectory_count > 0 and self.invalid_trajectory_count % 100 == 0: print( "(2) STATUS: {} trajectories announced and {} discarded for having fewer than {} points" .format(self.valid_trajectory_count, self.invalid_trajectory_count, self.minimum_length)) trajectories_in_progress[object_id] = [point] else: # This is a continuation of an existing trajectory updates_so_far.append(point) # Every so often we need to go through and flush out # trajectories that are in progress. We can only do this # if the user has supplied a split_threshold_time # parameter. # # TODO: Make this run based on the number of points # currently being stored rather than the number of # trajectories announced if self.valid_trajectory_count > 0 and self.valid_trajectory_count % 1000 == 0: if self.separation_time: old_trajectories = trajectories_in_progress trajectories_in_progress = dict() now = point.timestamp for (object_id, update_list) in old_trajectories.items(): if (now - update_list[-1].timestamp ) > self.separation_time: if len(update_list) >= self.minimum_length: new_trajectory = trajectory_class.from_position_list( update_list) yield (new_trajectory) self.valid_trajectory_count += 1 if self.valid_trajectory_count > 0 and self.valid_trajectory_count % 100 == 0: print( "(3) STATUS: {} trajectories announced and {} discarded for having fewer than {} points" .format(self.valid_trajectory_count, self.invalid_trajectory_count, self.minimum_length)) else: self.invalid_trajectory_count += 1 if self.invalid_trajectory_count > 0 and self.invalid_trajectory_count % 100 == 0: print( "(4) STATUS: {} trajectories announced and {} discarded for having fewer than {} points" .format(self.valid_trajectory_count, self.invalid_trajectory_count, self.minimum_length)) else: trajectories_in_progress[object_id] = update_list # We've finished iterating over all the position updates in # the window. Go through all the position updates we're still # hanging onto and make trajectories out of them. for (object_id, update_list) in trajectories_in_progress.items(): if len(update_list) >= self.minimum_length: new_trajectory = trajectory_class.from_position_list( update_list) yield (new_trajectory) self.valid_trajectory_count += 1 if self.valid_trajectory_count > 0 and self.valid_trajectory_count % 100 == 0: print( "STATUS: {} trajectories announced and {} discarded for having fewer than {} points" .format(self.valid_trajectory_count, self.invalid_trajectory_count, self.minimum_length)) else: self.invalid_trajectory_count += 1 if self.invalid_trajectory_count > 0 and self.invalid_trajectory_count % 100 == 0: print( "STATUS: {} trajectories announced and {} discarded for having fewer than {} points" .format(self.valid_trajectory_count, self.invalid_trajectory_count, self.minimum_length)) print("INFO: Done assembling trajectories.") if self.valid_trajectory_count == 0: print( "INFO: No trajectories produced. Are you sure your delimiters and your column assignments are correct?" ) return