OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "testing/gtest/include/gtest/gtest.h" | 5 #include "testing/gtest/include/gtest/gtest.h" |
6 #include "ui/gfx/geometry/r_tree.h" | 6 #include "ui/gfx/geometry/r_tree.h" |
7 #include "ui/gfx/geometry/r_tree_base.h" | |
8 #include "ui/gfx/geometry/rect.h" | 7 #include "ui/gfx/geometry/rect.h" |
9 | 8 |
10 namespace gfx { | 9 namespace gfx { |
11 | 10 |
12 class RTreeTest : public ::testing::Test { | 11 class RTreeTest : public ::testing::Test { |
13 protected: | 12 protected: |
14 typedef RTree<int> RT; | 13 // Given a pointer to an RTree, traverse it and verify its internal structure |
15 | 14 // is consistent with the RTree semantics. |
16 // Given a pointer to an RTree, traverse it and verify that its internal | 15 void ValidateRTree(RTree* rt) { |
17 // structure is consistent with RTree semantics. | |
18 void ValidateRTree(RTreeBase* rt) { | |
19 // If RTree is empty it should have an empty rectangle. | 16 // If RTree is empty it should have an empty rectangle. |
20 if (!rt->root()->count()) { | 17 if (!rt->root_->count()) { |
21 EXPECT_TRUE(rt->root()->rect().IsEmpty()); | 18 EXPECT_TRUE(rt->root_->rect().IsEmpty()); |
22 EXPECT_EQ(0, rt->root()->Level()); | 19 EXPECT_EQ(rt->root_->level(), 0); |
23 return; | 20 return; |
24 } | 21 } |
25 // Root is allowed to have fewer than min_children_ but never more than | 22 // Root is allowed to have fewer than min_children_ but never more than |
26 // max_children_. | 23 // max_children_. |
27 EXPECT_LE(rt->root()->count(), rt->max_children_); | 24 EXPECT_LE(rt->root_->count(), rt->max_children_); |
28 // The root should never be a record node. | 25 // The root should never be a record node. |
29 EXPECT_GT(rt->root()->Level(), -1); | 26 EXPECT_GT(rt->root_->level(), -1); |
| 27 EXPECT_FALSE(rt->root_->key()); |
30 // The root should never have a parent pointer. | 28 // The root should never have a parent pointer. |
31 EXPECT_TRUE(rt->root()->parent() == NULL); | 29 EXPECT_FALSE(rt->root_->parent()); |
32 // Bounds must be consistent on the root. | 30 // Bounds must be consistent on the root. |
33 CheckBoundsConsistent(rt->root()); | 31 CheckBoundsConsistent(rt->root_.get()); |
34 for (size_t i = 0; i < rt->root()->count(); ++i) { | 32 // We traverse root's children ourselves, so we can avoid asserts about |
| 33 // root's potential inconsistencies. |
| 34 for (size_t i = 0; i < rt->root_->children_.size(); ++i) { |
35 ValidateNode( | 35 ValidateNode( |
36 rt->root()->child(i), rt->min_children_, rt->max_children_); | 36 rt->root_->children_[i], rt->min_children_, rt->max_children_); |
37 } | 37 } |
38 } | 38 } |
39 | 39 |
40 // Recursive descent method used by ValidateRTree to check each node within | 40 // Recursive descent method used by ValidateRTree to check each node within |
41 // the RTree for consistency with RTree semantics. | 41 // the RTree for consistency with RTree semantics. |
42 void ValidateNode(const RTreeBase::NodeBase* node_base, | 42 void ValidateNode(RTree::Node* node, |
43 size_t min_children, | 43 size_t min_children, |
44 size_t max_children) { | 44 size_t max_children) { |
45 if (node_base->Level() >= 0) { | 45 // Record nodes have different requirements, handle up front. |
46 const RTreeBase::Node* node = | 46 if (node->level() == -1) { |
47 static_cast<const RTreeBase::Node*>(node_base); | 47 // Record nodes may have no children. |
48 EXPECT_GE(node->count(), min_children); | 48 EXPECT_EQ(node->count(), 0U); |
49 EXPECT_LE(node->count(), max_children); | 49 // They must have an associated non-NULL key. |
50 CheckBoundsConsistent(node); | 50 EXPECT_TRUE(node->key()); |
51 for (size_t i = 0; i < node->count(); ++i) | 51 // They must always have a parent. |
52 ValidateNode(node->child(i), min_children, max_children); | 52 EXPECT_TRUE(node->parent()); |
| 53 return; |
| 54 } |
| 55 // Non-record node, normal expectations apply. |
| 56 EXPECT_GE(node->count(), min_children); |
| 57 EXPECT_LE(node->count(), max_children); |
| 58 EXPECT_EQ(node->key(), 0); |
| 59 CheckBoundsConsistent(node); |
| 60 for (size_t i = 0; i < node->children_.size(); ++i) { |
| 61 ValidateNode(node->children_[i], min_children, max_children); |
53 } | 62 } |
54 } | 63 } |
55 | 64 |
56 // Check bounds are consistent with children bounds, and other checks | 65 // Check bounds are consistent with children bounds, and other checks |
57 // convenient to do while enumerating the children of node. | 66 // convenient to do while enumerating the children of node. |
58 void CheckBoundsConsistent(const RTreeBase::Node* node) { | 67 void CheckBoundsConsistent(RTree::Node* node) { |
59 EXPECT_FALSE(node->rect().IsEmpty()); | 68 EXPECT_FALSE(node->rect_.IsEmpty()); |
60 Rect check_bounds; | 69 Rect check_bounds; |
61 for (size_t i = 0; i < node->count(); ++i) { | 70 for (size_t i = 0; i < node->children_.size(); ++i) { |
62 const RTreeBase::NodeBase* child_node = node->child(i); | 71 RTree::Node* child_node = node->children_[i]; |
63 check_bounds.Union(child_node->rect()); | 72 check_bounds.Union(child_node->rect()); |
64 EXPECT_EQ(node->Level() - 1, child_node->Level()); | 73 EXPECT_EQ(node->level() - 1, child_node->level()); |
65 EXPECT_EQ(node, child_node->parent()); | 74 EXPECT_EQ(node, child_node->parent()); |
66 } | 75 } |
67 EXPECT_EQ(check_bounds, node->rect()); | 76 EXPECT_EQ(node->rect_, check_bounds); |
68 } | 77 } |
69 | 78 |
70 // Adds count squares stacked around the point (0,0) with key equal to width. | 79 // Adds count squares stacked around the point (0,0) with key equal to width. |
71 void AddStackedSquares(RT* rt, int count) { | 80 void AddStackedSquares(RTree* rt, int count) { |
72 for (int i = 1; i <= count; ++i) { | 81 for (int i = 1; i <= count; ++i) { |
73 rt->Insert(Rect(0, 0, i, i), i); | 82 rt->Insert(Rect(0, 0, i, i), i); |
74 ValidateRTree(static_cast<RTreeBase*>(rt)); | 83 ValidateRTree(rt); |
75 } | 84 } |
76 } | 85 } |
77 | 86 |
78 // Given an unordered list of matching keys, verifies that it contains all | 87 // Given an unordered list of matching keys, verify that it contains all |
79 // values [1..length] for the length of that list. | 88 // values [1..length] for the length of that list. |
80 void VerifyAllKeys(const RT::Matches& keys) { | 89 void VerifyAllKeys(const base::hash_set<intptr_t>& keys) { |
81 for (size_t i = 1; i <= keys.size(); ++i) | 90 // Verify that the keys are in values [1,count]. |
82 EXPECT_EQ(1U, keys.count(i)); | 91 for (size_t i = 1; i <= keys.size(); ++i) { |
| 92 EXPECT_EQ(keys.count(i), 1U); |
| 93 } |
83 } | 94 } |
84 | 95 |
85 // Given a node and a rectangle, builds an expanded rectangle list where the | 96 // Given a node and a rectangle, builds an expanded rectangle list where the |
86 // ith element of the vector is the union of the rectangle of the ith child of | 97 // ith element of the rectangle is union of the recangle of the ith child of |
87 // the node and the argument rectangle. | 98 // the node and the argument rectangle. |
88 void BuildExpandedRects(RTreeBase::Node* node, | 99 void BuildExpandedRects(RTree::Node* node, |
89 const Rect& rect, | 100 const Rect& rect, |
90 std::vector<Rect>* expanded_rects) { | 101 std::vector<Rect>* expanded_rects) { |
91 expanded_rects->clear(); | 102 expanded_rects->clear(); |
92 expanded_rects->reserve(node->count()); | 103 expanded_rects->reserve(node->children_.size()); |
93 for (size_t i = 0; i < node->count(); ++i) { | 104 for (size_t i = 0; i < node->children_.size(); ++i) { |
94 Rect expanded_rect(rect); | 105 Rect expanded_rect(rect); |
95 expanded_rect.Union(node->child(i)->rect()); | 106 expanded_rect.Union(node->children_[i]->rect_); |
96 expanded_rects->push_back(expanded_rect); | 107 expanded_rects->push_back(expanded_rect); |
97 } | 108 } |
98 } | 109 } |
99 }; | 110 }; |
100 | 111 |
101 class RTreeNodeTest : public RTreeTest { | 112 // An empty RTree should never return Query results, and RTrees should be empty |
102 protected: | 113 // upon construction. |
103 typedef RTreeBase::NodeBase RTreeNodeBase; | 114 TEST_F(RTreeTest, QueryEmptyTree) { |
104 typedef RT::Record RTreeRecord; | 115 RTree rt(2, 10); |
105 typedef RTreeBase::Node RTreeNode; | 116 ValidateRTree(&rt); |
106 typedef RTreeBase::Node::Rects RTreeRects; | 117 base::hash_set<intptr_t> results; |
107 typedef RTreeBase::Nodes RTreeNodes; | 118 Rect test_rect(25, 25); |
108 | 119 rt.Query(test_rect, &results); |
109 // Accessors to private members of RTree::Node. | 120 EXPECT_EQ(results.size(), 0U); |
110 const RTreeRecord* record(RTreeNode* node, size_t i) { | 121 ValidateRTree(&rt); |
111 return static_cast<const RTreeRecord*>(node->child(i)); | 122 } |
112 } | 123 |
113 | 124 // Clear should empty the tree, meaning that all queries should not return |
114 // Provides access for tests to private methods of RTree::Node. | 125 // results after. |
115 scoped_ptr<RTreeNode> NewNodeAtLevel(size_t level) { | 126 TEST_F(RTreeTest, ClearEmptiesTreeOfSingleNode) { |
116 return make_scoped_ptr(new RTreeBase::Node(level)); | 127 RTree rt(2, 5); |
117 } | 128 rt.Insert(Rect(0, 0, 100, 100), 1); |
118 | 129 rt.Clear(); |
119 void NodeRecomputeLocalBounds(RTreeNodeBase* node) { | 130 base::hash_set<intptr_t> results; |
120 node->RecomputeLocalBounds(); | 131 Rect test_rect(1, 1); |
121 } | 132 rt.Query(test_rect, &results); |
122 | 133 EXPECT_EQ(results.size(), 0U); |
123 bool NodeCompareVertical(RTreeNodeBase* a, RTreeNodeBase* b) { | 134 ValidateRTree(&rt); |
124 return RTreeBase::Node::CompareVertical(a, b); | 135 } |
125 } | 136 |
126 | 137 // Even with a complex internal structure, clear should empty the tree, meaning |
127 bool NodeCompareHorizontal(RTreeNodeBase* a, RTreeNodeBase* b) { | 138 // that all queries should not return results after. |
128 return RTreeBase::Node::CompareHorizontal(a, b); | 139 TEST_F(RTreeTest, ClearEmptiesTreeOfManyNodes) { |
129 } | 140 RTree rt(2, 5); |
130 | 141 AddStackedSquares(&rt, 100); |
131 bool NodeCompareCenterDistanceFromParent( | 142 rt.Clear(); |
132 const RTreeNodeBase* a, const RTreeNodeBase* b) { | 143 base::hash_set<intptr_t> results; |
133 return RTreeBase::Node::CompareCenterDistanceFromParent(a, b); | 144 Rect test_rect(1, 1); |
134 } | 145 rt.Query(test_rect, &results); |
135 | 146 EXPECT_EQ(results.size(), 0U); |
136 int NodeOverlapIncreaseToAdd(RTreeNode* node, | 147 ValidateRTree(&rt); |
137 const Rect& rect, | 148 } |
138 const RTreeNodeBase* candidate_node, | 149 |
139 const Rect& expanded_rect) { | 150 // Duplicate inserts should overwrite previous inserts. |
140 return node->OverlapIncreaseToAdd(rect, candidate_node, expanded_rect); | 151 TEST_F(RTreeTest, DuplicateInsertsOverwrite) { |
141 } | 152 RTree rt(2, 5); |
142 | 153 // Add 100 stacked squares, but always with duplicate key of 1. |
143 void NodeBuildLowBounds(const std::vector<RTreeNodeBase*>& vertical_sort, | 154 for (int i = 1; i <= 100; ++i) { |
144 const std::vector<RTreeNodeBase*>& horizontal_sort, | 155 rt.Insert(Rect(0, 0, i, i), 1); |
145 RTreeRects* vertical_bounds, | 156 ValidateRTree(&rt); |
146 RTreeRects* horizontal_bounds) { | 157 } |
147 RTreeBase::Node::BuildLowBounds( | 158 base::hash_set<intptr_t> results; |
148 vertical_sort, horizontal_sort, vertical_bounds, horizontal_bounds); | 159 Rect test_rect(1, 1); |
149 } | 160 rt.Query(test_rect, &results); |
150 | 161 EXPECT_EQ(results.size(), 1U); |
151 void NodeBuildHighBounds(const std::vector<RTreeNodeBase*>& vertical_sort, | 162 EXPECT_EQ(results.count(1), 1U); |
152 const std::vector<RTreeNodeBase*>& horizontal_sort, | 163 } |
153 RTreeRects* vertical_bounds, | 164 |
154 RTreeRects* horizontal_bounds) { | 165 // Call Remove() once on something that's been inserted repeatedly. |
155 RTreeBase::Node::BuildHighBounds( | 166 TEST_F(RTreeTest, DuplicateInsertRemove) { |
156 vertical_sort, horizontal_sort, vertical_bounds, horizontal_bounds); | 167 RTree rt(3, 9); |
157 } | 168 AddStackedSquares(&rt, 25); |
158 | 169 for (int i = 1; i <= 100; ++i) { |
159 int NodeSmallestMarginSum(size_t start_index, | 170 rt.Insert(Rect(0, 0, i, i), 26); |
160 size_t end_index, | 171 ValidateRTree(&rt); |
161 const RTreeRects& low_bounds, | 172 } |
162 const RTreeRects& high_bounds) { | 173 rt.Remove(26); |
163 return RTreeBase::Node::SmallestMarginSum( | 174 base::hash_set<intptr_t> results; |
164 start_index, end_index, low_bounds, high_bounds); | 175 Rect test_rect(1, 1); |
165 } | 176 rt.Query(test_rect, &results); |
166 | 177 EXPECT_EQ(results.size(), 25U); |
167 size_t NodeChooseSplitIndex(size_t min_children, | 178 VerifyAllKeys(results); |
168 size_t max_children, | 179 } |
169 const RTreeRects& low_bounds, | 180 |
170 const RTreeRects& high_bounds) { | 181 // Call Remove() repeatedly on something that's been inserted once. |
171 return RTreeBase::Node::ChooseSplitIndex( | 182 TEST_F(RTreeTest, InsertDuplicateRemove) { |
172 min_children, max_children, low_bounds, high_bounds); | 183 RTree rt(7, 15); |
173 } | 184 AddStackedSquares(&rt, 101); |
174 | 185 for (int i = 0; i < 100; ++i) { |
175 scoped_ptr<RTreeNodeBase> NodeDivideChildren( | 186 rt.Remove(101); |
176 RTreeNode* node, | 187 ValidateRTree(&rt); |
177 const RTreeRects& low_bounds, | 188 } |
178 const RTreeRects& high_bounds, | 189 base::hash_set<intptr_t> results; |
179 const std::vector<RTreeNodeBase*>& sorted_children, | 190 Rect test_rect(1, 1); |
180 size_t split_index) { | 191 rt.Query(test_rect, &results); |
181 return node->DivideChildren( | 192 EXPECT_EQ(results.size(), 100U); |
182 low_bounds, high_bounds, sorted_children, split_index); | 193 VerifyAllKeys(results); |
183 } | 194 } |
184 | 195 |
185 RTreeNode* NodeLeastOverlapIncrease(RTreeNode* node, | 196 // Stacked rects should meet all matching queries regardless of nesting. |
186 const Rect& node_rect, | 197 TEST_F(RTreeTest, QueryStackedSquaresNestedHit) { |
187 const RTreeRects& expanded_rects) { | 198 RTree rt(2, 5); |
188 return node->LeastOverlapIncrease(node_rect, expanded_rects); | 199 AddStackedSquares(&rt, 100); |
189 } | 200 base::hash_set<intptr_t> results; |
190 | 201 Rect test_rect(1, 1); |
191 RTreeNode* NodeLeastAreaEnlargement(RTreeNode* node, | 202 rt.Query(test_rect, &results); |
192 const Rect& node_rect, | 203 EXPECT_EQ(results.size(), 100U); |
193 const RTreeRects& expanded_rects) { | 204 VerifyAllKeys(results); |
194 return node->LeastAreaEnlargement(node_rect, expanded_rects); | 205 } |
195 } | 206 |
196 }; | 207 // Stacked rects should meet all matching queries when contained completely by |
197 | 208 // the query rectangle. |
198 // RTreeNodeTest -------------------------------------------------------------- | 209 TEST_F(RTreeTest, QueryStackedSquaresContainedHit) { |
199 | 210 RTree rt(2, 10); |
200 TEST_F(RTreeNodeTest, RemoveNodesForReinsert) { | 211 AddStackedSquares(&rt, 100); |
| 212 base::hash_set<intptr_t> results; |
| 213 Rect test_rect(0, 0, 100, 100); |
| 214 rt.Query(test_rect, &results); |
| 215 EXPECT_EQ(results.size(), 100U); |
| 216 VerifyAllKeys(results); |
| 217 } |
| 218 |
| 219 // Stacked rects should miss a missing query when the query has no intersection |
| 220 // with the rects. |
| 221 TEST_F(RTreeTest, QueryStackedSquaresCompleteMiss) { |
| 222 RTree rt(2, 7); |
| 223 AddStackedSquares(&rt, 100); |
| 224 base::hash_set<intptr_t> results; |
| 225 Rect test_rect(150, 150, 100, 100); |
| 226 rt.Query(test_rect, &results); |
| 227 EXPECT_EQ(results.size(), 0U); |
| 228 } |
| 229 |
| 230 // Removing half the nodes after insertion should still result in a valid tree. |
| 231 TEST_F(RTreeTest, RemoveHalfStackedRects) { |
| 232 RTree rt(2, 11); |
| 233 AddStackedSquares(&rt, 200); |
| 234 for (int i = 101; i <= 200; ++i) { |
| 235 rt.Remove(i); |
| 236 ValidateRTree(&rt); |
| 237 } |
| 238 base::hash_set<intptr_t> results; |
| 239 Rect test_rect(1, 1); |
| 240 rt.Query(test_rect, &results); |
| 241 EXPECT_EQ(results.size(), 100U); |
| 242 VerifyAllKeys(results); |
| 243 // Add the nodes back in. |
| 244 for (int i = 101; i <= 200; ++i) { |
| 245 rt.Insert(Rect(0, 0, i, i), i); |
| 246 ValidateRTree(&rt); |
| 247 } |
| 248 results.clear(); |
| 249 rt.Query(test_rect, &results); |
| 250 EXPECT_EQ(results.size(), 200U); |
| 251 VerifyAllKeys(results); |
| 252 } |
| 253 |
| 254 TEST_F(RTreeTest, InsertDupToRoot) { |
| 255 RTree rt(2, 5); |
| 256 rt.Insert(Rect(0, 0, 1, 2), 1); |
| 257 ValidateRTree(&rt); |
| 258 rt.Insert(Rect(0, 0, 2, 1), 1); |
| 259 ValidateRTree(&rt); |
| 260 } |
| 261 |
| 262 TEST_F(RTreeTest, InsertNegativeCoordsRect) { |
| 263 RTree rt(5, 11); |
| 264 for (int i = 1; i <= 100; ++i) { |
| 265 rt.Insert(Rect(-i, -i, i, i), (i * 2) - 1); |
| 266 ValidateRTree(&rt); |
| 267 rt.Insert(Rect(0, 0, i, i), i * 2); |
| 268 ValidateRTree(&rt); |
| 269 } |
| 270 base::hash_set<intptr_t> results; |
| 271 Rect test_rect(-1, -1, 2, 2); |
| 272 rt.Query(test_rect, &results); |
| 273 EXPECT_EQ(results.size(), 200U); |
| 274 VerifyAllKeys(results); |
| 275 } |
| 276 |
| 277 TEST_F(RTreeTest, RemoveNegativeCoordsRect) { |
| 278 RTree rt(7, 21); |
| 279 // Add 100 positive stacked squares. |
| 280 AddStackedSquares(&rt, 100); |
| 281 // Now add 100 negative stacked squares. |
| 282 for (int i = 101; i <= 200; ++i) { |
| 283 rt.Insert(Rect(100 - i, 100 - i, i - 100, i - 100), 301 - i); |
| 284 ValidateRTree(&rt); |
| 285 } |
| 286 // Now remove half of the negative squares. |
| 287 for (int i = 101; i <= 150; ++i) { |
| 288 rt.Remove(301 - i); |
| 289 ValidateRTree(&rt); |
| 290 } |
| 291 // Queries should return 100 positive and 50 negative stacked squares. |
| 292 base::hash_set<intptr_t> results; |
| 293 Rect test_rect(-1, -1, 2, 2); |
| 294 rt.Query(test_rect, &results); |
| 295 EXPECT_EQ(results.size(), 150U); |
| 296 VerifyAllKeys(results); |
| 297 } |
| 298 |
| 299 TEST_F(RTreeTest, InsertEmptyRectReplacementRemovesKey) { |
| 300 RTree rt(10, 31); |
| 301 AddStackedSquares(&rt, 50); |
| 302 ValidateRTree(&rt); |
| 303 |
| 304 // Replace last square with empty rect. |
| 305 rt.Insert(Rect(), 50); |
| 306 ValidateRTree(&rt); |
| 307 |
| 308 // Now query large area to get all rects in tree. |
| 309 base::hash_set<intptr_t> results; |
| 310 Rect test_rect(0, 0, 100, 100); |
| 311 rt.Query(test_rect, &results); |
| 312 |
| 313 // Should only be 49 rects in tree. |
| 314 EXPECT_EQ(results.size(), 49U); |
| 315 VerifyAllKeys(results); |
| 316 } |
| 317 |
| 318 TEST_F(RTreeTest, NodeRemoveNodesForReinsert) { |
201 // Make a leaf node for testing removal from. | 319 // Make a leaf node for testing removal from. |
202 scoped_ptr<RTreeNode> test_node(new RTreeNode); | 320 scoped_ptr<RTree::Node> test_node(new RTree::Node(0)); |
203 // Build 20 record nodes with rectangle centers going from (1,1) to (20,20) | 321 // Build 20 record nodes with rectangle centers going from (1,1) to (20,20) |
204 for (int i = 1; i <= 20; ++i) | 322 for (int i = 1; i <= 20; ++i) { |
205 test_node->AddChild(scoped_ptr<RTreeNodeBase>( | 323 test_node->AddChild(new RTree::Node(Rect(i - 1, i - 1, 2, 2), i)); |
206 new RTreeRecord(Rect(i - 1, i - 1, 2, 2), i))); | 324 } |
207 | |
208 // Quick verification of the node before removing children. | 325 // Quick verification of the node before removing children. |
209 ValidateNode(test_node.get(), 1U, 20U); | 326 ValidateNode(test_node.get(), 1U, 20U); |
210 // Use a scoped vector to delete all children that get removed from the Node. | 327 // Use a scoped vector to delete all children that get removed from the Node. |
211 RTreeNodes removals; | 328 ScopedVector<RTree::Node> removals; |
212 test_node->RemoveNodesForReinsert(1, &removals); | 329 test_node->RemoveNodesForReinsert(1, &removals); |
213 // Should have gotten back 1 node pointer. | 330 // Should have gotten back 1 node pointers. |
214 EXPECT_EQ(1U, removals.size()); | 331 EXPECT_EQ(removals.size(), 1U); |
215 // There should be 19 left in the test_node. | 332 // There should be 19 left in the test_node. |
216 EXPECT_EQ(19U, test_node->count()); | 333 EXPECT_EQ(test_node->count(), 19U); |
217 // If we fix up the bounds on the test_node, it should verify. | 334 // If we fix up the bounds on the test_node, it should verify. |
218 NodeRecomputeLocalBounds(test_node.get()); | 335 test_node->RecomputeBoundsNoParents(); |
219 ValidateNode(test_node.get(), 2U, 20U); | 336 ValidateNode(test_node.get(), 2U, 20U); |
220 // The node we removed should be node 10, as it was exactly in the center. | 337 // The node we removed should be node 10, as it was exactly in the center. |
221 EXPECT_EQ(10, static_cast<RTreeRecord*>(removals[0])->key()); | 338 EXPECT_EQ(removals[0]->key(), 10); |
222 | 339 |
223 // Now remove the next 2. | 340 // Now remove the next 2. |
224 removals.clear(); | 341 removals.clear(); |
225 test_node->RemoveNodesForReinsert(2, &removals); | 342 test_node->RemoveNodesForReinsert(2, &removals); |
226 EXPECT_EQ(2U, removals.size()); | 343 EXPECT_EQ(removals.size(), 2U); |
227 EXPECT_EQ(17U, test_node->count()); | 344 EXPECT_EQ(test_node->count(), 17U); |
228 NodeRecomputeLocalBounds(test_node.get()); | 345 test_node->RecomputeBoundsNoParents(); |
229 ValidateNode(test_node.get(), 2U, 20U); | 346 ValidateNode(test_node.get(), 2U, 20U); |
230 // Lastly the 2 nodes we should have gotten back are keys 9 and 11, as their | 347 // Lastly the 2 nodes we should have gotten back are keys 9 and 11, as their |
231 // centers were the closest to the center of the node bounding box. | 348 // centers were the closest to the center of the node bounding box. |
232 base::hash_set<intptr_t> results_hash; | 349 base::hash_set<intptr_t> results_hash; |
233 results_hash.insert(static_cast<RTreeRecord*>(removals[0])->key()); | 350 results_hash.insert(removals[0]->key()); |
234 results_hash.insert(static_cast<RTreeRecord*>(removals[1])->key()); | 351 results_hash.insert(removals[1]->key()); |
235 EXPECT_EQ(1U, results_hash.count(9)); | 352 EXPECT_EQ(results_hash.count(9), 1U); |
236 EXPECT_EQ(1U, results_hash.count(11)); | 353 EXPECT_EQ(results_hash.count(11), 1U); |
237 } | 354 } |
238 | 355 |
239 TEST_F(RTreeNodeTest, CompareVertical) { | 356 TEST_F(RTreeTest, NodeCompareVertical) { |
240 // One rect with lower y than another should always sort lower. | 357 // One rect with lower y than another should always sort lower than higher y. |
241 RTreeRecord low(Rect(0, 1, 10, 10), 1); | 358 RTree::Node low(Rect(0, 1, 10, 10), 1); |
242 RTreeRecord middle(Rect(0, 5, 10, 10), 5); | 359 RTree::Node middle(Rect(0, 5, 10, 10), 5); |
243 EXPECT_TRUE(NodeCompareVertical(&low, &middle)); | 360 EXPECT_TRUE(RTree::Node::CompareVertical(&low, &middle)); |
244 EXPECT_FALSE(NodeCompareVertical(&middle, &low)); | 361 EXPECT_FALSE(RTree::Node::CompareVertical(&middle, &low)); |
245 | 362 |
246 // Try a non-overlapping higher-y rectangle. | 363 // Try a non-overlapping higher-y rectangle. |
247 RTreeRecord high(Rect(-10, 20, 10, 1), 10); | 364 RTree::Node high(Rect(-10, 20, 10, 1), 10); |
248 EXPECT_TRUE(NodeCompareVertical(&low, &high)); | 365 EXPECT_TRUE(RTree::Node::CompareVertical(&low, &high)); |
249 EXPECT_FALSE(NodeCompareVertical(&high, &low)); | 366 EXPECT_FALSE(RTree::Node::CompareVertical(&high, &low)); |
250 | 367 |
251 // Ties are broken by lowest bottom y value. | 368 // Ties are broken by lowest bottom y value. |
252 RTreeRecord shorter_tie(Rect(10, 1, 100, 2), 2); | 369 RTree::Node shorter_tie(Rect(10, 1, 100, 2), 2); |
253 EXPECT_TRUE(NodeCompareVertical(&shorter_tie, &low)); | 370 EXPECT_TRUE(RTree::Node::CompareVertical(&shorter_tie, &low)); |
254 EXPECT_FALSE(NodeCompareVertical(&low, &shorter_tie)); | 371 EXPECT_FALSE(RTree::Node::CompareVertical(&low, &shorter_tie)); |
255 } | 372 } |
256 | 373 |
257 TEST_F(RTreeNodeTest, CompareHorizontal) { | 374 TEST_F(RTreeTest, NodeCompareHorizontal) { |
258 // One rect with lower x than another should always sort lower than higher x. | 375 // One rect with lower x than another should always sort lower than higher x. |
259 RTreeRecord low(Rect(1, 0, 10, 10), 1); | 376 RTree::Node low(Rect(1, 0, 10, 10), 1); |
260 RTreeRecord middle(Rect(5, 0, 10, 10), 5); | 377 RTree::Node middle(Rect(5, 0, 10, 10), 5); |
261 EXPECT_TRUE(NodeCompareHorizontal(&low, &middle)); | 378 EXPECT_TRUE(RTree::Node::CompareHorizontal(&low, &middle)); |
262 EXPECT_FALSE(NodeCompareHorizontal(&middle, &low)); | 379 EXPECT_FALSE(RTree::Node::CompareHorizontal(&middle, &low)); |
263 | 380 |
264 // Try a non-overlapping higher-x rectangle. | 381 // Try a non-overlapping higher-x rectangle. |
265 RTreeRecord high(Rect(20, -10, 1, 10), 10); | 382 RTree::Node high(Rect(20, -10, 1, 10), 10); |
266 EXPECT_TRUE(NodeCompareHorizontal(&low, &high)); | 383 EXPECT_TRUE(RTree::Node::CompareHorizontal(&low, &high)); |
267 EXPECT_FALSE(NodeCompareHorizontal(&high, &low)); | 384 EXPECT_FALSE(RTree::Node::CompareHorizontal(&high, &low)); |
268 | 385 |
269 // Ties are broken by lowest bottom x value. | 386 // Ties are broken by lowest bottom x value. |
270 RTreeRecord shorter_tie(Rect(1, 10, 2, 100), 2); | 387 RTree::Node shorter_tie(Rect(1, 10, 2, 100), 2); |
271 EXPECT_TRUE(NodeCompareHorizontal(&shorter_tie, &low)); | 388 EXPECT_TRUE(RTree::Node::CompareHorizontal(&shorter_tie, &low)); |
272 EXPECT_FALSE(NodeCompareHorizontal(&low, &shorter_tie)); | 389 EXPECT_FALSE(RTree::Node::CompareHorizontal(&low, &shorter_tie)); |
273 } | 390 } |
274 | 391 |
275 TEST_F(RTreeNodeTest, CompareCenterDistanceFromParent) { | 392 TEST_F(RTreeTest, NodeCompareCenterDistanceFromParent) { |
276 // Create a test node we can add children to, for distance comparisons. | 393 // Create a test node we can add children to, for distance comparisons. |
277 scoped_ptr<RTreeNode> parent(new RTreeNode); | 394 scoped_ptr<RTree::Node> parent(new RTree::Node(0)); |
278 | 395 |
279 // Add three children, one each with centers at (0, 0), (10, 10), (-9, -9), | 396 // Add three children, one each with centers at (0, 0), (10, 10), (-9, -9), |
280 // around which a bounding box will be centered at (0, 0) | 397 // around which a bounding box will be centered at (0, 0) |
281 scoped_ptr<RTreeRecord> center_zero(new RTreeRecord(Rect(-1, -1, 2, 2), 1)); | 398 RTree::Node* center_zero = new RTree::Node(Rect(-1, -1, 2, 2), 1); |
282 parent->AddChild(center_zero.PassAs<RTreeNodeBase>()); | 399 parent->AddChild(center_zero); |
283 | 400 |
284 scoped_ptr<RTreeRecord> center_positive(new RTreeRecord(Rect(9, 9, 2, 2), 2)); | 401 RTree::Node* center_positive = new RTree::Node(Rect(9, 9, 2, 2), 2); |
285 parent->AddChild(center_positive.PassAs<RTreeNodeBase>()); | 402 parent->AddChild(center_positive); |
286 | 403 |
287 scoped_ptr<RTreeRecord> center_negative( | 404 RTree::Node* center_negative = new RTree::Node(Rect(-10, -10, 2, 2), 3); |
288 new RTreeRecord(Rect(-10, -10, 2, 2), 3)); | 405 parent->AddChild(center_negative); |
289 parent->AddChild(center_negative.PassAs<RTreeNodeBase>()); | |
290 | 406 |
291 ValidateNode(parent.get(), 1U, 5U); | 407 ValidateNode(parent.get(), 1U, 5U); |
292 EXPECT_EQ(Rect(-10, -10, 21, 21), parent->rect()); | 408 EXPECT_EQ(parent->rect_, Rect(-10, -10, 21, 21)); |
293 | 409 |
294 EXPECT_TRUE( | 410 EXPECT_TRUE(RTree::Node::CompareCenterDistanceFromParent(center_zero, |
295 NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(1))); | 411 center_positive)); |
296 EXPECT_FALSE( | 412 EXPECT_FALSE(RTree::Node::CompareCenterDistanceFromParent(center_positive, |
297 NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(0))); | 413 center_zero)); |
298 EXPECT_TRUE( | 414 |
299 NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(2))); | 415 EXPECT_TRUE(RTree::Node::CompareCenterDistanceFromParent(center_zero, |
300 EXPECT_FALSE( | 416 center_negative)); |
301 NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(0))); | 417 EXPECT_FALSE(RTree::Node::CompareCenterDistanceFromParent(center_negative, |
302 EXPECT_TRUE( | 418 center_zero)); |
303 NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(1))); | 419 |
304 EXPECT_FALSE( | 420 EXPECT_TRUE(RTree::Node::CompareCenterDistanceFromParent(center_negative, |
305 NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(2))); | 421 center_positive)); |
306 } | 422 EXPECT_FALSE(RTree::Node::CompareCenterDistanceFromParent(center_positive, |
307 | 423 center_negative)); |
308 TEST_F(RTreeNodeTest, OverlapIncreaseToAdd) { | 424 } |
| 425 |
| 426 TEST_F(RTreeTest, NodeOverlapIncreaseToAdd) { |
309 // Create a test node with three children, for overlap comparisons. | 427 // Create a test node with three children, for overlap comparisons. |
310 scoped_ptr<RTreeNode> parent(new RTreeNode); | 428 scoped_ptr<RTree::Node> parent(new RTree::Node(0)); |
311 | 429 |
312 // Add three children, each 4 wide and tall, at (0, 0), (3, 3), (6, 6) with | 430 // Add three children, each 4 wide and tall, at (0, 0), (3, 3), (6, 6) with |
313 // overlapping corners. | 431 // overlapping corners. |
314 Rect top(0, 0, 4, 4); | 432 Rect top(0, 0, 4, 4); |
315 parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(top, 1))); | 433 parent->AddChild(new RTree::Node(top, 1)); |
316 Rect middle(3, 3, 4, 4); | 434 Rect middle(3, 3, 4, 4); |
317 parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(middle, 2))); | 435 parent->AddChild(new RTree::Node(middle, 2)); |
318 Rect bottom(6, 6, 4, 4); | 436 Rect bottom(6, 6, 4, 4); |
319 parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(bottom, 3))); | 437 parent->AddChild(new RTree::Node(bottom, 3)); |
320 ValidateNode(parent.get(), 1U, 5U); | 438 ValidateNode(parent.get(), 1U, 5U); |
321 | 439 |
322 // Test a rect in corner. | 440 // Test a rect in corner. |
323 Rect corner(0, 0, 1, 1); | 441 Rect corner(0, 0, 1, 1); |
324 Rect expanded = top; | 442 Rect expanded = top; |
325 expanded.Union(corner); | 443 expanded.Union(corner); |
326 // It should not add any overlap to add this to the first child at (0, 0). | 444 // It should not add any overlap to add this to the first child at (0, 0); |
327 EXPECT_EQ(0, NodeOverlapIncreaseToAdd( | 445 EXPECT_EQ(parent->OverlapIncreaseToAdd(corner, 0, expanded), 0); |
328 parent.get(), corner, parent->child(0), expanded)); | |
329 | 446 |
330 expanded = middle; | 447 expanded = middle; |
331 expanded.Union(corner); | 448 expanded.Union(corner); |
332 // Overlap for middle rectangle should increase from 2 pixels at (3, 3) and | 449 // Overlap for middle rectangle should increase from 2 pixels at (3, 3) and |
333 // (6, 6) to 17 pixels, as it will now cover 4x4 rectangle top, | 450 // (6, 6) to 17 pixels, as it will now cover 4x4 rectangle top, |
334 // so a change of +15. | 451 // so a change of +15 |
335 EXPECT_EQ(15, NodeOverlapIncreaseToAdd( | 452 EXPECT_EQ(parent->OverlapIncreaseToAdd(corner, 1, expanded), 15); |
336 parent.get(), corner, parent->child(1), expanded)); | |
337 | 453 |
338 expanded = bottom; | 454 expanded = bottom; |
339 expanded.Union(corner); | 455 expanded.Union(corner); |
340 // Overlap for bottom rectangle should increase from 1 pixel at (6, 6) to | 456 // Overlap for bottom rectangle should increase from 1 pixel at (6, 6) to |
341 // 32 pixels, as it will now cover both 4x4 rectangles top and middle, | 457 // 32 pixels, as it will now cover both 4x4 rectangles top and middle, |
342 // so a change of 31. | 458 // so a change of 31 |
343 EXPECT_EQ(31, NodeOverlapIncreaseToAdd( | 459 EXPECT_EQ(parent->OverlapIncreaseToAdd(corner, 2, expanded), 31); |
344 parent.get(), corner, parent->child(2), expanded)); | |
345 | 460 |
346 // Test a rect that doesn't overlap with anything, in the far right corner. | 461 // Test a rect that doesn't overlap with anything, in the far right corner. |
347 Rect far_corner(9, 0, 1, 1); | 462 Rect far_corner(9, 0, 1, 1); |
348 expanded = top; | 463 expanded = top; |
349 expanded.Union(far_corner); | 464 expanded.Union(far_corner); |
350 // Overlap of top should go from 1 to 4, as it will now cover the entire first | 465 // Overlap of top should go from 1 to 4, as it will now cover the entire first |
351 // row of pixels in middle. | 466 // row of pixels in middle. |
352 EXPECT_EQ(3, NodeOverlapIncreaseToAdd( | 467 EXPECT_EQ(parent->OverlapIncreaseToAdd(far_corner, 0, expanded), 3); |
353 parent.get(), far_corner, parent->child(0), expanded)); | |
354 | 468 |
355 expanded = middle; | 469 expanded = middle; |
356 expanded.Union(far_corner); | 470 expanded.Union(far_corner); |
357 // Overlap of middle should go from 2 to 8, as it will cover the rightmost 4 | 471 // Overlap of middle should go from 2 to 8, as it will cover the rightmost 4 |
358 // pixels of top and the top 4 pixels of bottom as it expands. | 472 // pixels of top and the top 4 pixles of bottom as it expands. |
359 EXPECT_EQ(6, NodeOverlapIncreaseToAdd( | 473 EXPECT_EQ(parent->OverlapIncreaseToAdd(far_corner, 1, expanded), 6); |
360 parent.get(), far_corner, parent->child(1), expanded)); | |
361 | 474 |
362 expanded = bottom; | 475 expanded = bottom; |
363 expanded.Union(far_corner); | 476 expanded.Union(far_corner); |
364 // Overlap of bottom should go from 1 to 4, as it will now cover the rightmost | 477 // Overlap of bottom should go from 1 to 4, as it will now cover the rightmost |
365 // 4 pixels of middle. | 478 // 4 pixels of middle. |
366 EXPECT_EQ(3, NodeOverlapIncreaseToAdd( | 479 EXPECT_EQ(parent->OverlapIncreaseToAdd(far_corner, 2, expanded), 3); |
367 parent.get(), far_corner, parent->child(2), expanded)); | |
368 } | 480 } |
369 | 481 |
370 TEST_F(RTreeNodeTest, BuildLowBounds) { | 482 TEST_F(RTreeTest, NodeBuildLowBounds) { |
371 RTreeNodes records; | 483 ScopedVector<RTree::Node> nodes; |
372 records.reserve(10); | 484 nodes.reserve(10); |
373 for (int i = 1; i <= 10; ++i) | 485 for (int i = 1; i <= 10; ++i) { |
374 records.push_back(new RTreeRecord(Rect(0, 0, i, i), i)); | 486 nodes.push_back(new RTree::Node(Rect(0, 0, i, i), i)); |
375 | 487 } |
376 RTreeRects vertical_bounds; | 488 std::vector<Rect> vertical_bounds; |
377 RTreeRects horizontal_bounds; | 489 std::vector<Rect> horizontal_bounds; |
378 NodeBuildLowBounds( | 490 RTree::Node::BuildLowBounds( |
379 records.get(), records.get(), &vertical_bounds, &horizontal_bounds); | 491 nodes.get(), nodes.get(), &vertical_bounds, &horizontal_bounds); |
380 for (int i = 0; i < 10; ++i) { | 492 for (int i = 0; i < 10; ++i) { |
381 EXPECT_EQ(records[i]->rect(), vertical_bounds[i]); | 493 EXPECT_EQ(vertical_bounds[i], Rect(0, 0, i + 1, i + 1)); |
382 EXPECT_EQ(records[i]->rect(), horizontal_bounds[i]); | 494 EXPECT_EQ(horizontal_bounds[i], Rect(0, 0, i + 1, i + 1)); |
383 } | 495 } |
384 } | 496 } |
385 | 497 |
386 TEST_F(RTreeNodeTest, BuildHighBounds) { | 498 TEST_F(RTreeTest, NodeBuildHighBounds) { |
387 RTreeNodes records; | 499 ScopedVector<RTree::Node> nodes; |
388 records.reserve(25); | 500 nodes.reserve(25); |
389 for (int i = 0; i < 25; ++i) | |
390 records.push_back(new RTreeRecord(Rect(i, i, 25 - i, 25 - i), i)); | |
391 | |
392 RTreeRects vertical_bounds; | |
393 RTreeRects horizontal_bounds; | |
394 NodeBuildHighBounds( | |
395 records.get(), records.get(), &vertical_bounds, &horizontal_bounds); | |
396 for (int i = 0; i < 25; ++i) { | 501 for (int i = 0; i < 25; ++i) { |
397 EXPECT_EQ(records[i]->rect(), vertical_bounds[i]); | 502 nodes.push_back(new RTree::Node(Rect(i, i, 25 - i, 25 - i), i)); |
398 EXPECT_EQ(records[i]->rect(), horizontal_bounds[i]); | 503 } |
| 504 std::vector<Rect> vertical_bounds; |
| 505 std::vector<Rect> horizontal_bounds; |
| 506 RTree::Node::BuildHighBounds( |
| 507 nodes.get(), nodes.get(), &vertical_bounds, &horizontal_bounds); |
| 508 for (int i = 0; i < 25; ++i) { |
| 509 EXPECT_EQ(vertical_bounds[i], Rect(i, i, 25 - i, 25 - i)); |
| 510 EXPECT_EQ(horizontal_bounds[i], Rect(i, i, 25 - i, 25 - i)); |
399 } | 511 } |
400 } | 512 } |
401 | 513 |
402 TEST_F(RTreeNodeTest, ChooseSplitAxisAndIndexVertical) { | 514 TEST_F(RTreeTest, NodeChooseSplitAxisAndIndex) { |
403 RTreeRects low_vertical_bounds; | 515 std::vector<Rect> low_vertical_bounds; |
404 RTreeRects high_vertical_bounds; | 516 std::vector<Rect> high_vertical_bounds; |
405 RTreeRects low_horizontal_bounds; | 517 std::vector<Rect> low_horizontal_bounds; |
406 RTreeRects high_horizontal_bounds; | 518 std::vector<Rect> high_horizontal_bounds; |
407 // In this test scenario we describe a mirrored, stacked configuration of | 519 // In this test scenario we describe a mirrored, stacked configuration of |
408 // horizontal, 1 pixel high rectangles labeled a-f like this: | 520 // horizontal, 1 pixel high rectangles labeled a-f like this: |
409 // | 521 // |
410 // shape: | v sort: | h sort: | | 522 // shape: | v sort: | h sort: | |
411 // -------+---------+---------+ | 523 // -------+---------+---------+ |
412 // aaaaa | 0 | 0 | | 524 // aaaaa | 0 | 0 | |
413 // bbb | 1 | 2 | | 525 // bbb | 1 | 2 | |
414 // c | 2 | 4 | | 526 // c | 2 | 4 | |
415 // d | 3 | 5 | | 527 // d | 3 | 5 | |
416 // eee | 4 | 3 | | 528 // eee | 4 | 3 | |
417 // fffff | 5 | 1 | | 529 // fffff | 5 | 1 | |
418 // | 530 // |
419 // These are already sorted vertically from top to bottom. Bounding rectangles | 531 // These are already sorted vertically from top to bottom. Bounding rectangles |
420 // of these vertically sorted will be 5 wide, i tall bounding boxes. | 532 // of these vertically sorted will be 5 wide, i tall bounding boxes. |
421 for (int i = 0; i < 6; ++i) { | 533 for (int i = 0; i < 6; ++i) { |
422 low_vertical_bounds.push_back(Rect(0, 0, 5, i + 1)); | 534 low_vertical_bounds.push_back(Rect(0, 0, 5, i + 1)); |
423 high_vertical_bounds.push_back(Rect(0, i, 5, 6 - i)); | 535 high_vertical_bounds.push_back(Rect(0, i, 5, 6 - i)); |
424 } | 536 } |
425 | 537 |
426 // Low bounds of horizontal sort start with bounds of box a and then jump to | 538 // Low bounds of horizontal sort start with bounds of box a and then jump to |
427 // cover everything, as box f is second in horizontal sort. | 539 // cover everything, as box f is second in horizontal sort. |
428 low_horizontal_bounds.push_back(Rect(0, 0, 5, 1)); | 540 low_horizontal_bounds.push_back(Rect(0, 0, 5, 1)); |
429 for (int i = 0; i < 5; ++i) | 541 for (int i = 0; i < 5; ++i) { |
430 low_horizontal_bounds.push_back(Rect(0, 0, 5, 6)); | 542 low_horizontal_bounds.push_back(Rect(0, 0, 5, 6)); |
| 543 } |
431 | 544 |
432 // High horizontal bounds are hand-calculated. | 545 // High horizontal bounds are hand-calculated. |
433 high_horizontal_bounds.push_back(Rect(0, 0, 5, 6)); | 546 high_horizontal_bounds.push_back(Rect(0, 0, 5, 6)); |
434 high_horizontal_bounds.push_back(Rect(0, 1, 5, 5)); | 547 high_horizontal_bounds.push_back(Rect(0, 1, 5, 5)); |
435 high_horizontal_bounds.push_back(Rect(1, 1, 3, 4)); | 548 high_horizontal_bounds.push_back(Rect(1, 1, 3, 4)); |
436 high_horizontal_bounds.push_back(Rect(1, 2, 3, 3)); | 549 high_horizontal_bounds.push_back(Rect(1, 2, 3, 3)); |
437 high_horizontal_bounds.push_back(Rect(2, 2, 1, 2)); | 550 high_horizontal_bounds.push_back(Rect(2, 2, 1, 2)); |
438 high_horizontal_bounds.push_back(Rect(2, 3, 1, 1)); | 551 high_horizontal_bounds.push_back(Rect(2, 3, 1, 1)); |
439 | 552 |
440 int smallest_vertical_margin = | 553 // This should split vertically, right down the middle. |
441 NodeSmallestMarginSum(2, 3, low_vertical_bounds, high_vertical_bounds); | 554 EXPECT_TRUE(RTree::Node::ChooseSplitAxis(low_vertical_bounds, |
442 int smallest_horizontal_margin = NodeSmallestMarginSum( | 555 high_vertical_bounds, |
443 2, 3, low_horizontal_bounds, high_horizontal_bounds); | 556 low_horizontal_bounds, |
444 EXPECT_LT(smallest_vertical_margin, smallest_horizontal_margin); | 557 high_horizontal_bounds, |
| 558 2, |
| 559 5)); |
| 560 EXPECT_EQ(3U, |
| 561 RTree::Node::ChooseSplitIndex( |
| 562 2, 5, low_vertical_bounds, high_vertical_bounds)); |
445 | 563 |
446 EXPECT_EQ( | 564 // We rotate the shape to test horizontal split axis detection: |
447 3U, | |
448 NodeChooseSplitIndex(2, 5, low_vertical_bounds, high_vertical_bounds)); | |
449 } | |
450 | |
451 TEST_F(RTreeNodeTest, ChooseSplitAxisAndIndexHorizontal) { | |
452 RTreeRects low_vertical_bounds; | |
453 RTreeRects high_vertical_bounds; | |
454 RTreeRects low_horizontal_bounds; | |
455 RTreeRects high_horizontal_bounds; | |
456 // We rotate the shape from ChooseSplitAxisAndIndexVertical to test | |
457 // horizontal split axis detection: | |
458 // | 565 // |
459 // +--------+ | 566 // +--------+ |
460 // | a f | | 567 // | a f | |
461 // | ab ef | | 568 // | ab ef | |
462 // sort: | abcdef | | 569 // sort: | abcdef | |
463 // | ab ef | | 570 // | ab ef | |
464 // | a f | | 571 // | a f | |
465 // |--------+ | 572 // |--------+ |
466 // v sort: | 024531 | | 573 // v sort: | 024531 | |
467 // h sort: | 012345 | | 574 // h sort: | 012345 | |
468 // +--------+ | 575 // +--------+ |
469 // | 576 // |
| 577 // Clear out old bounds first. |
| 578 low_vertical_bounds.clear(); |
| 579 high_vertical_bounds.clear(); |
| 580 low_horizontal_bounds.clear(); |
| 581 high_horizontal_bounds.clear(); |
| 582 |
470 // Low bounds of vertical sort start with bounds of box a and then jump to | 583 // Low bounds of vertical sort start with bounds of box a and then jump to |
471 // cover everything, as box f is second in vertical sort. | 584 // cover everything, as box f is second in vertical sort. |
472 low_vertical_bounds.push_back(Rect(0, 0, 1, 5)); | 585 low_vertical_bounds.push_back(Rect(0, 0, 1, 5)); |
473 for (int i = 0; i < 5; ++i) | 586 for (int i = 0; i < 5; ++i) { |
474 low_vertical_bounds.push_back(Rect(0, 0, 6, 5)); | 587 low_vertical_bounds.push_back(Rect(0, 0, 6, 5)); |
| 588 } |
475 | 589 |
476 // High vertical bounds are hand-calculated. | 590 // High vertical bounds are hand-calculated. |
477 high_vertical_bounds.push_back(Rect(0, 0, 6, 5)); | 591 high_vertical_bounds.push_back(Rect(0, 0, 6, 5)); |
478 high_vertical_bounds.push_back(Rect(1, 0, 5, 5)); | 592 high_vertical_bounds.push_back(Rect(1, 0, 5, 5)); |
479 high_vertical_bounds.push_back(Rect(1, 1, 4, 3)); | 593 high_vertical_bounds.push_back(Rect(1, 1, 4, 3)); |
480 high_vertical_bounds.push_back(Rect(2, 1, 3, 3)); | 594 high_vertical_bounds.push_back(Rect(2, 1, 3, 3)); |
481 high_vertical_bounds.push_back(Rect(2, 2, 2, 1)); | 595 high_vertical_bounds.push_back(Rect(2, 2, 2, 1)); |
482 high_vertical_bounds.push_back(Rect(3, 2, 1, 1)); | 596 high_vertical_bounds.push_back(Rect(3, 2, 1, 1)); |
483 | 597 |
484 // These are already sorted horizontally from left to right. Bounding | 598 // These are already sorted horizontally from left to right. Bounding |
485 // rectangles of these horizontally sorted will be i wide, 5 tall bounding | 599 // rectangles of these horizontally sorted will be i wide, 5 tall bounding |
486 // boxes. | 600 // boxes. |
487 for (int i = 0; i < 6; ++i) { | 601 for (int i = 0; i < 6; ++i) { |
488 low_horizontal_bounds.push_back(Rect(0, 0, i + 1, 5)); | 602 low_horizontal_bounds.push_back(Rect(0, 0, i + 1, 5)); |
489 high_horizontal_bounds.push_back(Rect(i, 0, 6 - i, 5)); | 603 high_horizontal_bounds.push_back(Rect(i, 0, 6 - i, 5)); |
490 } | 604 } |
491 | 605 |
492 int smallest_vertical_margin = | 606 // This should split horizontally, right down the middle. |
493 NodeSmallestMarginSum(2, 3, low_vertical_bounds, high_vertical_bounds); | 607 EXPECT_FALSE(RTree::Node::ChooseSplitAxis(low_vertical_bounds, |
494 int smallest_horizontal_margin = NodeSmallestMarginSum( | 608 high_vertical_bounds, |
495 2, 3, low_horizontal_bounds, high_horizontal_bounds); | 609 low_horizontal_bounds, |
496 | 610 high_horizontal_bounds, |
497 EXPECT_GT(smallest_vertical_margin, smallest_horizontal_margin); | 611 2, |
498 | 612 5)); |
499 EXPECT_EQ(3U, | 613 EXPECT_EQ(3U, |
500 NodeChooseSplitIndex( | 614 RTree::Node::ChooseSplitIndex( |
501 2, 5, low_horizontal_bounds, high_horizontal_bounds)); | 615 2, 5, low_horizontal_bounds, high_horizontal_bounds)); |
502 } | 616 } |
503 | 617 |
504 TEST_F(RTreeNodeTest, DivideChildren) { | 618 TEST_F(RTreeTest, NodeDivideChildren) { |
505 // Create a test node to split. | 619 // Create a test node to split. |
506 scoped_ptr<RTreeNode> test_node(new RTreeNode); | 620 scoped_ptr<RTree::Node> test_node(new RTree::Node(0)); |
507 std::vector<RTreeNodeBase*> sorted_children; | 621 std::vector<RTree::Node*> sorted_children; |
508 RTreeRects low_bounds; | 622 std::vector<Rect> low_bounds; |
509 RTreeRects high_bounds; | 623 std::vector<Rect> high_bounds; |
510 // Insert 10 record nodes, also inserting them into our children array. | 624 // Insert 10 record nodes, also inserting them into our children array. |
511 for (int i = 1; i <= 10; ++i) { | 625 for (int i = 1; i <= 10; ++i) { |
512 scoped_ptr<RTreeRecord> record(new RTreeRecord(Rect(0, 0, i, i), i)); | 626 RTree::Node* node = new RTree::Node(Rect(0, 0, i, i), i); |
513 sorted_children.push_back(record.get()); | 627 test_node->AddChild(node); |
514 test_node->AddChild(record.PassAs<RTreeNodeBase>()); | 628 sorted_children.push_back(node); |
515 low_bounds.push_back(Rect(0, 0, i, i)); | 629 low_bounds.push_back(Rect(0, 0, i, i)); |
516 high_bounds.push_back(Rect(0, 0, 10, 10)); | 630 high_bounds.push_back(Rect(0, 0, 10, 10)); |
517 } | 631 } |
518 // Split the children in half. | 632 // Split the children in half. |
519 scoped_ptr<RTreeNodeBase> split_node_base(NodeDivideChildren( | 633 scoped_ptr<RTree::Node> split_node( |
520 test_node.get(), low_bounds, high_bounds, sorted_children, 5)); | 634 test_node->DivideChildren(low_bounds, high_bounds, sorted_children, 5)); |
521 RTreeNode* split_node = static_cast<RTreeNode*>(split_node_base.get()); | |
522 // Both nodes should be valid. | 635 // Both nodes should be valid. |
523 ValidateNode(test_node.get(), 1U, 10U); | 636 ValidateNode(test_node.get(), 1U, 10U); |
524 ValidateNode(split_node, 1U, 10U); | 637 ValidateNode(split_node.get(), 1U, 10U); |
525 // Both nodes should have five children. | 638 // Both nodes should have five children. |
526 EXPECT_EQ(5U, test_node->count()); | 639 EXPECT_EQ(test_node->children_.size(), 5U); |
527 EXPECT_EQ(5U, split_node->count()); | 640 EXPECT_EQ(split_node->children_.size(), 5U); |
528 // Test node should have children 1-5, split node should have children 6-10. | 641 // Test node should have children 1-5, split node should have children 6-10. |
529 for (int i = 0; i < 5; ++i) { | 642 for (int i = 0; i < 5; ++i) { |
530 EXPECT_EQ(i + 1, record(test_node.get(), i)->key()); | 643 EXPECT_EQ(test_node->children_[i]->key(), i + 1); |
531 EXPECT_EQ(i + 6, record(split_node, i)->key()); | 644 EXPECT_EQ(split_node->children_[i]->key(), i + 6); |
532 } | 645 } |
533 } | 646 } |
534 | 647 |
535 TEST_F(RTreeNodeTest, RemoveChildNoOrphans) { | 648 TEST_F(RTreeTest, NodeRemoveChildNoOrphans) { |
536 scoped_ptr<RTreeNode> test_parent(new RTreeNode); | 649 scoped_ptr<RTree::Node> test_parent(new RTree::Node(0)); |
537 test_parent->AddChild( | 650 scoped_ptr<RTree::Node> child_one(new RTree::Node(Rect(0, 0, 1, 1), 1)); |
538 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 1, 1), 1))); | 651 scoped_ptr<RTree::Node> child_two(new RTree::Node(Rect(0, 0, 2, 2), 2)); |
539 test_parent->AddChild( | 652 scoped_ptr<RTree::Node> child_three(new RTree::Node(Rect(0, 0, 3, 3), 3)); |
540 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 2, 2), 2))); | 653 test_parent->AddChild(child_one.get()); |
541 test_parent->AddChild( | 654 test_parent->AddChild(child_two.get()); |
542 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 3, 3), 3))); | 655 test_parent->AddChild(child_three.get()); |
| 656 ValidateNode(test_parent.get(), 1U, 5U); |
| 657 // Remove the middle node. |
| 658 ScopedVector<RTree::Node> orphans; |
| 659 EXPECT_EQ(test_parent->RemoveChild(child_two.get(), &orphans), 2U); |
| 660 EXPECT_EQ(orphans.size(), 0U); |
| 661 EXPECT_EQ(test_parent->count(), 2U); |
| 662 test_parent->RecomputeBoundsNoParents(); |
| 663 ValidateNode(test_parent.get(), 1U, 5U); |
| 664 // Remove the end node. |
| 665 EXPECT_EQ(test_parent->RemoveChild(child_three.get(), &orphans), 1U); |
| 666 EXPECT_EQ(orphans.size(), 0U); |
| 667 EXPECT_EQ(test_parent->count(), 1U); |
| 668 test_parent->RecomputeBoundsNoParents(); |
| 669 ValidateNode(test_parent.get(), 1U, 5U); |
| 670 // Remove the first node. |
| 671 EXPECT_EQ(test_parent->RemoveChild(child_one.get(), &orphans), 0U); |
| 672 EXPECT_EQ(orphans.size(), 0U); |
| 673 EXPECT_EQ(test_parent->count(), 0U); |
| 674 } |
| 675 |
| 676 TEST_F(RTreeTest, NodeRemoveChildOrphans) { |
| 677 // Build flattened binary tree of Nodes 4 deep, from the record nodes up. |
| 678 ScopedVector<RTree::Node> nodes; |
| 679 nodes.resize(15); |
| 680 // Indicies 7 through 15 are record nodes. |
| 681 for (int i = 7; i < 15; ++i) { |
| 682 nodes[i] = new RTree::Node(Rect(0, 0, i, i), i); |
| 683 } |
| 684 // Nodes 3 through 6 are level 0 (leaves) and get 2 record nodes each. |
| 685 for (int i = 3; i < 7; ++i) { |
| 686 nodes[i] = new RTree::Node(0); |
| 687 nodes[i]->AddChild(nodes[(i * 2) + 1]); |
| 688 nodes[i]->AddChild(nodes[(i * 2) + 2]); |
| 689 } |
| 690 // Nodes 1 and 2 are level 1 and get 2 leaves each. |
| 691 for (int i = 1; i < 3; ++i) { |
| 692 nodes[i] = new RTree::Node(1); |
| 693 nodes[i]->AddChild(nodes[(i * 2) + 1]); |
| 694 nodes[i]->AddChild(nodes[(i * 2) + 2]); |
| 695 } |
| 696 // Node 0 is level 2 and gets 2 childen. |
| 697 nodes[0] = new RTree::Node(2); |
| 698 nodes[0]->AddChild(nodes[1]); |
| 699 nodes[0]->AddChild(nodes[2]); |
| 700 // This should now be a valid node structure. |
| 701 ValidateNode(nodes[0], 2U, 2U); |
| 702 |
| 703 // Now remove the level 0 nodes, so we get the record nodes as orphans. |
| 704 ScopedVector<RTree::Node> orphans; |
| 705 EXPECT_EQ(nodes[1]->RemoveChild(nodes[3], &orphans), 1U); |
| 706 EXPECT_EQ(nodes[1]->RemoveChild(nodes[4], &orphans), 0U); |
| 707 EXPECT_EQ(nodes[2]->RemoveChild(nodes[5], &orphans), 1U); |
| 708 EXPECT_EQ(nodes[2]->RemoveChild(nodes[6], &orphans), 0U); |
| 709 |
| 710 // Orphans should be nodes 7 through 15 in order. |
| 711 EXPECT_EQ(orphans.size(), 8U); |
| 712 for (int i = 0; i < 8; ++i) { |
| 713 EXPECT_EQ(orphans[i], nodes[i + 7]); |
| 714 } |
| 715 |
| 716 // Now we remove nodes 1 and 2 from the root, expecting no further orphans. |
| 717 // This prevents a crash due to double-delete on test exit, as no node should |
| 718 // own any other node right now. |
| 719 EXPECT_EQ(nodes[0]->RemoveChild(nodes[1], &orphans), 1U); |
| 720 EXPECT_EQ(orphans.size(), 8U); |
| 721 EXPECT_EQ(nodes[0]->RemoveChild(nodes[2], &orphans), 0U); |
| 722 EXPECT_EQ(orphans.size(), 8U); |
| 723 |
| 724 // Prevent double-delete of nodes by both nodes and orphans. |
| 725 orphans.weak_clear(); |
| 726 } |
| 727 |
| 728 TEST_F(RTreeTest, NodeRemoveAndReturnLastChild) { |
| 729 scoped_ptr<RTree::Node> test_parent(new RTree::Node(0)); |
| 730 scoped_ptr<RTree::Node> child_one(new RTree::Node(Rect(0, 0, 1, 1), 1)); |
| 731 scoped_ptr<RTree::Node> child_two(new RTree::Node(Rect(0, 0, 2, 2), 2)); |
| 732 scoped_ptr<RTree::Node> child_three(new RTree::Node(Rect(0, 0, 3, 3), 3)); |
| 733 test_parent->AddChild(child_one.get()); |
| 734 test_parent->AddChild(child_two.get()); |
| 735 test_parent->AddChild(child_three.get()); |
543 ValidateNode(test_parent.get(), 1U, 5U); | 736 ValidateNode(test_parent.get(), 1U, 5U); |
544 | 737 |
545 RTreeNodes orphans; | 738 EXPECT_EQ(test_parent->RemoveAndReturnLastChild().release(), |
546 | 739 child_three.get()); |
547 // Remove the middle node. | 740 EXPECT_EQ(test_parent->count(), 2U); |
548 scoped_ptr<RTreeNodeBase> middle_child( | 741 test_parent->RecomputeBoundsNoParents(); |
549 test_parent->RemoveChild(test_parent->child(1), &orphans)); | |
550 EXPECT_EQ(0U, orphans.size()); | |
551 EXPECT_EQ(2U, test_parent->count()); | |
552 NodeRecomputeLocalBounds(test_parent.get()); | |
553 ValidateNode(test_parent.get(), 1U, 5U); | 742 ValidateNode(test_parent.get(), 1U, 5U); |
554 | 743 |
555 // Remove the end node. | 744 EXPECT_EQ(test_parent->RemoveAndReturnLastChild().release(), child_two.get()); |
556 scoped_ptr<RTreeNodeBase> end_child( | 745 EXPECT_EQ(test_parent->count(), 1U); |
557 test_parent->RemoveChild(test_parent->child(1), &orphans)); | 746 test_parent->RecomputeBoundsNoParents(); |
558 EXPECT_EQ(0U, orphans.size()); | |
559 EXPECT_EQ(1U, test_parent->count()); | |
560 NodeRecomputeLocalBounds(test_parent.get()); | |
561 ValidateNode(test_parent.get(), 1U, 5U); | 747 ValidateNode(test_parent.get(), 1U, 5U); |
562 | 748 |
563 // Remove the first node. | 749 EXPECT_EQ(test_parent->RemoveAndReturnLastChild().release(), child_one.get()); |
564 scoped_ptr<RTreeNodeBase> first_child( | 750 EXPECT_EQ(test_parent->count(), 0U); |
565 test_parent->RemoveChild(test_parent->child(0), &orphans)); | |
566 EXPECT_EQ(0U, orphans.size()); | |
567 EXPECT_EQ(0U, test_parent->count()); | |
568 } | 751 } |
569 | 752 |
570 TEST_F(RTreeNodeTest, RemoveChildOrphans) { | 753 TEST_F(RTreeTest, NodeLeastOverlapIncrease) { |
571 // Build binary tree of Nodes of height 4, keeping weak pointers to the | 754 scoped_ptr<RTree::Node> test_parent(new RTree::Node(0)); |
572 // Levels 0 and 1 Nodes and the Records so we can test removal of them below. | 755 // Construct 4 nodes with 1x2 retangles spaced horizontally 1 pixel apart, or: |
573 std::vector<RTreeNode*> level_1_children; | |
574 std::vector<RTreeNode*> level_0_children; | |
575 std::vector<RTreeRecord*> records; | |
576 int id = 1; | |
577 scoped_ptr<RTreeNode> root(NewNodeAtLevel(2)); | |
578 for (int i = 0; i < 2; ++i) { | |
579 scoped_ptr<RTreeNode> level_1_child(NewNodeAtLevel(1)); | |
580 for (int j = 0; j < 2; ++j) { | |
581 scoped_ptr<RTreeNode> level_0_child(new RTreeNode); | |
582 for (int k = 0; k < 2; ++k) { | |
583 scoped_ptr<RTreeRecord> record( | |
584 new RTreeRecord(Rect(0, 0, id, id), id)); | |
585 ++id; | |
586 records.push_back(record.get()); | |
587 level_0_child->AddChild(record.PassAs<RTreeNodeBase>()); | |
588 } | |
589 level_0_children.push_back(level_0_child.get()); | |
590 level_1_child->AddChild(level_0_child.PassAs<RTreeNodeBase>()); | |
591 } | |
592 level_1_children.push_back(level_1_child.get()); | |
593 root->AddChild(level_1_child.PassAs<RTreeNodeBase>()); | |
594 } | |
595 | |
596 // This should now be a valid tree structure. | |
597 ValidateNode(root.get(), 2U, 2U); | |
598 EXPECT_EQ(2U, level_1_children.size()); | |
599 EXPECT_EQ(4U, level_0_children.size()); | |
600 EXPECT_EQ(8U, records.size()); | |
601 | |
602 // Now remove all of the level 0 nodes so we get the record nodes as orphans. | |
603 RTreeNodes orphans; | |
604 for (size_t i = 0; i < level_0_children.size(); ++i) | |
605 level_1_children[i / 2]->RemoveChild(level_0_children[i], &orphans); | |
606 | |
607 // Orphans should be all 8 records but no order guarantee. | |
608 EXPECT_EQ(8U, orphans.size()); | |
609 for (std::vector<RTreeRecord*>::iterator it = records.begin(); | |
610 it != records.end(); ++it) { | |
611 RTreeNodes::iterator orphan = | |
612 std::find(orphans.begin(), orphans.end(), *it); | |
613 EXPECT_NE(orphan, orphans.end()); | |
614 orphans.erase(orphan); | |
615 } | |
616 EXPECT_EQ(0U, orphans.size()); | |
617 } | |
618 | |
619 TEST_F(RTreeNodeTest, RemoveAndReturnLastChild) { | |
620 scoped_ptr<RTreeNode> test_parent(new RTreeNode); | |
621 test_parent->AddChild( | |
622 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 1, 1), 1))); | |
623 test_parent->AddChild( | |
624 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 2, 2), 2))); | |
625 test_parent->AddChild( | |
626 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 3, 3), 3))); | |
627 ValidateNode(test_parent.get(), 1U, 5U); | |
628 | |
629 RTreeNodeBase* child = test_parent->child(2); | |
630 scoped_ptr<RTreeNodeBase> last_child(test_parent->RemoveAndReturnLastChild()); | |
631 EXPECT_EQ(child, last_child.get()); | |
632 EXPECT_EQ(2U, test_parent->count()); | |
633 NodeRecomputeLocalBounds(test_parent.get()); | |
634 ValidateNode(test_parent.get(), 1U, 5U); | |
635 | |
636 child = test_parent->child(1); | |
637 scoped_ptr<RTreeNodeBase> middle_child( | |
638 test_parent->RemoveAndReturnLastChild()); | |
639 EXPECT_EQ(child, middle_child.get()); | |
640 EXPECT_EQ(1U, test_parent->count()); | |
641 NodeRecomputeLocalBounds(test_parent.get()); | |
642 ValidateNode(test_parent.get(), 1U, 5U); | |
643 | |
644 child = test_parent->child(0); | |
645 scoped_ptr<RTreeNodeBase> first_child( | |
646 test_parent->RemoveAndReturnLastChild()); | |
647 EXPECT_EQ(child, first_child.get()); | |
648 EXPECT_EQ(0U, test_parent->count()); | |
649 } | |
650 | |
651 TEST_F(RTreeNodeTest, LeastOverlapIncrease) { | |
652 scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1)); | |
653 // Construct 4 nodes with 1x2 rects spaced horizontally 1 pixel apart, or: | |
654 // | 756 // |
655 // a b c d | 757 // a b c d |
656 // a b c d | 758 // a b c d |
657 // | 759 // |
658 for (int i = 0; i < 4; ++i) { | 760 for (int i = 0; i < 4; ++i) { |
659 scoped_ptr<RTreeNode> node(new RTreeNode); | 761 test_parent->AddChild(new RTree::Node(Rect(i * 2, 0, 1, 2), i + 1)); |
660 scoped_ptr<RTreeRecord> record( | |
661 new RTreeRecord(Rect(i * 2, 0, 1, 2), i + 1)); | |
662 node->AddChild(record.PassAs<RTreeNodeBase>()); | |
663 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); | |
664 } | 762 } |
665 | 763 |
666 ValidateNode(test_parent.get(), 1U, 5U); | 764 ValidateNode(test_parent.get(), 1U, 5U); |
667 | 765 |
668 // Test rect at (7, 0) should require minimum overlap on the part of the | 766 // Test rect at (7, 0) should require minimum overlap on the part of the |
669 // fourth rectangle to add: | 767 // fourth rectangle to add: |
670 // | 768 // |
671 // a b c dT | 769 // a b c dT |
672 // a b c d | 770 // a b c d |
673 // | 771 // |
674 Rect test_rect_far(7, 0, 1, 1); | 772 Rect test_rect_far(7, 0, 1, 1); |
675 RTreeRects expanded_rects; | 773 std::vector<Rect> expanded_rects; |
676 BuildExpandedRects(test_parent.get(), test_rect_far, &expanded_rects); | 774 BuildExpandedRects(test_parent.get(), test_rect_far, &expanded_rects); |
677 RTreeNode* result = NodeLeastOverlapIncrease( | 775 RTree::Node* result = |
678 test_parent.get(), test_rect_far, expanded_rects); | 776 test_parent->LeastOverlapIncrease(test_rect_far, expanded_rects); |
679 EXPECT_EQ(4, record(result, 0)->key()); | 777 EXPECT_EQ(result->key(), 4); |
680 | 778 |
681 // Test rect covering the bottom half of all children should be a 4-way tie, | 779 // Test rect covering the bottom half of all children should be a 4-way tie, |
682 // so LeastOverlapIncrease should return NULL: | 780 // so LeastOverlapIncrease should return NULL: |
683 // | 781 // |
684 // a b c d | 782 // a b c d |
685 // TTTTTTT | 783 // TTTTTTT |
686 // | 784 // |
687 Rect test_rect_tie(0, 1, 7, 1); | 785 Rect test_rect_tie(0, 1, 7, 1); |
688 BuildExpandedRects(test_parent.get(), test_rect_tie, &expanded_rects); | 786 BuildExpandedRects(test_parent.get(), test_rect_tie, &expanded_rects); |
689 result = NodeLeastOverlapIncrease( | 787 result = test_parent->LeastOverlapIncrease(test_rect_tie, expanded_rects); |
690 test_parent.get(), test_rect_tie, expanded_rects); | |
691 EXPECT_TRUE(result == NULL); | 788 EXPECT_TRUE(result == NULL); |
692 | 789 |
693 // Test rect completely inside c should return the third rectangle: | 790 // Test rect completely inside c should return the third rectangle: |
694 // | 791 // |
695 // a b T d | 792 // a b T d |
696 // a b c d | 793 // a b c d |
697 // | 794 // |
698 Rect test_rect_inside(4, 0, 1, 1); | 795 Rect test_rect_inside(4, 0, 1, 1); |
699 BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects); | 796 BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects); |
700 result = NodeLeastOverlapIncrease( | 797 result = test_parent->LeastOverlapIncrease(test_rect_inside, expanded_rects); |
701 test_parent.get(), test_rect_inside, expanded_rects); | 798 EXPECT_EQ(result->key(), 3); |
702 EXPECT_EQ(3, record(result, 0)->key()); | |
703 | 799 |
704 // Add a rectangle that overlaps completely with rectangle c, to test | 800 // Add a rectangle that overlaps completely with rectangle c, to test |
705 // when there is a tie between two completely contained rectangles: | 801 // when there is a tie between two completely contained rectangles: |
706 // | 802 // |
707 // a b Ted | 803 // a b Ted |
708 // a b eed | 804 // a b eed |
709 // | 805 // |
710 scoped_ptr<RTreeNode> record_parent(new RTreeNode); | 806 test_parent->AddChild(new RTree::Node(Rect(4, 0, 2, 2), 9)); |
711 record_parent->AddChild( | |
712 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(4, 0, 2, 2), 9))); | |
713 test_parent->AddChild(record_parent.PassAs<RTreeNodeBase>()); | |
714 BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects); | 807 BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects); |
715 result = NodeLeastOverlapIncrease( | 808 result = test_parent->LeastOverlapIncrease(test_rect_inside, expanded_rects); |
716 test_parent.get(), test_rect_inside, expanded_rects); | |
717 EXPECT_TRUE(result == NULL); | 809 EXPECT_TRUE(result == NULL); |
718 } | 810 } |
719 | 811 |
720 TEST_F(RTreeNodeTest, LeastAreaEnlargement) { | 812 TEST_F(RTreeTest, NodeLeastAreaEnlargement) { |
721 scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1)); | 813 scoped_ptr<RTree::Node> test_parent(new RTree::Node(0)); |
722 // Construct 4 nodes in a cross-hairs style configuration: | 814 // Construct 4 nodes in a cross-hairs style configuration: |
723 // | 815 // |
724 // a | 816 // a |
725 // b c | 817 // b c |
726 // d | 818 // d |
727 // | 819 // |
728 scoped_ptr<RTreeNode> node(new RTreeNode); | 820 test_parent->AddChild(new RTree::Node(Rect(1, 0, 1, 1), 1)); |
729 node->AddChild( | 821 test_parent->AddChild(new RTree::Node(Rect(0, 1, 1, 1), 2)); |
730 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 0, 1, 1), 1))); | 822 test_parent->AddChild(new RTree::Node(Rect(2, 1, 1, 1), 3)); |
731 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); | 823 test_parent->AddChild(new RTree::Node(Rect(1, 2, 1, 1), 4)); |
732 node.reset(new RTreeNode); | |
733 node->AddChild( | |
734 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 1, 1), 2))); | |
735 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); | |
736 node.reset(new RTreeNode); | |
737 node->AddChild( | |
738 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(2, 1, 1, 1), 3))); | |
739 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); | |
740 node.reset(new RTreeNode); | |
741 node->AddChild( | |
742 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 2, 1, 1), 4))); | |
743 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); | |
744 | 824 |
745 ValidateNode(test_parent.get(), 1U, 5U); | 825 ValidateNode(test_parent.get(), 1U, 5U); |
746 | 826 |
747 // Test rect at (1, 3) should require minimum area to add to Node d: | 827 // Test rect at (1, 3) should require minimum area to add to Node d: |
748 // | 828 // |
749 // a | 829 // a |
750 // b c | 830 // b c |
751 // d | 831 // d |
752 // T | 832 // T |
753 // | 833 // |
754 Rect test_rect_below(1, 3, 1, 1); | 834 Rect test_rect_below(1, 3, 1, 1); |
755 RTreeRects expanded_rects; | 835 std::vector<Rect> expanded_rects; |
756 BuildExpandedRects(test_parent.get(), test_rect_below, &expanded_rects); | 836 BuildExpandedRects(test_parent.get(), test_rect_below, &expanded_rects); |
757 RTreeNode* result = NodeLeastAreaEnlargement( | 837 RTree::Node* result = |
758 test_parent.get(), test_rect_below, expanded_rects); | 838 test_parent->LeastAreaEnlargement(test_rect_below, expanded_rects); |
759 EXPECT_EQ(4, record(result, 0)->key()); | 839 EXPECT_EQ(result->key(), 4); |
760 | 840 |
761 // Test rect completely inside b should require minimum area to add to Node b: | 841 // Test rect completely inside b should require minimum area to add to Node b: |
762 // | 842 // |
763 // a | 843 // a |
764 // T c | 844 // T c |
765 // d | 845 // d |
766 // | 846 // |
767 Rect test_rect_inside(0, 1, 1, 1); | 847 Rect test_rect_inside(0, 1, 1, 1); |
768 BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects); | 848 BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects); |
769 result = NodeLeastAreaEnlargement( | 849 result = test_parent->LeastAreaEnlargement(test_rect_inside, expanded_rects); |
770 test_parent.get(), test_rect_inside, expanded_rects); | 850 EXPECT_EQ(result->key(), 2); |
771 EXPECT_EQ(2, record(result, 0)->key()); | |
772 | 851 |
773 // Add e at (0, 1) to overlap b and c, to test tie-breaking: | 852 // Add e at (0, 1) to overlap b and c, to test tie-breaking: |
774 // | 853 // |
775 // a | 854 // a |
776 // eee | 855 // eee |
777 // d | 856 // d |
778 // | 857 // |
779 node.reset(new RTreeNode); | 858 test_parent->AddChild(new RTree::Node(Rect(0, 1, 3, 1), 7)); |
780 node->AddChild( | |
781 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 3, 1), 7))); | |
782 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); | |
783 | 859 |
784 ValidateNode(test_parent.get(), 1U, 5U); | 860 ValidateNode(test_parent.get(), 1U, 5U); |
785 | 861 |
786 // Test rect at (3, 1) should tie between c and e, but c has smaller area so | 862 // Test rect at (3, 1) should tie between c and e, but c has smaller area so |
787 // the algorithm should select c: | 863 // the algorithm should select c: |
788 // | 864 // |
789 // | 865 // |
790 // a | 866 // a |
791 // eeeT | 867 // eeeT |
792 // d | 868 // d |
793 // | 869 // |
794 Rect test_rect_tie_breaker(3, 1, 1, 1); | 870 Rect test_rect_tie_breaker(3, 1, 1, 1); |
795 BuildExpandedRects(test_parent.get(), test_rect_tie_breaker, &expanded_rects); | 871 BuildExpandedRects(test_parent.get(), test_rect_tie_breaker, &expanded_rects); |
796 result = NodeLeastAreaEnlargement( | 872 result = |
797 test_parent.get(), test_rect_tie_breaker, expanded_rects); | 873 test_parent->LeastAreaEnlargement(test_rect_tie_breaker, expanded_rects); |
798 EXPECT_EQ(3, record(result, 0)->key()); | 874 EXPECT_EQ(result->key(), 3); |
799 } | |
800 | |
801 // RTreeTest ------------------------------------------------------------------ | |
802 | |
803 // An empty RTree should never return AppendIntersectingRecords results, and | |
804 // RTrees should be empty upon construction. | |
805 TEST_F(RTreeTest, AppendIntersectingRecordsOnEmptyTree) { | |
806 RT rt(2, 10); | |
807 ValidateRTree(&rt); | |
808 RT::Matches results; | |
809 Rect test_rect(25, 25); | |
810 rt.AppendIntersectingRecords(test_rect, &results); | |
811 EXPECT_EQ(0U, results.size()); | |
812 ValidateRTree(&rt); | |
813 } | |
814 | |
815 // Clear should empty the tree, meaning that all queries should not return | |
816 // results after. | |
817 TEST_F(RTreeTest, ClearEmptiesTreeOfSingleNode) { | |
818 RT rt(2, 5); | |
819 rt.Insert(Rect(0, 0, 100, 100), 1); | |
820 rt.Clear(); | |
821 RT::Matches results; | |
822 Rect test_rect(1, 1); | |
823 rt.AppendIntersectingRecords(test_rect, &results); | |
824 EXPECT_EQ(0U, results.size()); | |
825 ValidateRTree(&rt); | |
826 } | |
827 | |
828 // Even with a complex internal structure, clear should empty the tree, meaning | |
829 // that all queries should not return results after. | |
830 TEST_F(RTreeTest, ClearEmptiesTreeOfManyNodes) { | |
831 RT rt(2, 5); | |
832 AddStackedSquares(&rt, 100); | |
833 rt.Clear(); | |
834 RT::Matches results; | |
835 Rect test_rect(1, 1); | |
836 rt.AppendIntersectingRecords(test_rect, &results); | |
837 EXPECT_EQ(0U, results.size()); | |
838 ValidateRTree(&rt); | |
839 } | |
840 | |
841 // Duplicate inserts should overwrite previous inserts. | |
842 TEST_F(RTreeTest, DuplicateInsertsOverwrite) { | |
843 RT rt(2, 5); | |
844 // Add 100 stacked squares, but always with duplicate key of 0. | |
845 for (int i = 1; i <= 100; ++i) { | |
846 rt.Insert(Rect(0, 0, i, i), 0); | |
847 ValidateRTree(&rt); | |
848 } | |
849 RT::Matches results; | |
850 Rect test_rect(1, 1); | |
851 rt.AppendIntersectingRecords(test_rect, &results); | |
852 EXPECT_EQ(1U, results.size()); | |
853 EXPECT_EQ(1U, results.count(0)); | |
854 } | |
855 | |
856 // Call Remove() once on something that's been inserted repeatedly. | |
857 TEST_F(RTreeTest, DuplicateInsertRemove) { | |
858 RT rt(3, 9); | |
859 AddStackedSquares(&rt, 25); | |
860 for (int i = 1; i <= 100; ++i) { | |
861 rt.Insert(Rect(0, 0, i, i), 26); | |
862 ValidateRTree(&rt); | |
863 } | |
864 rt.Remove(26); | |
865 RT::Matches results; | |
866 Rect test_rect(1, 1); | |
867 rt.AppendIntersectingRecords(test_rect, &results); | |
868 EXPECT_EQ(25U, results.size()); | |
869 VerifyAllKeys(results); | |
870 } | |
871 | |
872 // Call Remove() repeatedly on something that's been inserted once. | |
873 TEST_F(RTreeTest, InsertDuplicateRemove) { | |
874 RT rt(7, 15); | |
875 AddStackedSquares(&rt, 101); | |
876 for (int i = 0; i < 100; ++i) { | |
877 rt.Remove(101); | |
878 ValidateRTree(&rt); | |
879 } | |
880 RT::Matches results; | |
881 Rect test_rect(1, 1); | |
882 rt.AppendIntersectingRecords(test_rect, &results); | |
883 EXPECT_EQ(100U, results.size()); | |
884 VerifyAllKeys(results); | |
885 } | |
886 | |
887 // Stacked rects should meet all matching queries regardless of nesting. | |
888 TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresNestedHit) { | |
889 RT rt(2, 5); | |
890 AddStackedSquares(&rt, 100); | |
891 RT::Matches results; | |
892 Rect test_rect(1, 1); | |
893 rt.AppendIntersectingRecords(test_rect, &results); | |
894 EXPECT_EQ(100U, results.size()); | |
895 VerifyAllKeys(results); | |
896 } | |
897 | |
898 // Stacked rects should meet all matching queries when contained completely by | |
899 // the query rectangle. | |
900 TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresContainedHit) { | |
901 RT rt(2, 10); | |
902 AddStackedSquares(&rt, 100); | |
903 RT::Matches results; | |
904 Rect test_rect(0, 0, 100, 100); | |
905 rt.AppendIntersectingRecords(test_rect, &results); | |
906 EXPECT_EQ(100U, results.size()); | |
907 VerifyAllKeys(results); | |
908 } | |
909 | |
910 // Stacked rects should miss a missing query when the query has no intersection | |
911 // with the rects. | |
912 TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresCompleteMiss) { | |
913 RT rt(2, 7); | |
914 AddStackedSquares(&rt, 100); | |
915 RT::Matches results; | |
916 Rect test_rect(150, 150, 100, 100); | |
917 rt.AppendIntersectingRecords(test_rect, &results); | |
918 EXPECT_EQ(0U, results.size()); | |
919 } | |
920 | |
921 // Removing half the nodes after insertion should still result in a valid tree. | |
922 TEST_F(RTreeTest, RemoveHalfStackedRects) { | |
923 RT rt(2, 11); | |
924 AddStackedSquares(&rt, 200); | |
925 for (int i = 101; i <= 200; ++i) { | |
926 rt.Remove(i); | |
927 ValidateRTree(&rt); | |
928 } | |
929 RT::Matches results; | |
930 Rect test_rect(1, 1); | |
931 rt.AppendIntersectingRecords(test_rect, &results); | |
932 EXPECT_EQ(100U, results.size()); | |
933 VerifyAllKeys(results); | |
934 | |
935 // Add the nodes back in. | |
936 for (int i = 101; i <= 200; ++i) { | |
937 rt.Insert(Rect(0, 0, i, i), i); | |
938 ValidateRTree(&rt); | |
939 } | |
940 results.clear(); | |
941 rt.AppendIntersectingRecords(test_rect, &results); | |
942 EXPECT_EQ(200U, results.size()); | |
943 VerifyAllKeys(results); | |
944 } | |
945 | |
946 TEST_F(RTreeTest, InsertDupToRoot) { | |
947 RT rt(2, 5); | |
948 rt.Insert(Rect(0, 0, 1, 2), 1); | |
949 ValidateRTree(&rt); | |
950 rt.Insert(Rect(0, 0, 2, 1), 1); | |
951 ValidateRTree(&rt); | |
952 } | |
953 | |
954 TEST_F(RTreeTest, InsertNegativeCoordsRect) { | |
955 RT rt(5, 11); | |
956 for (int i = 1; i <= 100; ++i) { | |
957 rt.Insert(Rect(-i, -i, i, i), (i * 2) - 1); | |
958 ValidateRTree(&rt); | |
959 rt.Insert(Rect(0, 0, i, i), i * 2); | |
960 ValidateRTree(&rt); | |
961 } | |
962 RT::Matches results; | |
963 Rect test_rect(-1, -1, 2, 2); | |
964 rt.AppendIntersectingRecords(test_rect, &results); | |
965 EXPECT_EQ(200U, results.size()); | |
966 VerifyAllKeys(results); | |
967 } | |
968 | |
969 TEST_F(RTreeTest, RemoveNegativeCoordsRect) { | |
970 RT rt(7, 21); | |
971 | |
972 // Add 100 positive stacked squares. | |
973 AddStackedSquares(&rt, 100); | |
974 | |
975 // Now add 100 negative stacked squares. | |
976 for (int i = 101; i <= 200; ++i) { | |
977 rt.Insert(Rect(100 - i, 100 - i, i - 100, i - 100), 301 - i); | |
978 ValidateRTree(&rt); | |
979 } | |
980 | |
981 // Now remove half of the negative squares. | |
982 for (int i = 101; i <= 150; ++i) { | |
983 rt.Remove(301 - i); | |
984 ValidateRTree(&rt); | |
985 } | |
986 | |
987 // Queries should return 100 positive and 50 negative stacked squares. | |
988 RT::Matches results; | |
989 Rect test_rect(-1, -1, 2, 2); | |
990 rt.AppendIntersectingRecords(test_rect, &results); | |
991 EXPECT_EQ(150U, results.size()); | |
992 VerifyAllKeys(results); | |
993 } | |
994 | |
995 TEST_F(RTreeTest, InsertEmptyRectReplacementRemovesKey) { | |
996 RT rt(10, 31); | |
997 AddStackedSquares(&rt, 50); | |
998 ValidateRTree(&rt); | |
999 | |
1000 // Replace last square with empty rect. | |
1001 rt.Insert(Rect(), 50); | |
1002 ValidateRTree(&rt); | |
1003 | |
1004 // Now query large area to get all rects in tree. | |
1005 RT::Matches results; | |
1006 Rect test_rect(0, 0, 100, 100); | |
1007 rt.AppendIntersectingRecords(test_rect, &results); | |
1008 | |
1009 // Should only be 49 rects in tree. | |
1010 EXPECT_EQ(49U, results.size()); | |
1011 VerifyAllKeys(results); | |
1012 } | 875 } |
1013 | 876 |
1014 } // namespace gfx | 877 } // namespace gfx |
OLD | NEW |