Home | History | Annotate | Download | only in geometry
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Defines a hierarchical bounding rectangle data structure for Rect objects,
      6 // associated with a generic unique key K for efficient spatial queries. The
      7 // R*-tree algorithm is used to build the trees. Based on the papers:
      8 //
      9 // A Guttman 'R-trees:  a dynamic index structure for spatial searching', Proc
     10 // ACM SIGMOD Int Conf on Management of Data, 47-57, 1984
     11 //
     12 // N Beckmann, H-P Kriegel, R Schneider, B Seeger 'The R*-tree: an efficient and
     13 // robust access method for points and rectangles', Proc ACM SIGMOD Int Conf on
     14 // Management of Data, 322-331, 1990
     15 
     16 #ifndef UI_GFX_GEOMETRY_R_TREE_H_
     17 #define UI_GFX_GEOMETRY_R_TREE_H_
     18 
     19 #include "r_tree_base.h"
     20 
     21 namespace gfx {
     22 
     23 template <typename Key>
     24 class RTree : public RTreeBase {
     25  public:
     26   typedef base::hash_set<Key> Matches;
     27 
     28   // RTrees organize pairs of keys and rectangles in a hierarchical bounding
     29   // box structure. This allows for queries of the tree within logarithmic time.
     30   // |min_children| and |max_children| allows for adjustment of the average size
     31   // of the nodes within RTree, which adjusts the base of the logarithm in the
     32   // algorithm runtime. Some parts of insertion and deletion are polynomial
     33   // in the size of the individual node, so the trade-off with larger nodes is
     34   // potentially faster queries but slower insertions and deletions. Generally
     35   // it is worth considering how much overlap between rectangles of different
     36   // keys will occur in the tree, and trying to set |max_children| as a
     37   // reasonable upper bound to the number of overlapping rectangles expected.
     38   // Then |min_children| can bet set to a quantity slightly less than half of
     39   // that.
     40   RTree(size_t min_children, size_t max_children);
     41   ~RTree();
     42 
     43   // Insert a new rect into the tree, associated with provided key. Note that if
     44   // |rect| is empty, the |key| will not actually be inserted. Duplicate keys
     45   // overwrite old entries.
     46   void Insert(const Rect& rect, Key key);
     47 
     48   // If present, remove the supplied |key| from the tree.
     49   void Remove(Key key);
     50 
     51   // Fills |matches_out| with all keys having bounding rects intersecting
     52   // |query_rect|.
     53   void AppendIntersectingRecords(const Rect& query_rect,
     54                                  Matches* matches_out) const;
     55 
     56   void Clear();
     57 
     58  private:
     59   friend class RTreeTest;
     60   friend class RTreeNodeTest;
     61 
     62   class Record : public RecordBase {
     63    public:
     64     Record(const Rect& rect, const Key& key);
     65     virtual ~Record();
     66     const Key& key() const { return key_; }
     67 
     68    private:
     69     Key key_;
     70 
     71     DISALLOW_COPY_AND_ASSIGN(Record);
     72   };
     73 
     74   // A map of supplied keys to their Node representation within the RTree, for
     75   // efficient retrieval of keys without requiring a bounding rect.
     76   typedef base::hash_map<Key, Record*> RecordMap;
     77   RecordMap record_map_;
     78 
     79   DISALLOW_COPY_AND_ASSIGN(RTree);
     80 };
     81 
     82 template <typename Key>
     83 RTree<Key>::RTree(size_t min_children, size_t max_children)
     84     : RTreeBase(min_children, max_children) {
     85 }
     86 
     87 template <typename Key>
     88 RTree<Key>::~RTree() {
     89 }
     90 
     91 template <typename Key>
     92 void RTree<Key>::Insert(const Rect& rect, Key key) {
     93   scoped_ptr<NodeBase> record;
     94   // Check if this key is already present in the tree.
     95   typename RecordMap::iterator it(record_map_.find(key));
     96 
     97   if (it != record_map_.end()) {
     98     // We will re-use this node structure, regardless of re-insert or return.
     99     Record* existing_record = it->second;
    100     // If the new rect and the current rect are identical we can skip the rest
    101     // of Insert() as nothing has changed.
    102     if (existing_record->rect() == rect)
    103       return;
    104 
    105     // Remove the node from the tree in its current position.
    106     record = RemoveNode(existing_record);
    107 
    108     PruneRootIfNecessary();
    109 
    110     // If we are replacing this key with an empty rectangle we just remove the
    111     // old node from the list and return, thus preventing insertion of empty
    112     // rectangles into our spatial database.
    113     if (rect.IsEmpty()) {
    114       record_map_.erase(it);
    115       return;
    116     }
    117 
    118     // Reset the rectangle to the new value.
    119     record->set_rect(rect);
    120   } else {
    121     if (rect.IsEmpty())
    122       return;
    123 
    124     record.reset(new Record(rect, key));
    125     record_map_.insert(std::make_pair(key, static_cast<Record*>(record.get())));
    126   }
    127 
    128   int highest_reinsert_level = -1;
    129   InsertNode(record.Pass(), &highest_reinsert_level);
    130 }
    131 
    132 template <typename Key>
    133 void RTree<Key>::Clear() {
    134   record_map_.clear();
    135   ResetRoot();
    136 }
    137 
    138 template <typename Key>
    139 void RTree<Key>::Remove(Key key) {
    140   // Search the map for the leaf parent that has the provided record.
    141   typename RecordMap::iterator it = record_map_.find(key);
    142   if (it == record_map_.end())
    143     return;
    144 
    145   Record* record = it->second;
    146   record_map_.erase(it);
    147   RemoveNode(record);
    148 
    149   // Lastly check the root. If it has only one non-leaf child, delete it and
    150   // replace it with its child.
    151   PruneRootIfNecessary();
    152 }
    153 
    154 template <typename Key>
    155 void RTree<Key>::AppendIntersectingRecords(
    156       const Rect& query_rect, Matches* matches_out) const {
    157   RTreeBase::Records matching_records;
    158   root()->AppendIntersectingRecords(query_rect, &matching_records);
    159   for (RTreeBase::Records::const_iterator it = matching_records.begin();
    160        it != matching_records.end();
    161        ++it) {
    162     const Record* record = static_cast<const Record*>(*it);
    163     matches_out->insert(record->key());
    164   }
    165 }
    166 
    167 
    168 // RTree::Record --------------------------------------------------------------
    169 
    170 template <typename Key>
    171 RTree<Key>::Record::Record(const Rect& rect, const Key& key)
    172     : RecordBase(rect),
    173       key_(key) {
    174 }
    175 
    176 template <typename Key>
    177 RTree<Key>::Record::~Record() {
    178 }
    179 
    180 }  // namespace gfx
    181 
    182 #endif  // UI_GFX_GEOMETRY_R_TREE_H_
    183