Beispiel #1
0
    def test_edge_property(self):
        """
        Small experimental test to verify whether the Frechet Distance
        between any two edges is defined my the maximum distance between
        both pairs of endpoints.
        """
        spacing = 0.5
        fixed = Edge2D(Point2D(0.0, 0.0), Point2D(0.0, 1.0)).get_steiner_edge(spacing)
        u, v = fixed.get_spine()

        def almost_equal(estimate, real):
            return real + 1 >= estimate >= real - 1

        for i in range(0, 10000):
            p1 = Point2D(float(randint(-20, 20)), float(randint(-20, 20)))
            p2 = Point2D(float(randint(-20, 20)), float(randint(-20, 20)))

            # Ensure points aren't the same
            if p1 == p2:
                p2 = Point2D(p2.x + 0.1, p2.y)

            rand_edge = Edge2D(p1, p2).get_steiner_edge(spacing)
            x, y = rand_edge.get_spine()
            r = min(
                max(np.linalg.norm(x.v - u.v), np.linalg.norm(y.v - v.v)),
                max(np.linalg.norm(y.v - u.v), np.linalg.norm(x.v - v.v))
            )
            frechet_estimate = discrete_frechet(fixed, rand_edge)

            assert almost_equal(r, frechet_estimate)
    def test_edge(self):
        curve = Edge2D(Point2D(-5.0, 1.0), Point2D(-4.0, 4.0))
        e = Edge2D(Point2D(-3.0, 1.0), Point2D(-3.0, 3.0))
        grid = FrechetGrid2D(curve, self.error)

        real = discrete_frechet(e.get_steiner_curve(STEINER_SPACING),
                                curve.get_steiner_curve(STEINER_SPACING))
        estimate = grid.approximate_frechet(e)

        # Test for (1 + epsilon) property of grid estimate
        assert estimate <= real or \
            real <= (1 + self.error) * estimate
Beispiel #3
0
    def test_query_trivial_curve(self):
        tree = CurveRangeTree2D(
            PolygonalCurve2D(
                [Point2D(0.0, 0.0),
                 Point2D(3.0, 0.0),
                 Point2D(3.0, 3.0)]), self.error, self.delta)

        # Create query parameters
        q_edge = Edge2D(Point2D(0.0, -1.0), Point2D(3.0, -1.0))
        x = Point2D(0.25, 0.0)
        x_edge = Edge2D(Point2D(0.0, 0.0), Point2D(3.0, 0.0))
        y = Point2D(3.0, 2.5)
        y_edge = Edge2D(Point2D(3.0, 0.0), Point2D(3.0, 3.0))

        assert tree.is_approximate(q_edge, x, y, x_edge, y_edge)
    def __init_distances(self, curve):
        distances = dict()

        for p_prime in self.grid_u.points:
            distances[str(p_prime)] = dict()

            for q_prime in self.grid_v.points:
                distances[str(p_prime)][str(q_prime)] = \
                    discrete_frechet(Edge2D(p_prime, q_prime).get_steiner_curve(STEINER_SPACING),
                                     curve.get_steiner_curve(STEINER_SPACING))

        return distances
Beispiel #5
0
    def test_query_square_curve(self):
        tree = CurveRangeTree2D(
            PolygonalCurve2D([
                Point2D(0.0, 0.0),
                Point2D(5.0, 0.0),
                Point2D(5.0, 5.0),
                Point2D(1.0, 5.0),
                Point2D(1.0, 1.0),
                Point2D(4.0, 1.0),
                Point2D(4.0, 4.0),
                Point2D(2.0, 4.0),
                Point2D(2.0, 2.0),
                Point2D(3.0, 2.0),
                Point2D(3.0, 3.0)
            ]), self.error, self.delta)

        # Create query parameters
        x = Point2D(2.5, 0.0)
        x_edge = Edge2D(Point2D(0.0, 0.0), Point2D(5.0, 0.0))
        y = Point2D(3.0, 2.5)
        y_edge = Edge2D(Point2D(3.0, 2.0), Point2D(3.0, 3.0))

        # Query various edges against this tree
        q_edge = Edge2D(Point2D(2.5, -2.0), Point2D(5.5, -0.5))
        assert tree.is_approximate(q_edge, x, y, x_edge, y_edge)

        q_edge = Edge2D(Point2D(-1.1, 5.0), Point2D(-1.1, 1))
        assert not tree.is_approximate(q_edge, x, y, x_edge, y_edge)

        q_edge = Edge2D(Point2D(1.0, 2.5), Point2D(5.0, 2.5))
        assert not tree.is_approximate(q_edge, x, y, x_edge, y_edge)

        q_edge = Edge2D(Point2D(0.0, 0.0), Point2D(5.0, 5.0))
        assert not tree.is_approximate(q_edge, x, y, x_edge, y_edge)
Beispiel #6
0
    def test_small_float_values(self):
        tree = CurveRangeTree2D(
            PolygonalCurve2D([
                Point2D(0.0, 0.0),
                Point2D(1.0, 0.0),
                Point2D(0.0, -0.01),
                Point2D(1.0, -0.01),
                Point2D(0.0, -0.02),
                Point2D(1.0, -0.02)
            ]), self.error, 0.55)

        # Create query parameters
        q_edge = Edge2D(Point2D(0.0, 0.0), Point2D(1.0, -0.02))
        x = Point2D(0.0, 0.0)
        x_edge = Edge2D(Point2D(0.0, 0.0), Point2D(1.0, 0.0))
        y = Point2D(1.0, -0.02)
        y_edge = Edge2D(Point2D(0.0, -0.02), Point2D(1.0, -0.02))

        assert tree.is_approximate(q_edge, x, y, x_edge, y_edge)

        q_edge = Edge2D(Point2D(2.2, 0.0), Point2D(2.2, -0.02))
        assert not tree.is_approximate(q_edge, x, y, x_edge, y_edge)
 def __init__(self, curve, error):
     assert 0 < error <= 1, 'Error rate specified must be greater than 0 and at most 1.'
     self.__u, self.__v = curve.get_spine()
     self.__steiner_curve = curve.get_steiner_curve(STEINER_SPACING)
     self.__L = discrete_frechet(
         Edge2D(self.__u, self.__v).get_steiner_curve(STEINER_SPACING),
         curve.get_steiner_curve(STEINER_SPACING))
     self.__error = error
     self.grid_u = ExponentialGrid2D(self.__u, error, error * self.__L / 2, self.__L / error) \
         if self.__L != 0 else None
     self.grid_v = ExponentialGrid2D(self.__v, error, error * self.__L / 2, self.__L / error) \
         if self.__L != 0 else None
     self.distances = self.__init_distances(
         curve) if self.__L != 0 else None
    def find_frechet_bottleneck(self, q_edge, subpaths):
        # Step 2: Partition q_edge and compute partitioning point sets
        partitions = list()
        pi = q_edge.sub_divide(self.__error * self.__delta / 3)
        for subpath in subpaths[1:]:
            dag_points = Edge2D.partition(pi, subpath.curve.get_point(0),
                                          2 * self.__delta)

            if len(dag_points) > 0:
                partitions.append(dag_points)

        # Step 3: Construct the Directed Acyclic Graph
        dag = DirectedAcyclicGraph()
        for i in range(0, len(partitions) - 1):
            j = i + 1

            for u in partitions[i]:
                for v in partitions[j]:
                    if u == v:
                        continue
                    elif u != q_edge.p2 and v.is_on_edge(Edge2D(u, q_edge.p2)):
                        dag.add_edge(
                            u, v, subpaths[i + 1].grid.approximate_frechet(
                                Edge2D(u, v)))

        if len(partitions) > 0:
            for v in partitions[0]:
                if v == q_edge.p1:
                    continue
                dag.add_edge(
                    q_edge.p1, v,
                    subpaths[0].grid.approximate_frechet(Edge2D(q_edge.p1, v)))

            for u in partitions[len(partitions) - 1]:
                if u == q_edge.p2:
                    continue
                dag.add_edge(
                    u, q_edge.p2,
                    subpaths[len(partitions) - 1].grid.approximate_frechet(
                        Edge2D(u, q_edge.p2)))
        else:
            dag.add_edge(
                q_edge.p1, q_edge.p2, subpaths[0].grid.approximate_frechet(
                    Edge2D(q_edge.p1, q_edge.p2)))
            dag.add_edge(
                q_edge.p1, q_edge.p2,
                subpaths[len(partitions) - 1].grid.approximate_frechet(
                    Edge2D(q_edge.p1, q_edge.p2)))

        # Step 4: Find the heaviest weighted edge on the bottleneck path of the DAG
        delta_prime = dag.bottleneck_path_weight(q_edge.p1, q_edge.p2)
        return delta_prime <= (1 + self.__error) * self.__delta
Beispiel #9
0
    def is_approximate(self, q_edge, x, y, x_node, y_node):
        # Assume tree node data stores Point2D objects
        x_edge = Edge2D(x_node.point, x_node.parent.point)
        y_edge = Edge2D(y_node.point, y_node.parent.point)

        lca = self.tree.lowest_common_ancestor(x_node, y_node)
        paths = self.__find_decomposed_curves(x_node, lca) + self.__find_decomposed_curves(y_node, lca)[::-1]

        subpaths = list()
        for i in range(0, len(paths)):
            path = paths[i]
            curve_tree = self.path_trees.get(str(path))

            end = path.get_point(-1)
            if i == 0:
                subpaths += curve_tree.partition_path(x, end, x_edge, Edge2D(path.get_point(-2), end))
            elif i == len(paths) - 1:
                subpaths += curve_tree.partition_path(y, end, y_edge, Edge2D(path.get_point(-2), end))
            else:
                start = path.get_point(0)
                subpaths += curve_tree.partition_path(start, end,
                                                      Edge2D(start, path.get_point(1)), Edge2D(path.get_point(-2), end))

        return self.path_trees.values()[0].find_frechet_bottleneck(q_edge, subpaths)
    def partition_path(self, x, y, x_edge, y_edge):
        # Assumes x located on the left side of the path w.r.t. y
        x_node = self.__find_node(self.root, x_edge)
        y_node = self.__find_node(self.root, y_edge)

        # Assumes tree has already been decomposed
        lca = self.lowest_common_ancestor(x_node, y_node)

        # noinspection PyUnreachableCode
        def __walk_left(node, edge):
            if node.is_leaf():
                yield node
            elif node.curve.is_in_left_curve(edge):
                for n in __walk_left(node.left, edge):
                    yield n

                yield node.right
            elif node.curve.is_in_right_curve(edge):
                for n in __walk_left(node.right, edge):
                    yield n
            else:
                return
                yield

        # noinspection PyUnreachableCode
        def __walk_right(node, edge):
            if node.is_leaf():
                yield node
            elif node.curve.is_in_left_curve(edge):
                for n in __walk_right(node.left, edge):
                    yield n
            elif node.curve.is_in_right_curve(edge):
                for n in __walk_right(node.right, edge):
                    yield n

                yield node.left
            else:
                return
                yield

        subpaths = list()

        if lca.left:
            for node in __walk_left(lca.left, x_edge):
                if node == x_node:
                    node = self.Node(Edge2D(x, node.curve.get_point(1)),
                                     self.__error)

                subpaths.append(node)

        if lca.right:
            right_subpaths = list()

            for node in __walk_right(lca.right, y_edge):
                if node == y_node:
                    node = self.Node(Edge2D(node.curve.get_point(0), y),
                                     self.__error)

                right_subpaths.append(node)

            subpaths += right_subpaths[::-1]

        return subpaths