1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #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" 9 10 namespace gfx { 11 12 class RTreeTest : public ::testing::Test { 13 protected: 14 typedef RTree<int> RT; 15 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()); 23 return; 24 } 25 // Root is allowed to have fewer than min_children_ but never more than 26 // max_children_. 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) { 35 ValidateNode( 36 rt->root()->child(i), rt->min_children_, rt->max_children_); 37 } 38 } 39 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, 43 size_t min_children, 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); 53 } 54 } 55 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()); 60 Rect check_bounds; 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()); 66 } 67 EXPECT_EQ(check_bounds, node->rect()); 68 } 69 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)); 75 } 76 } 77 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)); 83 } 84 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, 89 const Rect& rect, 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); 97 } 98 } 99 }; 100 101 class RTreeNodeTest : public RTreeTest { 102 protected: 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; 108 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)); 112 } 113 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)); 117 } 118 119 void NodeRecomputeLocalBounds(RTreeNodeBase* node) { 120 node->RecomputeLocalBounds(); 121 } 122 123 bool NodeCompareVertical(RTreeNodeBase* a, RTreeNodeBase* b) { 124 return RTreeBase::Node::CompareVertical(a, b); 125 } 126 127 bool NodeCompareHorizontal(RTreeNodeBase* a, RTreeNodeBase* b) { 128 return RTreeBase::Node::CompareHorizontal(a, b); 129 } 130 131 bool NodeCompareCenterDistanceFromParent( 132 const RTreeNodeBase* a, const RTreeNodeBase* b) { 133 return RTreeBase::Node::CompareCenterDistanceFromParent(a, b); 134 } 135 136 int NodeOverlapIncreaseToAdd(RTreeNode* node, 137 const Rect& rect, 138 const RTreeNodeBase* candidate_node, 139 const Rect& expanded_rect) { 140 return node->OverlapIncreaseToAdd(rect, candidate_node, expanded_rect); 141 } 142 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); 149 } 150 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); 157 } 158 159 int NodeSmallestMarginSum(size_t start_index, 160 size_t end_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); 165 } 166 167 size_t NodeChooseSplitIndex(size_t min_children, 168 size_t max_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); 173 } 174 175 scoped_ptr<RTreeNodeBase> NodeDivideChildren( 176 RTreeNode* node, 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); 183 } 184 185 RTreeNode* NodeLeastOverlapIncrease(RTreeNode* node, 186 const Rect& node_rect, 187 const RTreeRects& expanded_rects) { 188 return node->LeastOverlapIncrease(node_rect, expanded_rects); 189 } 190 191 RTreeNode* NodeLeastAreaEnlargement(RTreeNode* node, 192 const Rect& node_rect, 193 const RTreeRects& expanded_rects) { 194 return node->LeastAreaEnlargement(node_rect, expanded_rects); 195 } 196 }; 197 198 // RTreeNodeTest -------------------------------------------------------------- 199 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))); 207 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. 211 RTreeNodes removals; 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()); 222 223 // Now remove the next 2. 224 removals.clear(); 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)); 237 } 238 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)); 245 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)); 250 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)); 255 } 256 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)); 263 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)); 268 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)); 273 } 274 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); 278 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.PassAs<RTreeNodeBase>()); 283 284 scoped_ptr<RTreeRecord> center_positive(new RTreeRecord(Rect(9, 9, 2, 2), 2)); 285 parent->AddChild(center_positive.PassAs<RTreeNodeBase>()); 286 287 scoped_ptr<RTreeRecord> center_negative( 288 new RTreeRecord(Rect(-10, -10, 2, 2), 3)); 289 parent->AddChild(center_negative.PassAs<RTreeNodeBase>()); 290 291 ValidateNode(parent.get(), 1U, 5U); 292 EXPECT_EQ(Rect(-10, -10, 21, 21), parent->rect()); 293 294 EXPECT_TRUE( 295 NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(1))); 296 EXPECT_FALSE( 297 NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(0))); 298 EXPECT_TRUE( 299 NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(2))); 300 EXPECT_FALSE( 301 NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(0))); 302 EXPECT_TRUE( 303 NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(1))); 304 EXPECT_FALSE( 305 NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(2))); 306 } 307 308 TEST_F(RTreeNodeTest, OverlapIncreaseToAdd) { 309 // Create a test node with three children, for overlap comparisons. 310 scoped_ptr<RTreeNode> parent(new RTreeNode); 311 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); 321 322 // Test a rect in corner. 323 Rect corner(0, 0, 1, 1); 324 Rect expanded = top; 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)); 329 330 expanded = middle; 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)); 337 338 expanded = bottom; 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)); 345 346 // Test a rect that doesn't overlap with anything, in the far right corner. 347 Rect far_corner(9, 0, 1, 1); 348 expanded = top; 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)); 354 355 expanded = middle; 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)); 361 362 expanded = bottom; 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)); 368 } 369 370 TEST_F(RTreeNodeTest, BuildLowBounds) { 371 RTreeNodes records; 372 records.reserve(10); 373 for (int i = 1; i <= 10; ++i) 374 records.push_back(new RTreeRecord(Rect(0, 0, i, i), i)); 375 376 RTreeRects vertical_bounds; 377 RTreeRects horizontal_bounds; 378 NodeBuildLowBounds( 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]); 383 } 384 } 385 386 TEST_F(RTreeNodeTest, BuildHighBounds) { 387 RTreeNodes records; 388 records.reserve(25); 389 for (int i = 0; i < 25; ++i) 390 records.push_back(new RTreeRecord(Rect(i, i, 25 - i, 25 - i), i)); 391 392 RTreeRects vertical_bounds; 393 RTreeRects horizontal_bounds; 394 NodeBuildHighBounds( 395 records.get(), records.get(), &vertical_bounds, &horizontal_bounds); 396 for (int i = 0; i < 25; ++i) { 397 EXPECT_EQ(records[i]->rect(), vertical_bounds[i]); 398 EXPECT_EQ(records[i]->rect(), horizontal_bounds[i]); 399 } 400 } 401 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: 409 // 410 // shape: | v sort: | h sort: | 411 // -------+---------+---------+ 412 // aaaaa | 0 | 0 | 413 // bbb | 1 | 2 | 414 // c | 2 | 4 | 415 // d | 3 | 5 | 416 // eee | 4 | 3 | 417 // fffff | 5 | 1 | 418 // 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)); 424 } 425 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)); 431 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)); 439 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); 445 446 EXPECT_EQ( 447 3U, 448 NodeChooseSplitIndex(2, 5, low_vertical_bounds, high_vertical_bounds)); 449 } 450 451 TEST_F(RTreeNodeTest, ChooseSplitAxisAndIndexHorizontal) { 452 RTreeRects low_vertical_bounds; 453 RTreeRects high_vertical_bounds; 454 RTreeRects low_horizontal_bounds; 455 RTreeRects high_horizontal_bounds; 456 // We rotate the shape from ChooseSplitAxisAndIndexVertical to test 457 // horizontal split axis detection: 458 // 459 // +--------+ 460 // | a f | 461 // | ab ef | 462 // sort: | abcdef | 463 // | ab ef | 464 // | a f | 465 // |--------+ 466 // v sort: | 024531 | 467 // h sort: | 012345 | 468 // +--------+ 469 // 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)); 475 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)); 483 484 // These are already sorted horizontally from left to right. Bounding 485 // rectangles of these horizontally sorted will be i wide, 5 tall bounding 486 // boxes. 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)); 490 } 491 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); 496 497 EXPECT_GT(smallest_vertical_margin, smallest_horizontal_margin); 498 499 EXPECT_EQ(3U, 500 NodeChooseSplitIndex( 501 2, 5, low_horizontal_bounds, high_horizontal_bounds)); 502 } 503 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.PassAs<RTreeNodeBase>()); 515 low_bounds.push_back(Rect(0, 0, i, i)); 516 high_bounds.push_back(Rect(0, 0, 10, 10)); 517 } 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()); 532 } 533 } 534 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); 544 545 RTreeNodes orphans; 546 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); 554 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); 562 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()); 568 } 569 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; 576 int id = 1; 577 scoped_ptr<RTreeNode> root(NewNodeAtLevel(2)); 578 for (int i = 0; i < 2; ++i) { 579 scoped_ptr<RTreeNode> level_1_child(NewNodeAtLevel(1)); 580 for (int j = 0; j < 2; ++j) { 581 scoped_ptr<RTreeNode> level_0_child(new RTreeNode); 582 for (int k = 0; k < 2; ++k) { 583 scoped_ptr<RTreeRecord> record( 584 new RTreeRecord(Rect(0, 0, id, id), id)); 585 ++id; 586 records.push_back(record.get()); 587 level_0_child->AddChild(record.PassAs<RTreeNodeBase>()); 588 } 589 level_0_children.push_back(level_0_child.get()); 590 level_1_child->AddChild(level_0_child.PassAs<RTreeNodeBase>()); 591 } 592 level_1_children.push_back(level_1_child.get()); 593 root->AddChild(level_1_child.PassAs<RTreeNodeBase>()); 594 } 595 596 // This should now be a valid tree structure. 597 ValidateNode(root.get(), 2U, 2U); 598 EXPECT_EQ(2U, level_1_children.size()); 599 EXPECT_EQ(4U, level_0_children.size()); 600 EXPECT_EQ(8U, records.size()); 601 602 // Now remove all of the level 0 nodes so we get the record nodes as orphans. 603 RTreeNodes orphans; 604 for (size_t i = 0; i < level_0_children.size(); ++i) 605 level_1_children[i / 2]->RemoveChild(level_0_children[i], &orphans); 606 607 // Orphans should be all 8 records but no order guarantee. 608 EXPECT_EQ(8U, orphans.size()); 609 for (std::vector<RTreeRecord*>::iterator it = records.begin(); 610 it != records.end(); ++it) { 611 RTreeNodes::iterator orphan = 612 std::find(orphans.begin(), orphans.end(), *it); 613 EXPECT_NE(orphan, orphans.end()); 614 orphans.erase(orphan); 615 } 616 EXPECT_EQ(0U, orphans.size()); 617 } 618 619 TEST_F(RTreeNodeTest, RemoveAndReturnLastChild) { 620 scoped_ptr<RTreeNode> test_parent(new RTreeNode); 621 test_parent->AddChild( 622 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 1, 1), 1))); 623 test_parent->AddChild( 624 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 2, 2), 2))); 625 test_parent->AddChild( 626 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 3, 3), 3))); 627 ValidateNode(test_parent.get(), 1U, 5U); 628 629 RTreeNodeBase* child = test_parent->child(2); 630 scoped_ptr<RTreeNodeBase> last_child(test_parent->RemoveAndReturnLastChild()); 631 EXPECT_EQ(child, last_child.get()); 632 EXPECT_EQ(2U, test_parent->count()); 633 NodeRecomputeLocalBounds(test_parent.get()); 634 ValidateNode(test_parent.get(), 1U, 5U); 635 636 child = test_parent->child(1); 637 scoped_ptr<RTreeNodeBase> middle_child( 638 test_parent->RemoveAndReturnLastChild()); 639 EXPECT_EQ(child, middle_child.get()); 640 EXPECT_EQ(1U, test_parent->count()); 641 NodeRecomputeLocalBounds(test_parent.get()); 642 ValidateNode(test_parent.get(), 1U, 5U); 643 644 child = test_parent->child(0); 645 scoped_ptr<RTreeNodeBase> first_child( 646 test_parent->RemoveAndReturnLastChild()); 647 EXPECT_EQ(child, first_child.get()); 648 EXPECT_EQ(0U, test_parent->count()); 649 } 650 651 TEST_F(RTreeNodeTest, LeastOverlapIncrease) { 652 scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1)); 653 // Construct 4 nodes with 1x2 rects spaced horizontally 1 pixel apart, or: 654 // 655 // a b c d 656 // a b c d 657 // 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.PassAs<RTreeNodeBase>()); 663 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); 664 } 665 666 ValidateNode(test_parent.get(), 1U, 5U); 667 668 // Test rect at (7, 0) should require minimum overlap on the part of the 669 // fourth rectangle to add: 670 // 671 // a b c dT 672 // a b c d 673 // 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()); 680 681 // Test rect covering the bottom half of all children should be a 4-way tie, 682 // so LeastOverlapIncrease should return NULL: 683 // 684 // a b c d 685 // TTTTTTT 686 // 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); 692 693 // Test rect completely inside c should return the third rectangle: 694 // 695 // a b T d 696 // a b c d 697 // 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()); 703 704 // Add a rectangle that overlaps completely with rectangle c, to test 705 // when there is a tie between two completely contained rectangles: 706 // 707 // a b Ted 708 // a b eed 709 // 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.PassAs<RTreeNodeBase>()); 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); 718 } 719 720 TEST_F(RTreeNodeTest, LeastAreaEnlargement) { 721 scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1)); 722 // Construct 4 nodes in a cross-hairs style configuration: 723 // 724 // a 725 // b c 726 // d 727 // 728 scoped_ptr<RTreeNode> node(new RTreeNode); 729 node->AddChild( 730 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 0, 1, 1), 1))); 731 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); 732 node.reset(new RTreeNode); 733 node->AddChild( 734 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 1, 1), 2))); 735 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); 736 node.reset(new RTreeNode); 737 node->AddChild( 738 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(2, 1, 1, 1), 3))); 739 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); 740 node.reset(new RTreeNode); 741 node->AddChild( 742 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 2, 1, 1), 4))); 743 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); 744 745 ValidateNode(test_parent.get(), 1U, 5U); 746 747 // Test rect at (1, 3) should require minimum area to add to Node d: 748 // 749 // a 750 // b c 751 // d 752 // T 753 // 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()); 760 761 // Test rect completely inside b should require minimum area to add to Node b: 762 // 763 // a 764 // T c 765 // d 766 // 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()); 772 773 // Add e at (0, 1) to overlap b and c, to test tie-breaking: 774 // 775 // a 776 // eee 777 // d 778 // 779 node.reset(new RTreeNode); 780 node->AddChild( 781 scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 3, 1), 7))); 782 test_parent->AddChild(node.PassAs<RTreeNodeBase>()); 783 784 ValidateNode(test_parent.get(), 1U, 5U); 785 786 // Test rect at (3, 1) should tie between c and e, but c has smaller area so 787 // the algorithm should select c: 788 // 789 // 790 // a 791 // eeeT 792 // d 793 // 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()); 799 } 800 801 // RTreeTest ------------------------------------------------------------------ 802 803 // An empty RTree should never return AppendIntersectingRecords results, and 804 // RTrees should be empty upon construction. 805 TEST_F(RTreeTest, AppendIntersectingRecordsOnEmptyTree) { 806 RT rt(2, 10); 807 ValidateRTree(&rt); 808 RT::Matches results; 809 Rect test_rect(25, 25); 810 rt.AppendIntersectingRecords(test_rect, &results); 811 EXPECT_EQ(0U, results.size()); 812 ValidateRTree(&rt); 813 } 814 815 // Clear should empty the tree, meaning that all queries should not return 816 // results after. 817 TEST_F(RTreeTest, ClearEmptiesTreeOfSingleNode) { 818 RT rt(2, 5); 819 rt.Insert(Rect(0, 0, 100, 100), 1); 820 rt.Clear(); 821 RT::Matches results; 822 Rect test_rect(1, 1); 823 rt.AppendIntersectingRecords(test_rect, &results); 824 EXPECT_EQ(0U, results.size()); 825 ValidateRTree(&rt); 826 } 827 828 // Even with a complex internal structure, clear should empty the tree, meaning 829 // that all queries should not return results after. 830 TEST_F(RTreeTest, ClearEmptiesTreeOfManyNodes) { 831 RT rt(2, 5); 832 AddStackedSquares(&rt, 100); 833 rt.Clear(); 834 RT::Matches results; 835 Rect test_rect(1, 1); 836 rt.AppendIntersectingRecords(test_rect, &results); 837 EXPECT_EQ(0U, results.size()); 838 ValidateRTree(&rt); 839 } 840 841 // Duplicate inserts should overwrite previous inserts. 842 TEST_F(RTreeTest, DuplicateInsertsOverwrite) { 843 RT rt(2, 5); 844 // Add 100 stacked squares, but always with duplicate key of 0. 845 for (int i = 1; i <= 100; ++i) { 846 rt.Insert(Rect(0, 0, i, i), 0); 847 ValidateRTree(&rt); 848 } 849 RT::Matches results; 850 Rect test_rect(1, 1); 851 rt.AppendIntersectingRecords(test_rect, &results); 852 EXPECT_EQ(1U, results.size()); 853 EXPECT_EQ(1U, results.count(0)); 854 } 855 856 // Call Remove() once on something that's been inserted repeatedly. 857 TEST_F(RTreeTest, DuplicateInsertRemove) { 858 RT rt(3, 9); 859 AddStackedSquares(&rt, 25); 860 for (int i = 1; i <= 100; ++i) { 861 rt.Insert(Rect(0, 0, i, i), 26); 862 ValidateRTree(&rt); 863 } 864 rt.Remove(26); 865 RT::Matches results; 866 Rect test_rect(1, 1); 867 rt.AppendIntersectingRecords(test_rect, &results); 868 EXPECT_EQ(25U, results.size()); 869 VerifyAllKeys(results); 870 } 871 872 // Call Remove() repeatedly on something that's been inserted once. 873 TEST_F(RTreeTest, InsertDuplicateRemove) { 874 RT rt(7, 15); 875 AddStackedSquares(&rt, 101); 876 for (int i = 0; i < 100; ++i) { 877 rt.Remove(101); 878 ValidateRTree(&rt); 879 } 880 RT::Matches results; 881 Rect test_rect(1, 1); 882 rt.AppendIntersectingRecords(test_rect, &results); 883 EXPECT_EQ(100U, results.size()); 884 VerifyAllKeys(results); 885 } 886 887 // Stacked rects should meet all matching queries regardless of nesting. 888 TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresNestedHit) { 889 RT rt(2, 5); 890 AddStackedSquares(&rt, 100); 891 RT::Matches results; 892 Rect test_rect(1, 1); 893 rt.AppendIntersectingRecords(test_rect, &results); 894 EXPECT_EQ(100U, results.size()); 895 VerifyAllKeys(results); 896 } 897 898 // Stacked rects should meet all matching queries when contained completely by 899 // the query rectangle. 900 TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresContainedHit) { 901 RT rt(2, 10); 902 AddStackedSquares(&rt, 100); 903 RT::Matches results; 904 Rect test_rect(0, 0, 100, 100); 905 rt.AppendIntersectingRecords(test_rect, &results); 906 EXPECT_EQ(100U, results.size()); 907 VerifyAllKeys(results); 908 } 909 910 // Stacked rects should miss a missing query when the query has no intersection 911 // with the rects. 912 TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresCompleteMiss) { 913 RT rt(2, 7); 914 AddStackedSquares(&rt, 100); 915 RT::Matches results; 916 Rect test_rect(150, 150, 100, 100); 917 rt.AppendIntersectingRecords(test_rect, &results); 918 EXPECT_EQ(0U, results.size()); 919 } 920 921 // Removing half the nodes after insertion should still result in a valid tree. 922 TEST_F(RTreeTest, RemoveHalfStackedRects) { 923 RT rt(2, 11); 924 AddStackedSquares(&rt, 200); 925 for (int i = 101; i <= 200; ++i) { 926 rt.Remove(i); 927 ValidateRTree(&rt); 928 } 929 RT::Matches results; 930 Rect test_rect(1, 1); 931 rt.AppendIntersectingRecords(test_rect, &results); 932 EXPECT_EQ(100U, results.size()); 933 VerifyAllKeys(results); 934 935 // Add the nodes back in. 936 for (int i = 101; i <= 200; ++i) { 937 rt.Insert(Rect(0, 0, i, i), i); 938 ValidateRTree(&rt); 939 } 940 results.clear(); 941 rt.AppendIntersectingRecords(test_rect, &results); 942 EXPECT_EQ(200U, results.size()); 943 VerifyAllKeys(results); 944 } 945 946 TEST_F(RTreeTest, InsertDupToRoot) { 947 RT rt(2, 5); 948 rt.Insert(Rect(0, 0, 1, 2), 1); 949 ValidateRTree(&rt); 950 rt.Insert(Rect(0, 0, 2, 1), 1); 951 ValidateRTree(&rt); 952 } 953 954 TEST_F(RTreeTest, InsertNegativeCoordsRect) { 955 RT rt(5, 11); 956 for (int i = 1; i <= 100; ++i) { 957 rt.Insert(Rect(-i, -i, i, i), (i * 2) - 1); 958 ValidateRTree(&rt); 959 rt.Insert(Rect(0, 0, i, i), i * 2); 960 ValidateRTree(&rt); 961 } 962 RT::Matches results; 963 Rect test_rect(-1, -1, 2, 2); 964 rt.AppendIntersectingRecords(test_rect, &results); 965 EXPECT_EQ(200U, results.size()); 966 VerifyAllKeys(results); 967 } 968 969 TEST_F(RTreeTest, RemoveNegativeCoordsRect) { 970 RT rt(7, 21); 971 972 // Add 100 positive stacked squares. 973 AddStackedSquares(&rt, 100); 974 975 // Now add 100 negative stacked squares. 976 for (int i = 101; i <= 200; ++i) { 977 rt.Insert(Rect(100 - i, 100 - i, i - 100, i - 100), 301 - i); 978 ValidateRTree(&rt); 979 } 980 981 // Now remove half of the negative squares. 982 for (int i = 101; i <= 150; ++i) { 983 rt.Remove(301 - i); 984 ValidateRTree(&rt); 985 } 986 987 // Queries should return 100 positive and 50 negative stacked squares. 988 RT::Matches results; 989 Rect test_rect(-1, -1, 2, 2); 990 rt.AppendIntersectingRecords(test_rect, &results); 991 EXPECT_EQ(150U, results.size()); 992 VerifyAllKeys(results); 993 } 994 995 TEST_F(RTreeTest, InsertEmptyRectReplacementRemovesKey) { 996 RT rt(10, 31); 997 AddStackedSquares(&rt, 50); 998 ValidateRTree(&rt); 999 1000 // Replace last square with empty rect. 1001 rt.Insert(Rect(), 50); 1002 ValidateRTree(&rt); 1003 1004 // Now query large area to get all rects in tree. 1005 RT::Matches results; 1006 Rect test_rect(0, 0, 100, 100); 1007 rt.AppendIntersectingRecords(test_rect, &results); 1008 1009 // Should only be 49 rects in tree. 1010 EXPECT_EQ(49U, results.size()); 1011 VerifyAllKeys(results); 1012 } 1013 1014 TEST_F(RTreeTest, InsertReplacementMaintainsTree) { 1015 RT rt(2, 5); 1016 AddStackedSquares(&rt, 100); 1017 ValidateRTree(&rt); 1018 1019 for (int i = 1; i <= 100; ++i) { 1020 rt.Insert(Rect(0, 0, 0, 0), i); 1021 ValidateRTree(&rt); 1022 } 1023 } 1024 1025 } // namespace gfx 1026