1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "testing/gtest/include/gtest/gtest.h"
6 #include "ui/gfx/geometry/r_tree.h"
7 #include "ui/gfx/geometry/r_tree_base.h"
8 #include "ui/gfx/geometry/rect.h"
12 class RTreeTest
: public ::testing::Test
{
14 typedef RTree
<int> 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
) {
19 // If RTree is empty it should have an empty rectangle.
20 if (!rt
->root()->count()) {
21 EXPECT_TRUE(rt
->root()->rect().IsEmpty());
22 EXPECT_EQ(0, rt
->root()->Level());
25 // Root is allowed to have fewer than min_children_ but never more than
27 EXPECT_LE(rt
->root()->count(), rt
->max_children_
);
28 // The root should never be a record node.
29 EXPECT_GT(rt
->root()->Level(), -1);
30 // The root should never have a parent pointer.
31 EXPECT_TRUE(rt
->root()->parent() == NULL
);
32 // Bounds must be consistent on the root.
33 CheckBoundsConsistent(rt
->root());
34 for (size_t i
= 0; i
< rt
->root()->count(); ++i
) {
36 rt
->root()->child(i
), rt
->min_children_
, rt
->max_children_
);
40 // Recursive descent method used by ValidateRTree to check each node within
41 // the RTree for consistency with RTree semantics.
42 void ValidateNode(const RTreeBase::NodeBase
* node_base
,
44 size_t max_children
) {
45 if (node_base
->Level() >= 0) {
46 const RTreeBase::Node
* node
=
47 static_cast<const RTreeBase::Node
*>(node_base
);
48 EXPECT_GE(node
->count(), min_children
);
49 EXPECT_LE(node
->count(), max_children
);
50 CheckBoundsConsistent(node
);
51 for (size_t i
= 0; i
< node
->count(); ++i
)
52 ValidateNode(node
->child(i
), min_children
, max_children
);
56 // Check bounds are consistent with children bounds, and other checks
57 // convenient to do while enumerating the children of node.
58 void CheckBoundsConsistent(const RTreeBase::Node
* node
) {
59 EXPECT_FALSE(node
->rect().IsEmpty());
61 for (size_t i
= 0; i
< node
->count(); ++i
) {
62 const RTreeBase::NodeBase
* child_node
= node
->child(i
);
63 check_bounds
.Union(child_node
->rect());
64 EXPECT_EQ(node
->Level() - 1, child_node
->Level());
65 EXPECT_EQ(node
, child_node
->parent());
67 EXPECT_EQ(check_bounds
, node
->rect());
70 // Adds count squares stacked around the point (0,0) with key equal to width.
71 void AddStackedSquares(RT
* rt
, int count
) {
72 for (int i
= 1; i
<= count
; ++i
) {
73 rt
->Insert(Rect(0, 0, i
, i
), i
);
74 ValidateRTree(static_cast<RTreeBase
*>(rt
));
78 // Given an unordered list of matching keys, verifies that it contains all
79 // values [1..length] for the length of that list.
80 void VerifyAllKeys(const RT::Matches
& keys
) {
81 for (size_t i
= 1; i
<= keys
.size(); ++i
)
82 EXPECT_EQ(1U, keys
.count(i
));
85 // Given a node and a rectangle, builds an expanded rectangle list where the
86 // ith element of the vector is the union of the rectangle of the ith child of
87 // the node and the argument rectangle.
88 void BuildExpandedRects(RTreeBase::Node
* node
,
90 std::vector
<Rect
>* expanded_rects
) {
91 expanded_rects
->clear();
92 expanded_rects
->reserve(node
->count());
93 for (size_t i
= 0; i
< node
->count(); ++i
) {
94 Rect
expanded_rect(rect
);
95 expanded_rect
.Union(node
->child(i
)->rect());
96 expanded_rects
->push_back(expanded_rect
);
101 class RTreeNodeTest
: public RTreeTest
{
103 typedef RTreeBase::NodeBase RTreeNodeBase
;
104 typedef RT::Record RTreeRecord
;
105 typedef RTreeBase::Node RTreeNode
;
106 typedef RTreeBase::Node::Rects RTreeRects
;
107 typedef RTreeBase::Nodes RTreeNodes
;
109 // Accessors to private members of RTree::Node.
110 const RTreeRecord
* record(RTreeNode
* node
, size_t i
) {
111 return static_cast<const RTreeRecord
*>(node
->child(i
));
114 // Provides access for tests to private methods of RTree::Node.
115 scoped_ptr
<RTreeNode
> NewNodeAtLevel(size_t level
) {
116 return make_scoped_ptr(new RTreeBase::Node(level
));
119 void NodeRecomputeLocalBounds(RTreeNodeBase
* node
) {
120 node
->RecomputeLocalBounds();
123 bool NodeCompareVertical(RTreeNodeBase
* a
, RTreeNodeBase
* b
) {
124 return RTreeBase::Node::CompareVertical(a
, b
);
127 bool NodeCompareHorizontal(RTreeNodeBase
* a
, RTreeNodeBase
* b
) {
128 return RTreeBase::Node::CompareHorizontal(a
, b
);
131 bool NodeCompareCenterDistanceFromParent(
132 const RTreeNodeBase
* a
, const RTreeNodeBase
* b
) {
133 return RTreeBase::Node::CompareCenterDistanceFromParent(a
, b
);
136 int NodeOverlapIncreaseToAdd(RTreeNode
* node
,
138 const RTreeNodeBase
* candidate_node
,
139 const Rect
& expanded_rect
) {
140 return node
->OverlapIncreaseToAdd(rect
, candidate_node
, expanded_rect
);
143 void NodeBuildLowBounds(const std::vector
<RTreeNodeBase
*>& vertical_sort
,
144 const std::vector
<RTreeNodeBase
*>& horizontal_sort
,
145 RTreeRects
* vertical_bounds
,
146 RTreeRects
* horizontal_bounds
) {
147 RTreeBase::Node::BuildLowBounds(
148 vertical_sort
, horizontal_sort
, vertical_bounds
, horizontal_bounds
);
151 void NodeBuildHighBounds(const std::vector
<RTreeNodeBase
*>& vertical_sort
,
152 const std::vector
<RTreeNodeBase
*>& horizontal_sort
,
153 RTreeRects
* vertical_bounds
,
154 RTreeRects
* horizontal_bounds
) {
155 RTreeBase::Node::BuildHighBounds(
156 vertical_sort
, horizontal_sort
, vertical_bounds
, horizontal_bounds
);
159 int NodeSmallestMarginSum(size_t start_index
,
161 const RTreeRects
& low_bounds
,
162 const RTreeRects
& high_bounds
) {
163 return RTreeBase::Node::SmallestMarginSum(
164 start_index
, end_index
, low_bounds
, high_bounds
);
167 size_t NodeChooseSplitIndex(size_t min_children
,
169 const RTreeRects
& low_bounds
,
170 const RTreeRects
& high_bounds
) {
171 return RTreeBase::Node::ChooseSplitIndex(
172 min_children
, max_children
, low_bounds
, high_bounds
);
175 scoped_ptr
<RTreeNodeBase
> NodeDivideChildren(
177 const RTreeRects
& low_bounds
,
178 const RTreeRects
& high_bounds
,
179 const std::vector
<RTreeNodeBase
*>& sorted_children
,
180 size_t split_index
) {
181 return node
->DivideChildren(
182 low_bounds
, high_bounds
, sorted_children
, split_index
);
185 RTreeNode
* NodeLeastOverlapIncrease(RTreeNode
* node
,
186 const Rect
& node_rect
,
187 const RTreeRects
& expanded_rects
) {
188 return node
->LeastOverlapIncrease(node_rect
, expanded_rects
);
191 RTreeNode
* NodeLeastAreaEnlargement(RTreeNode
* node
,
192 const Rect
& node_rect
,
193 const RTreeRects
& expanded_rects
) {
194 return node
->LeastAreaEnlargement(node_rect
, expanded_rects
);
198 // RTreeNodeTest --------------------------------------------------------------
200 TEST_F(RTreeNodeTest
, RemoveNodesForReinsert
) {
201 // Make a leaf node for testing removal from.
202 scoped_ptr
<RTreeNode
> test_node(new RTreeNode
);
203 // Build 20 record nodes with rectangle centers going from (1,1) to (20,20)
204 for (int i
= 1; i
<= 20; ++i
)
205 test_node
->AddChild(scoped_ptr
<RTreeNodeBase
>(
206 new RTreeRecord(Rect(i
- 1, i
- 1, 2, 2), i
)));
208 // Quick verification of the node before removing children.
209 ValidateNode(test_node
.get(), 1U, 20U);
210 // Use a scoped vector to delete all children that get removed from the Node.
212 test_node
->RemoveNodesForReinsert(1, &removals
);
213 // Should have gotten back 1 node pointer.
214 EXPECT_EQ(1U, removals
.size());
215 // There should be 19 left in the test_node.
216 EXPECT_EQ(19U, test_node
->count());
217 // If we fix up the bounds on the test_node, it should verify.
218 NodeRecomputeLocalBounds(test_node
.get());
219 ValidateNode(test_node
.get(), 2U, 20U);
220 // The node we removed should be node 10, as it was exactly in the center.
221 EXPECT_EQ(10, static_cast<RTreeRecord
*>(removals
[0])->key());
223 // Now remove the next 2.
225 test_node
->RemoveNodesForReinsert(2, &removals
);
226 EXPECT_EQ(2U, removals
.size());
227 EXPECT_EQ(17U, test_node
->count());
228 NodeRecomputeLocalBounds(test_node
.get());
229 ValidateNode(test_node
.get(), 2U, 20U);
230 // Lastly the 2 nodes we should have gotten back are keys 9 and 11, as their
231 // centers were the closest to the center of the node bounding box.
232 base::hash_set
<intptr_t> results_hash
;
233 results_hash
.insert(static_cast<RTreeRecord
*>(removals
[0])->key());
234 results_hash
.insert(static_cast<RTreeRecord
*>(removals
[1])->key());
235 EXPECT_EQ(1U, results_hash
.count(9));
236 EXPECT_EQ(1U, results_hash
.count(11));
239 TEST_F(RTreeNodeTest
, CompareVertical
) {
240 // One rect with lower y than another should always sort lower.
241 RTreeRecord
low(Rect(0, 1, 10, 10), 1);
242 RTreeRecord
middle(Rect(0, 5, 10, 10), 5);
243 EXPECT_TRUE(NodeCompareVertical(&low
, &middle
));
244 EXPECT_FALSE(NodeCompareVertical(&middle
, &low
));
246 // Try a non-overlapping higher-y rectangle.
247 RTreeRecord
high(Rect(-10, 20, 10, 1), 10);
248 EXPECT_TRUE(NodeCompareVertical(&low
, &high
));
249 EXPECT_FALSE(NodeCompareVertical(&high
, &low
));
251 // Ties are broken by lowest bottom y value.
252 RTreeRecord
shorter_tie(Rect(10, 1, 100, 2), 2);
253 EXPECT_TRUE(NodeCompareVertical(&shorter_tie
, &low
));
254 EXPECT_FALSE(NodeCompareVertical(&low
, &shorter_tie
));
257 TEST_F(RTreeNodeTest
, CompareHorizontal
) {
258 // One rect with lower x than another should always sort lower than higher x.
259 RTreeRecord
low(Rect(1, 0, 10, 10), 1);
260 RTreeRecord
middle(Rect(5, 0, 10, 10), 5);
261 EXPECT_TRUE(NodeCompareHorizontal(&low
, &middle
));
262 EXPECT_FALSE(NodeCompareHorizontal(&middle
, &low
));
264 // Try a non-overlapping higher-x rectangle.
265 RTreeRecord
high(Rect(20, -10, 1, 10), 10);
266 EXPECT_TRUE(NodeCompareHorizontal(&low
, &high
));
267 EXPECT_FALSE(NodeCompareHorizontal(&high
, &low
));
269 // Ties are broken by lowest bottom x value.
270 RTreeRecord
shorter_tie(Rect(1, 10, 2, 100), 2);
271 EXPECT_TRUE(NodeCompareHorizontal(&shorter_tie
, &low
));
272 EXPECT_FALSE(NodeCompareHorizontal(&low
, &shorter_tie
));
275 TEST_F(RTreeNodeTest
, CompareCenterDistanceFromParent
) {
276 // Create a test node we can add children to, for distance comparisons.
277 scoped_ptr
<RTreeNode
> parent(new RTreeNode
);
279 // Add three children, one each with centers at (0, 0), (10, 10), (-9, -9),
280 // around which a bounding box will be centered at (0, 0)
281 scoped_ptr
<RTreeRecord
> center_zero(new RTreeRecord(Rect(-1, -1, 2, 2), 1));
282 parent
->AddChild(center_zero
.Pass());
284 scoped_ptr
<RTreeRecord
> center_positive(new RTreeRecord(Rect(9, 9, 2, 2), 2));
285 parent
->AddChild(center_positive
.Pass());
287 scoped_ptr
<RTreeRecord
> center_negative(
288 new RTreeRecord(Rect(-10, -10, 2, 2), 3));
289 parent
->AddChild(center_negative
.Pass());
291 ValidateNode(parent
.get(), 1U, 5U);
292 EXPECT_EQ(Rect(-10, -10, 21, 21), parent
->rect());
295 NodeCompareCenterDistanceFromParent(parent
->child(0), parent
->child(1)));
297 NodeCompareCenterDistanceFromParent(parent
->child(1), parent
->child(0)));
299 NodeCompareCenterDistanceFromParent(parent
->child(0), parent
->child(2)));
301 NodeCompareCenterDistanceFromParent(parent
->child(2), parent
->child(0)));
303 NodeCompareCenterDistanceFromParent(parent
->child(2), parent
->child(1)));
305 NodeCompareCenterDistanceFromParent(parent
->child(1), parent
->child(2)));
308 TEST_F(RTreeNodeTest
, OverlapIncreaseToAdd
) {
309 // Create a test node with three children, for overlap comparisons.
310 scoped_ptr
<RTreeNode
> parent(new RTreeNode
);
312 // Add three children, each 4 wide and tall, at (0, 0), (3, 3), (6, 6) with
313 // overlapping corners.
314 Rect
top(0, 0, 4, 4);
315 parent
->AddChild(scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(top
, 1)));
316 Rect
middle(3, 3, 4, 4);
317 parent
->AddChild(scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(middle
, 2)));
318 Rect
bottom(6, 6, 4, 4);
319 parent
->AddChild(scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(bottom
, 3)));
320 ValidateNode(parent
.get(), 1U, 5U);
322 // Test a rect in corner.
323 Rect
corner(0, 0, 1, 1);
325 expanded
.Union(corner
);
326 // It should not add any overlap to add this to the first child at (0, 0).
327 EXPECT_EQ(0, NodeOverlapIncreaseToAdd(
328 parent
.get(), corner
, parent
->child(0), expanded
));
331 expanded
.Union(corner
);
332 // Overlap for middle rectangle should increase from 2 pixels at (3, 3) and
333 // (6, 6) to 17 pixels, as it will now cover 4x4 rectangle top,
334 // so a change of +15.
335 EXPECT_EQ(15, NodeOverlapIncreaseToAdd(
336 parent
.get(), corner
, parent
->child(1), expanded
));
339 expanded
.Union(corner
);
340 // Overlap for bottom rectangle should increase from 1 pixel at (6, 6) to
341 // 32 pixels, as it will now cover both 4x4 rectangles top and middle,
342 // so a change of 31.
343 EXPECT_EQ(31, NodeOverlapIncreaseToAdd(
344 parent
.get(), corner
, parent
->child(2), expanded
));
346 // Test a rect that doesn't overlap with anything, in the far right corner.
347 Rect
far_corner(9, 0, 1, 1);
349 expanded
.Union(far_corner
);
350 // Overlap of top should go from 1 to 4, as it will now cover the entire first
351 // row of pixels in middle.
352 EXPECT_EQ(3, NodeOverlapIncreaseToAdd(
353 parent
.get(), far_corner
, parent
->child(0), expanded
));
356 expanded
.Union(far_corner
);
357 // Overlap of middle should go from 2 to 8, as it will cover the rightmost 4
358 // pixels of top and the top 4 pixels of bottom as it expands.
359 EXPECT_EQ(6, NodeOverlapIncreaseToAdd(
360 parent
.get(), far_corner
, parent
->child(1), expanded
));
363 expanded
.Union(far_corner
);
364 // Overlap of bottom should go from 1 to 4, as it will now cover the rightmost
365 // 4 pixels of middle.
366 EXPECT_EQ(3, NodeOverlapIncreaseToAdd(
367 parent
.get(), far_corner
, parent
->child(2), expanded
));
370 TEST_F(RTreeNodeTest
, BuildLowBounds
) {
373 for (int i
= 1; i
<= 10; ++i
)
374 records
.push_back(new RTreeRecord(Rect(0, 0, i
, i
), i
));
376 RTreeRects vertical_bounds
;
377 RTreeRects horizontal_bounds
;
379 records
.get(), records
.get(), &vertical_bounds
, &horizontal_bounds
);
380 for (int i
= 0; i
< 10; ++i
) {
381 EXPECT_EQ(records
[i
]->rect(), vertical_bounds
[i
]);
382 EXPECT_EQ(records
[i
]->rect(), horizontal_bounds
[i
]);
386 TEST_F(RTreeNodeTest
, BuildHighBounds
) {
389 for (int i
= 0; i
< 25; ++i
)
390 records
.push_back(new RTreeRecord(Rect(i
, i
, 25 - i
, 25 - i
), i
));
392 RTreeRects vertical_bounds
;
393 RTreeRects horizontal_bounds
;
395 records
.get(), records
.get(), &vertical_bounds
, &horizontal_bounds
);
396 for (int i
= 0; i
< 25; ++i
) {
397 EXPECT_EQ(records
[i
]->rect(), vertical_bounds
[i
]);
398 EXPECT_EQ(records
[i
]->rect(), horizontal_bounds
[i
]);
402 TEST_F(RTreeNodeTest
, ChooseSplitAxisAndIndexVertical
) {
403 RTreeRects low_vertical_bounds
;
404 RTreeRects high_vertical_bounds
;
405 RTreeRects low_horizontal_bounds
;
406 RTreeRects high_horizontal_bounds
;
407 // In this test scenario we describe a mirrored, stacked configuration of
408 // horizontal, 1 pixel high rectangles labeled a-f like this:
410 // shape: | v sort: | h sort: |
411 // -------+---------+---------+
419 // These are already sorted vertically from top to bottom. Bounding rectangles
420 // of these vertically sorted will be 5 wide, i tall bounding boxes.
421 for (int i
= 0; i
< 6; ++i
) {
422 low_vertical_bounds
.push_back(Rect(0, 0, 5, i
+ 1));
423 high_vertical_bounds
.push_back(Rect(0, i
, 5, 6 - i
));
426 // Low bounds of horizontal sort start with bounds of box a and then jump to
427 // cover everything, as box f is second in horizontal sort.
428 low_horizontal_bounds
.push_back(Rect(0, 0, 5, 1));
429 for (int i
= 0; i
< 5; ++i
)
430 low_horizontal_bounds
.push_back(Rect(0, 0, 5, 6));
432 // High horizontal bounds are hand-calculated.
433 high_horizontal_bounds
.push_back(Rect(0, 0, 5, 6));
434 high_horizontal_bounds
.push_back(Rect(0, 1, 5, 5));
435 high_horizontal_bounds
.push_back(Rect(1, 1, 3, 4));
436 high_horizontal_bounds
.push_back(Rect(1, 2, 3, 3));
437 high_horizontal_bounds
.push_back(Rect(2, 2, 1, 2));
438 high_horizontal_bounds
.push_back(Rect(2, 3, 1, 1));
440 int smallest_vertical_margin
=
441 NodeSmallestMarginSum(2, 3, low_vertical_bounds
, high_vertical_bounds
);
442 int smallest_horizontal_margin
= NodeSmallestMarginSum(
443 2, 3, low_horizontal_bounds
, high_horizontal_bounds
);
444 EXPECT_LT(smallest_vertical_margin
, smallest_horizontal_margin
);
448 NodeChooseSplitIndex(2, 5, low_vertical_bounds
, high_vertical_bounds
));
451 TEST_F(RTreeNodeTest
, ChooseSplitAxisAndIndexHorizontal
) {
452 RTreeRects low_vertical_bounds
;
453 RTreeRects high_vertical_bounds
;
454 RTreeRects low_horizontal_bounds
;
455 RTreeRects high_horizontal_bounds
;
456 // We rotate the shape from ChooseSplitAxisAndIndexVertical to test
457 // horizontal split axis detection:
466 // v sort: | 024531 |
467 // h sort: | 012345 |
470 // Low bounds of vertical sort start with bounds of box a and then jump to
471 // cover everything, as box f is second in vertical sort.
472 low_vertical_bounds
.push_back(Rect(0, 0, 1, 5));
473 for (int i
= 0; i
< 5; ++i
)
474 low_vertical_bounds
.push_back(Rect(0, 0, 6, 5));
476 // High vertical bounds are hand-calculated.
477 high_vertical_bounds
.push_back(Rect(0, 0, 6, 5));
478 high_vertical_bounds
.push_back(Rect(1, 0, 5, 5));
479 high_vertical_bounds
.push_back(Rect(1, 1, 4, 3));
480 high_vertical_bounds
.push_back(Rect(2, 1, 3, 3));
481 high_vertical_bounds
.push_back(Rect(2, 2, 2, 1));
482 high_vertical_bounds
.push_back(Rect(3, 2, 1, 1));
484 // These are already sorted horizontally from left to right. Bounding
485 // rectangles of these horizontally sorted will be i wide, 5 tall bounding
487 for (int i
= 0; i
< 6; ++i
) {
488 low_horizontal_bounds
.push_back(Rect(0, 0, i
+ 1, 5));
489 high_horizontal_bounds
.push_back(Rect(i
, 0, 6 - i
, 5));
492 int smallest_vertical_margin
=
493 NodeSmallestMarginSum(2, 3, low_vertical_bounds
, high_vertical_bounds
);
494 int smallest_horizontal_margin
= NodeSmallestMarginSum(
495 2, 3, low_horizontal_bounds
, high_horizontal_bounds
);
497 EXPECT_GT(smallest_vertical_margin
, smallest_horizontal_margin
);
500 NodeChooseSplitIndex(
501 2, 5, low_horizontal_bounds
, high_horizontal_bounds
));
504 TEST_F(RTreeNodeTest
, DivideChildren
) {
505 // Create a test node to split.
506 scoped_ptr
<RTreeNode
> test_node(new RTreeNode
);
507 std::vector
<RTreeNodeBase
*> sorted_children
;
508 RTreeRects low_bounds
;
509 RTreeRects high_bounds
;
510 // Insert 10 record nodes, also inserting them into our children array.
511 for (int i
= 1; i
<= 10; ++i
) {
512 scoped_ptr
<RTreeRecord
> record(new RTreeRecord(Rect(0, 0, i
, i
), i
));
513 sorted_children
.push_back(record
.get());
514 test_node
->AddChild(record
.Pass());
515 low_bounds
.push_back(Rect(0, 0, i
, i
));
516 high_bounds
.push_back(Rect(0, 0, 10, 10));
518 // Split the children in half.
519 scoped_ptr
<RTreeNodeBase
> split_node_base(NodeDivideChildren(
520 test_node
.get(), low_bounds
, high_bounds
, sorted_children
, 5));
521 RTreeNode
* split_node
= static_cast<RTreeNode
*>(split_node_base
.get());
522 // Both nodes should be valid.
523 ValidateNode(test_node
.get(), 1U, 10U);
524 ValidateNode(split_node
, 1U, 10U);
525 // Both nodes should have five children.
526 EXPECT_EQ(5U, test_node
->count());
527 EXPECT_EQ(5U, split_node
->count());
528 // Test node should have children 1-5, split node should have children 6-10.
529 for (int i
= 0; i
< 5; ++i
) {
530 EXPECT_EQ(i
+ 1, record(test_node
.get(), i
)->key());
531 EXPECT_EQ(i
+ 6, record(split_node
, i
)->key());
535 TEST_F(RTreeNodeTest
, RemoveChildNoOrphans
) {
536 scoped_ptr
<RTreeNode
> test_parent(new RTreeNode
);
537 test_parent
->AddChild(
538 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 0, 1, 1), 1)));
539 test_parent
->AddChild(
540 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 0, 2, 2), 2)));
541 test_parent
->AddChild(
542 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 0, 3, 3), 3)));
543 ValidateNode(test_parent
.get(), 1U, 5U);
547 // Remove the middle node.
548 scoped_ptr
<RTreeNodeBase
> middle_child(
549 test_parent
->RemoveChild(test_parent
->child(1), &orphans
));
550 EXPECT_EQ(0U, orphans
.size());
551 EXPECT_EQ(2U, test_parent
->count());
552 NodeRecomputeLocalBounds(test_parent
.get());
553 ValidateNode(test_parent
.get(), 1U, 5U);
555 // Remove the end node.
556 scoped_ptr
<RTreeNodeBase
> end_child(
557 test_parent
->RemoveChild(test_parent
->child(1), &orphans
));
558 EXPECT_EQ(0U, orphans
.size());
559 EXPECT_EQ(1U, test_parent
->count());
560 NodeRecomputeLocalBounds(test_parent
.get());
561 ValidateNode(test_parent
.get(), 1U, 5U);
563 // Remove the first node.
564 scoped_ptr
<RTreeNodeBase
> first_child(
565 test_parent
->RemoveChild(test_parent
->child(0), &orphans
));
566 EXPECT_EQ(0U, orphans
.size());
567 EXPECT_EQ(0U, test_parent
->count());
570 TEST_F(RTreeNodeTest
, RemoveChildOrphans
) {
571 // Build binary tree of Nodes of height 4, keeping weak pointers to the
572 // Levels 0 and 1 Nodes and the Records so we can test removal of them below.
573 std::vector
<RTreeNode
*> level_1_children
;
574 std::vector
<RTreeNode
*> level_0_children
;
575 std::vector
<RTreeRecord
*> records
;
577 scoped_ptr
<RTreeNode
> root(NewNodeAtLevel(2));
578 for (int i
= 0; i
< 2; ++i
) {
579 scoped_ptr
<RTreeNode
> level_1_child(NewNodeAtLevel(1));
580 for (int j
= 0; j
< 2; ++j
) {
581 scoped_ptr
<RTreeNode
> level_0_child(new RTreeNode
);
582 for (int k
= 0; k
< 2; ++k
) {
583 scoped_ptr
<RTreeRecord
> record(
584 new RTreeRecord(Rect(0, 0, id
, id
), id
));
586 records
.push_back(record
.get());
587 level_0_child
->AddChild(record
.Pass());
589 level_0_children
.push_back(level_0_child
.get());
590 level_1_child
->AddChild(level_0_child
.Pass());
592 level_1_children
.push_back(level_1_child
.get());
593 root
->AddChild(level_1_child
.Pass());
596 // This should now be a valid tree structure.
597 ValidateNode(root
.get(), 2U, 2U);
598 EXPECT_EQ(2U, level_1_children
.size());
599 EXPECT_EQ(4U, level_0_children
.size());
600 EXPECT_EQ(8U, records
.size());
602 // Now remove all of the level 0 nodes so we get the record nodes as orphans.
604 for (size_t i
= 0; i
< level_0_children
.size(); ++i
)
605 level_1_children
[i
/ 2]->RemoveChild(level_0_children
[i
], &orphans
);
607 // Orphans should be all 8 records but no order guarantee.
608 EXPECT_EQ(8U, orphans
.size());
609 for (std::vector
<RTreeRecord
*>::iterator it
= records
.begin();
610 it
!= records
.end(); ++it
) {
611 RTreeNodes::iterator orphan
=
612 std::find(orphans
.begin(), orphans
.end(), *it
);
613 EXPECT_NE(orphan
, orphans
.end());
614 orphans
.erase(orphan
);
616 EXPECT_EQ(0U, orphans
.size());
619 TEST_F(RTreeNodeTest
, RemoveAndReturnLastChild
) {
620 scoped_ptr
<RTreeNode
> test_parent(new RTreeNode
);
621 test_parent
->AddChild(
622 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 0, 1, 1), 1)));
623 test_parent
->AddChild(
624 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 0, 2, 2), 2)));
625 test_parent
->AddChild(
626 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 0, 3, 3), 3)));
627 ValidateNode(test_parent
.get(), 1U, 5U);
629 RTreeNodeBase
* child
= test_parent
->child(2);
630 scoped_ptr
<RTreeNodeBase
> last_child(test_parent
->RemoveAndReturnLastChild());
631 EXPECT_EQ(child
, last_child
.get());
632 EXPECT_EQ(2U, test_parent
->count());
633 NodeRecomputeLocalBounds(test_parent
.get());
634 ValidateNode(test_parent
.get(), 1U, 5U);
636 child
= test_parent
->child(1);
637 scoped_ptr
<RTreeNodeBase
> middle_child(
638 test_parent
->RemoveAndReturnLastChild());
639 EXPECT_EQ(child
, middle_child
.get());
640 EXPECT_EQ(1U, test_parent
->count());
641 NodeRecomputeLocalBounds(test_parent
.get());
642 ValidateNode(test_parent
.get(), 1U, 5U);
644 child
= test_parent
->child(0);
645 scoped_ptr
<RTreeNodeBase
> first_child(
646 test_parent
->RemoveAndReturnLastChild());
647 EXPECT_EQ(child
, first_child
.get());
648 EXPECT_EQ(0U, test_parent
->count());
651 TEST_F(RTreeNodeTest
, LeastOverlapIncrease
) {
652 scoped_ptr
<RTreeNode
> test_parent(NewNodeAtLevel(1));
653 // Construct 4 nodes with 1x2 rects spaced horizontally 1 pixel apart, or:
658 for (int i
= 0; i
< 4; ++i
) {
659 scoped_ptr
<RTreeNode
> node(new RTreeNode
);
660 scoped_ptr
<RTreeRecord
> record(
661 new RTreeRecord(Rect(i
* 2, 0, 1, 2), i
+ 1));
662 node
->AddChild(record
.Pass());
663 test_parent
->AddChild(node
.Pass());
666 ValidateNode(test_parent
.get(), 1U, 5U);
668 // Test rect at (7, 0) should require minimum overlap on the part of the
669 // fourth rectangle to add:
674 Rect
test_rect_far(7, 0, 1, 1);
675 RTreeRects expanded_rects
;
676 BuildExpandedRects(test_parent
.get(), test_rect_far
, &expanded_rects
);
677 RTreeNode
* result
= NodeLeastOverlapIncrease(
678 test_parent
.get(), test_rect_far
, expanded_rects
);
679 EXPECT_EQ(4, record(result
, 0)->key());
681 // Test rect covering the bottom half of all children should be a 4-way tie,
682 // so LeastOverlapIncrease should return NULL:
687 Rect
test_rect_tie(0, 1, 7, 1);
688 BuildExpandedRects(test_parent
.get(), test_rect_tie
, &expanded_rects
);
689 result
= NodeLeastOverlapIncrease(
690 test_parent
.get(), test_rect_tie
, expanded_rects
);
691 EXPECT_TRUE(result
== NULL
);
693 // Test rect completely inside c should return the third rectangle:
698 Rect
test_rect_inside(4, 0, 1, 1);
699 BuildExpandedRects(test_parent
.get(), test_rect_inside
, &expanded_rects
);
700 result
= NodeLeastOverlapIncrease(
701 test_parent
.get(), test_rect_inside
, expanded_rects
);
702 EXPECT_EQ(3, record(result
, 0)->key());
704 // Add a rectangle that overlaps completely with rectangle c, to test
705 // when there is a tie between two completely contained rectangles:
710 scoped_ptr
<RTreeNode
> record_parent(new RTreeNode
);
711 record_parent
->AddChild(
712 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(4, 0, 2, 2), 9)));
713 test_parent
->AddChild(record_parent
.Pass());
714 BuildExpandedRects(test_parent
.get(), test_rect_inside
, &expanded_rects
);
715 result
= NodeLeastOverlapIncrease(
716 test_parent
.get(), test_rect_inside
, expanded_rects
);
717 EXPECT_TRUE(result
== NULL
);
720 TEST_F(RTreeNodeTest
, LeastAreaEnlargement
) {
721 scoped_ptr
<RTreeNode
> test_parent(NewNodeAtLevel(1));
722 // Construct 4 nodes in a cross-hairs style configuration:
728 scoped_ptr
<RTreeNode
> node(new RTreeNode
);
730 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(1, 0, 1, 1), 1)));
731 test_parent
->AddChild(node
.Pass());
732 node
.reset(new RTreeNode
);
734 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 1, 1, 1), 2)));
735 test_parent
->AddChild(node
.Pass());
736 node
.reset(new RTreeNode
);
738 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(2, 1, 1, 1), 3)));
739 test_parent
->AddChild(node
.Pass());
740 node
.reset(new RTreeNode
);
742 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(1, 2, 1, 1), 4)));
743 test_parent
->AddChild(node
.Pass());
745 ValidateNode(test_parent
.get(), 1U, 5U);
747 // Test rect at (1, 3) should require minimum area to add to Node d:
754 Rect
test_rect_below(1, 3, 1, 1);
755 RTreeRects expanded_rects
;
756 BuildExpandedRects(test_parent
.get(), test_rect_below
, &expanded_rects
);
757 RTreeNode
* result
= NodeLeastAreaEnlargement(
758 test_parent
.get(), test_rect_below
, expanded_rects
);
759 EXPECT_EQ(4, record(result
, 0)->key());
761 // Test rect completely inside b should require minimum area to add to Node b:
767 Rect
test_rect_inside(0, 1, 1, 1);
768 BuildExpandedRects(test_parent
.get(), test_rect_inside
, &expanded_rects
);
769 result
= NodeLeastAreaEnlargement(
770 test_parent
.get(), test_rect_inside
, expanded_rects
);
771 EXPECT_EQ(2, record(result
, 0)->key());
773 // Add e at (0, 1) to overlap b and c, to test tie-breaking:
779 node
.reset(new RTreeNode
);
781 scoped_ptr
<RTreeNodeBase
>(new RTreeRecord(Rect(0, 1, 3, 1), 7)));
782 test_parent
->AddChild(node
.Pass());
784 ValidateNode(test_parent
.get(), 1U, 5U);
786 // Test rect at (3, 1) should tie between c and e, but c has smaller area so
787 // the algorithm should select c:
794 Rect
test_rect_tie_breaker(3, 1, 1, 1);
795 BuildExpandedRects(test_parent
.get(), test_rect_tie_breaker
, &expanded_rects
);
796 result
= NodeLeastAreaEnlargement(
797 test_parent
.get(), test_rect_tie_breaker
, expanded_rects
);
798 EXPECT_EQ(3, record(result
, 0)->key());
801 // RTreeTest ------------------------------------------------------------------
803 // An empty RTree should never return AppendIntersectingRecords results, and
804 // RTrees should be empty upon construction.
805 TEST_F(RTreeTest
, AppendIntersectingRecordsOnEmptyTree
) {
809 Rect
test_rect(25, 25);
810 rt
.AppendIntersectingRecords(test_rect
, &results
);
811 EXPECT_EQ(0U, results
.size());
815 // Clear should empty the tree, meaning that all queries should not return
817 TEST_F(RTreeTest
, ClearEmptiesTreeOfSingleNode
) {
819 rt
.Insert(Rect(0, 0, 100, 100), 1);
822 Rect
test_rect(1, 1);
823 rt
.AppendIntersectingRecords(test_rect
, &results
);
824 EXPECT_EQ(0U, results
.size());
828 // Even with a complex internal structure, clear should empty the tree, meaning
829 // that all queries should not return results after.
830 TEST_F(RTreeTest
, ClearEmptiesTreeOfManyNodes
) {
832 AddStackedSquares(&rt
, 100);
835 Rect
test_rect(1, 1);
836 rt
.AppendIntersectingRecords(test_rect
, &results
);
837 EXPECT_EQ(0U, results
.size());
841 // Duplicate inserts should overwrite previous inserts.
842 TEST_F(RTreeTest
, DuplicateInsertsOverwrite
) {
844 // Add 100 stacked squares, but always with duplicate key of 0.
845 for (int i
= 1; i
<= 100; ++i
) {
846 rt
.Insert(Rect(0, 0, i
, i
), 0);
850 Rect
test_rect(1, 1);
851 rt
.AppendIntersectingRecords(test_rect
, &results
);
852 EXPECT_EQ(1U, results
.size());
853 EXPECT_EQ(1U, results
.count(0));
856 // Call Remove() once on something that's been inserted repeatedly.
857 TEST_F(RTreeTest
, DuplicateInsertRemove
) {
859 AddStackedSquares(&rt
, 25);
860 for (int i
= 1; i
<= 100; ++i
) {
861 rt
.Insert(Rect(0, 0, i
, i
), 26);
866 Rect
test_rect(1, 1);
867 rt
.AppendIntersectingRecords(test_rect
, &results
);
868 EXPECT_EQ(25U, results
.size());
869 VerifyAllKeys(results
);
872 // Call Remove() repeatedly on something that's been inserted once.
873 TEST_F(RTreeTest
, InsertDuplicateRemove
) {
875 AddStackedSquares(&rt
, 101);
876 for (int i
= 0; i
< 100; ++i
) {
881 Rect
test_rect(1, 1);
882 rt
.AppendIntersectingRecords(test_rect
, &results
);
883 EXPECT_EQ(100U, results
.size());
884 VerifyAllKeys(results
);
887 // Stacked rects should meet all matching queries regardless of nesting.
888 TEST_F(RTreeTest
, AppendIntersectingRecordsStackedSquaresNestedHit
) {
890 AddStackedSquares(&rt
, 100);
892 Rect
test_rect(1, 1);
893 rt
.AppendIntersectingRecords(test_rect
, &results
);
894 EXPECT_EQ(100U, results
.size());
895 VerifyAllKeys(results
);
898 // Stacked rects should meet all matching queries when contained completely by
899 // the query rectangle.
900 TEST_F(RTreeTest
, AppendIntersectingRecordsStackedSquaresContainedHit
) {
902 AddStackedSquares(&rt
, 100);
904 Rect
test_rect(0, 0, 100, 100);
905 rt
.AppendIntersectingRecords(test_rect
, &results
);
906 EXPECT_EQ(100U, results
.size());
907 VerifyAllKeys(results
);
910 // Stacked rects should miss a missing query when the query has no intersection
912 TEST_F(RTreeTest
, AppendIntersectingRecordsStackedSquaresCompleteMiss
) {
914 AddStackedSquares(&rt
, 100);
916 Rect
test_rect(150, 150, 100, 100);
917 rt
.AppendIntersectingRecords(test_rect
, &results
);
918 EXPECT_EQ(0U, results
.size());
921 // Removing half the nodes after insertion should still result in a valid tree.
922 TEST_F(RTreeTest
, RemoveHalfStackedRects
) {
924 AddStackedSquares(&rt
, 200);
925 for (int i
= 101; i
<= 200; ++i
) {
930 Rect
test_rect(1, 1);
931 rt
.AppendIntersectingRecords(test_rect
, &results
);
932 EXPECT_EQ(100U, results
.size());
933 VerifyAllKeys(results
);
935 // Add the nodes back in.
936 for (int i
= 101; i
<= 200; ++i
) {
937 rt
.Insert(Rect(0, 0, i
, i
), i
);
941 rt
.AppendIntersectingRecords(test_rect
, &results
);
942 EXPECT_EQ(200U, results
.size());
943 VerifyAllKeys(results
);
946 TEST_F(RTreeTest
, InsertDupToRoot
) {
948 rt
.Insert(Rect(0, 0, 1, 2), 1);
950 rt
.Insert(Rect(0, 0, 2, 1), 1);
954 TEST_F(RTreeTest
, InsertNegativeCoordsRect
) {
956 for (int i
= 1; i
<= 100; ++i
) {
957 rt
.Insert(Rect(-i
, -i
, i
, i
), (i
* 2) - 1);
959 rt
.Insert(Rect(0, 0, i
, i
), i
* 2);
963 Rect
test_rect(-1, -1, 2, 2);
964 rt
.AppendIntersectingRecords(test_rect
, &results
);
965 EXPECT_EQ(200U, results
.size());
966 VerifyAllKeys(results
);
969 TEST_F(RTreeTest
, RemoveNegativeCoordsRect
) {
972 // Add 100 positive stacked squares.
973 AddStackedSquares(&rt
, 100);
975 // Now add 100 negative stacked squares.
976 for (int i
= 101; i
<= 200; ++i
) {
977 rt
.Insert(Rect(100 - i
, 100 - i
, i
- 100, i
- 100), 301 - i
);
981 // Now remove half of the negative squares.
982 for (int i
= 101; i
<= 150; ++i
) {
987 // Queries should return 100 positive and 50 negative stacked squares.
989 Rect
test_rect(-1, -1, 2, 2);
990 rt
.AppendIntersectingRecords(test_rect
, &results
);
991 EXPECT_EQ(150U, results
.size());
992 VerifyAllKeys(results
);
995 TEST_F(RTreeTest
, InsertEmptyRectReplacementRemovesKey
) {
997 AddStackedSquares(&rt
, 50);
1000 // Replace last square with empty rect.
1001 rt
.Insert(Rect(), 50);
1004 // Now query large area to get all rects in tree.
1005 RT::Matches results
;
1006 Rect
test_rect(0, 0, 100, 100);
1007 rt
.AppendIntersectingRecords(test_rect
, &results
);
1009 // Should only be 49 rects in tree.
1010 EXPECT_EQ(49U, results
.size());
1011 VerifyAllKeys(results
);
1014 TEST_F(RTreeTest
, InsertReplacementMaintainsTree
) {
1016 AddStackedSquares(&rt
, 100);
1019 for (int i
= 1; i
<= 100; ++i
) {
1020 rt
.Insert(Rect(0, 0, 0, 0), i
);