// 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 #include #include #include #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 void Build(const Container& items, const Functor& bounds_getter) { DCHECK_EQ(0u, num_data_elements_); std::vector 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 void Build(const Container& items) { Build(items, [](const gfx::Rect& bounds) { return bounds; }); } void Search(const gfx::Rect& query, std::vector* results) const; // Equivalent, behaviorally, to checking if |Search| added anything to // |results|. This is faster, however. bool ContainsItemInRect(const gfx::Rect& query) 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* results) const; bool ContainsItemInRectRecursive(Node* node, const gfx::Rect& query) const; // Consumes the input array. Branch BuildRecursive(std::vector* 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 nodes_; }; } // namespace cc #endif // CC_BASE_RTREE_H_