Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: ui/gfx/geometry/r_tree_unittest.cc

Issue 269513002: readability review for luken (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698