| // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CC_BASE_RTREE_H_ |
| #define CC_BASE_RTREE_H_ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <deque> |
| #include <vector> |
| |
| #include "cc/base/cc_export.h" |
| #include "ui/gfx/geometry/rect.h" |
| |
| namespace cc { |
| |
| // The following description and most of the implementation is borrowed from |
| // Skia's SkRTree implementation. |
| // |
| // An R-Tree implementation. In short, it is a balanced n-ary tree containing a |
| // hierarchy of bounding rectangles. |
| // |
| // It only supports bulk-loading, i.e. creation from a batch of bounding |
| // rectangles. This performs a bottom-up bulk load using the STR |
| // (sort-tile-recursive) algorithm. |
| // |
| // Things to do: Experiment with other bulk-load algorithms (in particular the |
| // Hilbert pack variant, which groups rects by position on the Hilbert curve, is |
| // probably worth a look). There also exist top-down bulk load variants |
| // (VAMSplit, TopDownGreedy, etc). |
| // |
| // For more details see: |
| // |
| // Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). |
| // "The R*-tree: an efficient and robust access method for points and |
| // rectangles" |
| class CC_EXPORT RTree { |
| public: |
| RTree(); |
| ~RTree(); |
| |
| template <typename Container, typename Functor> |
| void Build(const Container& items, const Functor& bounds_getter) { |
| DCHECK_EQ(0u, num_data_elements_); |
| |
| std::vector<Branch> branches; |
| branches.reserve(items.size()); |
| |
| for (size_t i = 0; i < items.size(); i++) { |
| const gfx::Rect& bounds = bounds_getter(items[i]); |
| if (bounds.IsEmpty()) |
| continue; |
| |
| branches.push_back(Branch()); |
| Branch& branch = branches.back(); |
| branch.bounds = bounds; |
| branch.index = i; |
| } |
| |
| num_data_elements_ = branches.size(); |
| if (num_data_elements_ == 1u) { |
| Node* node = AllocateNodeAtLevel(0); |
| node->num_children = 1; |
| node->children[0] = branches[0]; |
| root_.subtree = node; |
| root_.bounds = branches[0].bounds; |
| } else if (num_data_elements_ > 1u) { |
| root_ = BuildRecursive(&branches, 0); |
| } |
| } |
| |
| template <typename Container> |
| void Build(const Container& items) { |
| Build(items, [](const gfx::Rect& bounds) { return bounds; }); |
| } |
| |
| void Search(const gfx::Rect& query, std::vector<size_t>* results) const; |
| |
| gfx::Rect GetBounds() const; |
| |
| private: |
| // These values were empirically determined to produce reasonable performance |
| // in most cases. |
| enum { MIN_CHILDREN = 6, MAX_CHILDREN = 11 }; |
| |
| struct Node; |
| struct Branch { |
| // When the node level is 0, then the node is a leaf and the branch has a |
| // valid index pointing to an element in the vector that was used to build |
| // this rtree. When the level is not 0, it's an internal node and it has a |
| // valid subtree pointer. |
| union { |
| Node* subtree; |
| size_t index; |
| }; |
| gfx::Rect bounds; |
| }; |
| |
| struct Node { |
| uint16_t num_children; |
| uint16_t level; |
| Branch children[MAX_CHILDREN]; |
| }; |
| |
| void SearchRecursive(Node* root, |
| const gfx::Rect& query, |
| std::vector<size_t>* results) const; |
| |
| // Consumes the input array. |
| Branch BuildRecursive(std::vector<Branch>* branches, int level); |
| Node* AllocateNodeAtLevel(int level); |
| |
| // This is the count of data elements (rather than total nodes in the tree) |
| size_t num_data_elements_; |
| Branch root_; |
| std::deque<Node> nodes_; |
| }; |
| |
| } // namespace cc |
| |
| #endif // CC_BASE_RTREE_H_ |