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)
Example #2
0
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
Example #3
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
Example #5
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
Example #6
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
Example #7
0
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
Example #8
0
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)
Example #10
0
    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