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