示例#1
0
        def split_leaf(self):
            """
            Splits the given RTreeNode into 2 separate Nodes
            Then moves its entries into one of the two nodes
            """
            if len(self.children) > 0:
                raise NotImplementedError('[DEBUG] Unexpected behavior')
            # 1. Find the two most far-apart objects
            max_distance = -1
            max_obj_a, max_obj_b = None, None
            for idx, entry in enumerate(self.entries):
                for idx_2 in range(len(self.entries)):
                    if idx == idx_2:
                        continue
                    other_entry = self.entries[idx_2]

                    dist = entry.mbr.distance_between(other_entry.mbr)
                    if dist > max_distance:
                        max_distance = dist
                        max_obj_a = entry
                        max_obj_b = other_entry

            # 2. Create two new nodes to accommodate the new objects
            node_a = self.__class__(min_order=self.minimum_order, max_order=self.maximum_order,
                                    mbr=Rectangle.containing(max_obj_a.mbr))
            node_a.add(max_obj_a)
            node_b = self.__class__(min_order=self.minimum_order, max_order=self.maximum_order,
                                    mbr=Rectangle.containing(max_obj_b.mbr))
            node_b.add(max_obj_b)

            # 3. Move rest of entries to appropriate nodes
            rest_entries = [entry for entry in self.entries if entry != max_obj_a and entry != max_obj_b]
            for idx, entry in enumerate(rest_entries):
                rest_entry_count = len(rest_entries) - idx
                needed_a_entries = node_a.minimum_order - len(node_a.entries)
                needed_b_entries = node_b.minimum_order - len(node_b.entries)
                if rest_entry_count == needed_a_entries:
                    node_a.add(entry)  # All the rest should go to A
                elif rest_entry_count == needed_b_entries:
                    node_b.add(entry)  # All the rest should go to B
                else:
                    # Put it in the one whose MBR requires least expansion
                    # TODO: Handle case where both bound entry
                    node: 'RTreeNode' = self.find_min_expansion_node([node_a, node_b], entry)
                    node.add(entry)

            # 4. Expand node's MBR to fir their biggest
            for node in [node_a, node_b]:
                for entry in node.entries:
                    entry: Entry
                    if not node.mbr.is_bounding(entry.mbr):
                        node.mbr.expand_to(entry.mbr)

            return node_a, node_b
示例#2
0
    def test_add_without_root_should_add_root(self):
        entry_bounds = Rectangle(Point(10, 10), Point(20, 0))
        entry = Entry(name='Tank', bounds=entry_bounds)
        r_tree = RTree(2, 4)
        r_tree.add(entry)

        self.assertIsNotNone(r_tree.root)
        self.assertIsInstance(r_tree.root, RTree.RTreeNode)
        self.assertEqual(r_tree.root.mbr, Rectangle.containing(entry_bounds))
        self.assertEqual(len(r_tree.root.entries), 1)
        self.assertEqual(r_tree.root.entries[0], entry)
示例#3
0
    def test_containing(self):
        """
        The class method containing() should return a
            Rectangle object that can contain the passed rectangle
        """
        expected_tl = Point(self.rect_a.top_left.x - Point.MOVE_DISTANCE,
                            self.rect_a.top_left.y + Point.MOVE_DISTANCE)
        expected_br = Point(self.rect_a.bottom_right.x + Point.MOVE_DISTANCE,
                            self.rect_a.bottom_right.y - Point.MOVE_DISTANCE)
        expected_rectangle = Rectangle(top_left=expected_tl,
                                       bottom_right=expected_br)

        self.assertEqual(expected_rectangle, Rectangle.containing(self.rect_a))
示例#4
0
 def add(self, object: Entry):
     if self.root is None:
         self.root: self.RTreeNode = self.RTreeNode(mbr=Rectangle.containing(object.mbr),
                                                    min_order=self.minimum_order, max_order=self.maximum_order)
     self.root.add(object)