Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 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 "ui/gfx/geometry/r_tree.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <limits> | |
| 9 | |
| 10 #include "base/logging.h" | |
| 11 | |
| 12 namespace { | |
| 13 | |
| 14 // Returns the center coordinates of the given rectangle. | |
| 15 gfx::Vector2d CenterOfRect(const gfx::Rect& rect) { | |
| 16 return rect.OffsetFromOrigin() + | |
| 17 gfx::Vector2d(rect.width() / 2, rect.height() / 2); | |
| 18 } | |
| 19 | |
| 20 } | |
| 21 | |
| 22 namespace gfx { | |
| 23 | |
| 24 RTree::Node::Node(int level) : level_(level), parent_(NULL), key_(NULL) { | |
| 25 } | |
| 26 | |
| 27 RTree::Node::Node(const Rect& rect, const void* key) | |
| 28 : rect_(rect), level_(-1), parent_(NULL), key_(key) { | |
| 29 } | |
| 30 | |
| 31 RTree::Node::~Node() { | |
| 32 Clear(); | |
| 33 } | |
| 34 | |
| 35 void RTree::Node::Clear() { | |
| 36 // Iterate through children and delete them all. | |
| 37 children_.clear(); | |
| 38 key_ = NULL; | |
| 39 } | |
| 40 | |
| 41 void RTree::Node::Query(const Rect& query_rect, | |
| 42 std::set<const void*>* matches_out) const { | |
| 43 // Check own bounding box for intersection, can cull all children if no | |
| 44 // intersection. | |
| 45 if (!rect_.Intersects(query_rect)) { | |
| 46 return; | |
| 47 } | |
| 48 | |
| 49 // Conversely if we are completely contained within the query rect we can | |
| 50 // confidently skip all bounds checks for ourselves and all our children. | |
| 51 if (query_rect.Contains(rect_)) { | |
| 52 GetAllValues(matches_out); | |
| 53 return; | |
| 54 } | |
| 55 | |
| 56 // We intersect the query rect but we are not are not contained within it. | |
| 57 // If we are a record node, then add our record value. Otherwise we must | |
| 58 // query each of our children in turn. | |
| 59 if (key_) { | |
| 60 DCHECK_EQ(level_, -1); | |
| 61 matches_out->insert(key_); | |
| 62 } else { | |
| 63 for (size_t i = 0; i < children_.size(); ++i) { | |
| 64 // Sanity-check our children. | |
| 65 Node* node = children_[i]; | |
| 66 DCHECK_EQ(node->parent_, this); | |
| 67 DCHECK_EQ(level_ - 1, node->level_); | |
| 68 DCHECK(rect_.Contains(node->rect_)); | |
| 69 node->Query(query_rect, matches_out); | |
| 70 } | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 void RTree::Node::RecomputeBounds() { | |
| 75 RecomputeBoundsNoParents(); | |
| 76 // Recompute our parent's bounds recursively up to the root. | |
| 77 if (parent_) { | |
| 78 parent_->RecomputeBounds(); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 void RTree::Node::RemoveNodesForReinsert(size_t number_to_remove, | |
| 83 std::vector<Node*>* nodes) { | |
|
piman
2014/04/28 18:24:28
nit: it'd be good to return nodes in a ScopedVecto
luken
2014/04/29 21:01:04
Done.
| |
| 84 DCHECK_GE(children_.size(), number_to_remove); | |
| 85 | |
| 86 // Sort our children by their distance from the center of their rectangles to | |
| 87 // the center of our bounding rectangle. | |
| 88 std::sort(children_.begin(), | |
| 89 children_.end(), | |
| 90 &RTree::Node::CompareCenterDistanceFromParent); | |
| 91 | |
| 92 // Add lowest distance nodes from our children list to the returned vector. | |
| 93 nodes->insert( | |
| 94 nodes->end(), children_.begin(), children_.begin() + number_to_remove); | |
| 95 // Remove those same nodes from our list, without deleting them. | |
| 96 children_.weak_erase(children_.begin(), children_.begin() + number_to_remove); | |
| 97 } | |
| 98 | |
| 99 size_t RTree::Node::RemoveChild(Node* child_node, std::vector<Node*>* orphans) { | |
|
piman
2014/04/28 18:24:28
Same here wrt ScopedVector
luken
2014/04/29 21:01:04
Done.
| |
| 100 // Should actually be one of our children. | |
| 101 DCHECK_EQ(child_node->parent_, this); | |
| 102 | |
| 103 // Add children of child_node to the orphans vector. | |
| 104 orphans->insert(orphans->end(), | |
| 105 child_node->children_.begin(), | |
| 106 child_node->children_.end()); | |
| 107 // Remove without deletion those children from the child_node vector. | |
| 108 child_node->children_.weak_clear(); | |
| 109 | |
| 110 // Find an iterator to this Node in our own children_ vector. | |
| 111 ScopedVector<Node>::iterator child_it = children_.end(); | |
| 112 for (size_t i = 0; i < children_.size(); ++i) { | |
| 113 if (children_[i] == child_node) { | |
| 114 child_it = children_.begin() + i; | |
| 115 break; | |
| 116 } | |
| 117 } | |
| 118 // Should have found the pointer in our children_ vector. | |
| 119 DCHECK(child_it != children_.end()); | |
| 120 // Remove without deleting the child node from our children_ vector. | |
| 121 children_.weak_erase(child_it); | |
| 122 | |
| 123 return children_.size(); | |
| 124 } | |
| 125 | |
| 126 RTree::Node* RTree::Node::RemoveAndReturnLastChild() { | |
|
piman
2014/04/28 18:24:28
return scoped_ptr
luken
2014/04/29 21:01:04
Done.
| |
| 127 if (!children_.size()) | |
| 128 return NULL; | |
| 129 | |
| 130 Node* last_child = children_[children_.size() - 1]; | |
| 131 DCHECK_EQ(last_child->parent_, this); | |
| 132 children_.weak_erase(children_.begin() + children_.size() - 1); | |
| 133 // Invalidate parent, as this child may even become the new root. | |
| 134 last_child->parent_ = NULL; | |
| 135 return last_child; | |
| 136 } | |
| 137 | |
| 138 // Uses the R*-Tree algorithm CHOOSELEAF proposed by Beckmann et al. | |
| 139 RTree::Node* RTree::Node::ChooseSubtree(Node* node) { | |
| 140 // Should never be called on a record node. | |
| 141 DCHECK(!key_); | |
| 142 DCHECK(level_ >= 0); | |
| 143 DCHECK(node); | |
| 144 | |
| 145 // If we are a parent of nodes on the provided node level, we are done. | |
| 146 if (level_ == node->level_ + 1) | |
| 147 return this; | |
| 148 | |
| 149 // We are an internal node, and thus guaranteed to have children. | |
| 150 DCHECK_GT(children_.size(), 0U); | |
| 151 | |
| 152 // Iterate over all children to find best candidate for insertion. | |
| 153 Node* best_candidate = NULL; | |
| 154 | |
| 155 // For parents of leaf nodes, we pick the node that will cause the least | |
| 156 // increase in overlap by the addition of this new node. This may detect a | |
| 157 // tie, in which case it will return NULL. | |
| 158 if (level_ == 1) | |
| 159 best_candidate = LeastOverlapIncrease(node); | |
| 160 | |
| 161 // For non-parents of leaf nodes, or for parents of leaf nodes with ties in | |
| 162 // overlap increase, we choose the subtree with least area enlargement caused | |
| 163 // by the addition of the new node. | |
| 164 if (!best_candidate) | |
| 165 best_candidate = LeastAreaEnlargement(node); | |
| 166 | |
| 167 DCHECK(best_candidate); | |
| 168 return best_candidate->ChooseSubtree(node); | |
| 169 } | |
| 170 | |
| 171 RTree::Node* RTree::Node::LeastAreaEnlargement(Node* node) { | |
| 172 Node* best_node = NULL; | |
| 173 int least_area_enlargement = std::numeric_limits<int>::max(); | |
| 174 for (size_t i = 0; i < children_.size(); ++i) { | |
| 175 Node* candidate_node = children_[i]; | |
| 176 Rect expanded_rect = candidate_node->rect_; | |
| 177 expanded_rect.Union(node->rect_); | |
| 178 int area_change = | |
| 179 expanded_rect.size().GetArea() - candidate_node->rect_.size().GetArea(); | |
| 180 if (area_change < least_area_enlargement) { | |
| 181 best_node = candidate_node; | |
| 182 least_area_enlargement = area_change; | |
| 183 } else if (area_change == least_area_enlargement) { | |
| 184 // Ties are broken by choosing entry with least area. | |
| 185 DCHECK(best_node); | |
| 186 if (candidate_node->rect_.size().GetArea() < | |
| 187 best_node->rect_.size().GetArea()) { | |
| 188 best_node = candidate_node; | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 DCHECK(best_node); | |
| 194 return best_node; | |
| 195 } | |
| 196 | |
| 197 RTree::Node* RTree::Node::LeastOverlapIncrease(RTree::Node* node) { | |
| 198 Node* best_node = NULL; | |
| 199 Node* tied_node = NULL; | |
|
piman
2014/04/28 18:24:28
nit: this could just be a bool.
luken
2014/04/29 21:01:04
Done.
| |
| 200 int least_overlap_increase = std::numeric_limits<int>::max(); | |
| 201 for (size_t i = 0; i < children_.size(); ++i) { | |
| 202 Node* candidate_node = children_[i]; | |
| 203 Rect expanded_rect = candidate_node->rect_; | |
| 204 expanded_rect.Union(node->rect_); | |
|
piman
2014/04/28 18:24:28
I would really like if we didn't do redundant comp
luken
2014/04/29 21:01:04
Done.
| |
| 205 int overlap_increase = OverlapIncreaseToAdd(node->rect_, i, expanded_rect); | |
| 206 if (overlap_increase < least_overlap_increase) { | |
| 207 least_overlap_increase = overlap_increase; | |
| 208 best_node = candidate_node; | |
| 209 tied_node = NULL; | |
| 210 } else if (overlap_increase == least_overlap_increase) { | |
| 211 tied_node = candidate_node; | |
| 212 // If we are tied at zero there is no possible better overlap increase, | |
| 213 // so we can report a tie early. | |
| 214 if (overlap_increase == 0) { | |
| 215 return NULL; | |
| 216 } | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 // If we ended up with a tie return NULL to report it. | |
| 221 if (tied_node) | |
| 222 return NULL; | |
| 223 | |
| 224 return best_node; | |
| 225 } | |
| 226 | |
| 227 int RTree::Node::OverlapIncreaseToAdd(const Rect& rect, | |
| 228 size_t candidate, | |
| 229 const Rect& expanded_rect) { | |
| 230 Node* candidate_node = children_[candidate]; | |
| 231 | |
| 232 // Early-out option for when rect is contained completely within candidate. | |
| 233 if (candidate_node->rect_.Contains(rect)) { | |
| 234 return 0; | |
| 235 } | |
| 236 | |
| 237 int total_original_overlap = 0; | |
| 238 int total_expanded_overlap = 0; | |
| 239 | |
| 240 // Now calculate overlap with all other rects in this node. | |
| 241 for (size_t i = 0; i < children_.size(); ++i) { | |
| 242 // Skip calculating overlap with the candidate rect. | |
| 243 if (i == candidate) | |
| 244 continue; | |
| 245 Node* overlap_node = children_[i]; | |
| 246 Rect overlap_rect = candidate_node->rect_; | |
| 247 overlap_rect.Intersect(overlap_node->rect_); | |
| 248 total_original_overlap += overlap_rect.size().GetArea(); | |
| 249 Rect expanded_overlap_rect = expanded_rect; | |
| 250 expanded_overlap_rect.Intersect(overlap_node->rect_); | |
| 251 total_expanded_overlap += expanded_overlap_rect.size().GetArea(); | |
| 252 } | |
| 253 | |
| 254 // Compare this overlap increase with best one to date, update best. | |
| 255 int overlap_increase = total_expanded_overlap - total_original_overlap; | |
| 256 return overlap_increase; | |
| 257 } | |
| 258 | |
| 259 size_t RTree::Node::AddChild(Node* node) { | |
| 260 DCHECK(node); | |
| 261 // Sanity-check that the level of the child being added is one more than ours. | |
| 262 DCHECK_EQ(level_ - 1, node->level_); | |
| 263 node->parent_ = this; | |
| 264 children_.push_back(node); | |
| 265 rect_.Union(node->rect_); | |
| 266 return children_.size(); | |
| 267 } | |
| 268 | |
| 269 RTree::Node* RTree::Node::Split(size_t min_children, size_t max_children) { | |
| 270 // Please don't attempt to split a record Node. | |
| 271 DCHECK(!key_); | |
| 272 // We should have too many children to begin with. | |
| 273 DCHECK_GT(children_.size(), max_children); | |
| 274 // First determine if splitting along the horizontal or vertical axis. We | |
| 275 // sort the rectangles of our children by lower then upper values along both | |
| 276 // horizontal and vertical axes. | |
| 277 std::vector<Node*> vertical_sort(children_.get()); | |
| 278 std::vector<Node*> horizontal_sort(children_.get()); | |
| 279 std::sort(vertical_sort.begin(), | |
| 280 vertical_sort.end(), | |
| 281 &RTree::Node::CompareVertical); | |
| 282 std::sort(horizontal_sort.begin(), | |
| 283 horizontal_sort.end(), | |
| 284 &RTree::Node::CompareHorizontal); | |
| 285 | |
| 286 // We will be examining the bounding boxes of different splits of our children | |
| 287 // sorted along each axis. Here we precompute the bounding boxes of these | |
| 288 // distributions. For the low bounds the ith element can be considered the | |
| 289 // union of all rects [0,i] in the relevant sorted axis array. | |
| 290 std::vector<Rect> low_vertical_bounds; | |
| 291 std::vector<Rect> low_horizontal_bounds; | |
| 292 BuildLowBounds(vertical_sort, | |
| 293 horizontal_sort, | |
| 294 &low_vertical_bounds, | |
| 295 &low_horizontal_bounds); | |
| 296 | |
| 297 // For the high bounds the ith element can be considered the union of all | |
| 298 // rects [i, children_.size()) in the relevant sorted axis array. | |
| 299 std::vector<Rect> high_vertical_bounds; | |
| 300 std::vector<Rect> high_horizontal_bounds; | |
| 301 BuildHighBounds(vertical_sort, | |
| 302 horizontal_sort, | |
| 303 &high_vertical_bounds, | |
| 304 &high_horizontal_bounds); | |
| 305 | |
| 306 bool is_vertical_split = ChooseSplitAxis(low_vertical_bounds, | |
| 307 high_vertical_bounds, | |
| 308 low_horizontal_bounds, | |
| 309 high_horizontal_bounds, | |
| 310 min_children, | |
| 311 max_children); | |
| 312 | |
| 313 // Lastly we determine optimal index and do the split. | |
| 314 Node* sibling = NULL; | |
| 315 if (is_vertical_split) { | |
| 316 size_t split_index = ChooseSplitIndex( | |
| 317 min_children, max_children, low_vertical_bounds, high_vertical_bounds); | |
| 318 sibling = DivideChildren( | |
| 319 low_vertical_bounds, high_vertical_bounds, vertical_sort, split_index); | |
| 320 } else { | |
| 321 size_t split_index = ChooseSplitIndex(min_children, | |
| 322 max_children, | |
| 323 low_horizontal_bounds, | |
| 324 high_horizontal_bounds); | |
| 325 sibling = DivideChildren(low_horizontal_bounds, | |
| 326 high_horizontal_bounds, | |
| 327 horizontal_sort, | |
| 328 split_index); | |
| 329 } | |
| 330 | |
| 331 return sibling; | |
| 332 } | |
| 333 | |
| 334 // static | |
| 335 void RTree::Node::BuildLowBounds(const std::vector<Node*>& vertical_sort, | |
| 336 const std::vector<Node*>& horizontal_sort, | |
| 337 std::vector<Rect>* vertical_bounds, | |
| 338 std::vector<Rect>* horizontal_bounds) { | |
| 339 DCHECK_EQ(vertical_sort.size(), horizontal_sort.size()); | |
| 340 Rect vertical_bounds_rect; | |
| 341 Rect horizontal_bounds_rect; | |
| 342 vertical_bounds->reserve(vertical_sort.size()); | |
| 343 horizontal_bounds->reserve(horizontal_sort.size()); | |
| 344 for (size_t i = 0; i < vertical_sort.size(); ++i) { | |
| 345 vertical_bounds_rect.Union(vertical_sort[i]->rect_); | |
| 346 horizontal_bounds_rect.Union(horizontal_sort[i]->rect_); | |
| 347 vertical_bounds->push_back(vertical_bounds_rect); | |
| 348 horizontal_bounds->push_back(horizontal_bounds_rect); | |
| 349 } | |
| 350 } | |
| 351 | |
| 352 // static | |
| 353 void RTree::Node::BuildHighBounds(const std::vector<Node*>& vertical_sort, | |
| 354 const std::vector<Node*>& horizontal_sort, | |
| 355 std::vector<Rect>* vertical_bounds, | |
| 356 std::vector<Rect>* horizontal_bounds) { | |
| 357 DCHECK_EQ(vertical_sort.size(), horizontal_sort.size()); | |
| 358 Rect vertical_bounds_rect; | |
| 359 Rect horizontal_bounds_rect; | |
| 360 vertical_bounds->resize(vertical_sort.size()); | |
| 361 horizontal_bounds->resize(horizontal_sort.size()); | |
| 362 for (int i = static_cast<int>(vertical_sort.size()) - 1; i >= 0; --i) { | |
| 363 vertical_bounds_rect.Union(vertical_sort[i]->rect_); | |
| 364 horizontal_bounds_rect.Union(horizontal_sort[i]->rect_); | |
| 365 vertical_bounds->at(i) = vertical_bounds_rect; | |
| 366 horizontal_bounds->at(i) = horizontal_bounds_rect; | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 // static | |
| 371 bool RTree::Node::ChooseSplitAxis( | |
| 372 const std::vector<Rect>& low_vertical_bounds, | |
| 373 const std::vector<Rect>& high_vertical_bounds, | |
| 374 const std::vector<Rect>& low_horizontal_bounds, | |
| 375 const std::vector<Rect>& high_horizontal_bounds, | |
| 376 size_t min_children, | |
| 377 size_t max_children) { | |
| 378 // Examine the possible distributions of each sorted list by iterating through | |
| 379 // valid split points p, min_children <= p <= max_children - min_children, and | |
| 380 // computing the sums of the margins of the bounding boxes in each group. | |
| 381 // Smallest margin sum will determine split axis. | |
| 382 int smallest_horizontal_margin_sum = std::numeric_limits<int>::max(); | |
| 383 int smallest_vertical_margin_sum = std::numeric_limits<int>::max(); | |
| 384 for (size_t p = min_children; p < max_children - min_children; ++p) { | |
| 385 int horizontal_margin_sum = | |
| 386 low_horizontal_bounds[p].width() + low_horizontal_bounds[p].height() + | |
| 387 high_horizontal_bounds[p].width() + high_horizontal_bounds[p].height(); | |
| 388 int vertical_margin_sum = | |
| 389 low_vertical_bounds[p].width() + low_vertical_bounds[p].height() + | |
| 390 high_vertical_bounds[p].width() + high_vertical_bounds[p].height(); | |
| 391 // Update margin minima if necessary. | |
| 392 smallest_horizontal_margin_sum = | |
| 393 std::min(horizontal_margin_sum, smallest_horizontal_margin_sum); | |
| 394 smallest_vertical_margin_sum = | |
| 395 std::min(vertical_margin_sum, smallest_vertical_margin_sum); | |
| 396 } | |
| 397 | |
| 398 // Split along the axis perpendicular to the axis with the overall smallest | |
| 399 // margin sum. Meaning the axis sort resulting in two boxes with the smallest | |
| 400 // combined margin will become the axis along which the sorted rectangles are | |
| 401 // distributed to the two Nodes. | |
| 402 bool is_vertical_split = | |
| 403 smallest_vertical_margin_sum < smallest_horizontal_margin_sum; | |
| 404 return is_vertical_split; | |
| 405 } | |
| 406 | |
| 407 RTree::Node* RTree::Node::DivideChildren( | |
| 408 const std::vector<Rect>& low_bounds, | |
| 409 const std::vector<Rect>& high_bounds, | |
| 410 const std::vector<Node*>& sorted_children, | |
| 411 size_t split_index) { | |
| 412 Node* sibling = new Node(level_); | |
| 413 sibling->parent_ = parent_; | |
| 414 rect_ = low_bounds[split_index - 1]; | |
| 415 sibling->rect_ = high_bounds[split_index]; | |
| 416 // Our own children_ vector is unsorted, so we wipe it out and divide the | |
| 417 // sorted bounds rects between ourselves and our sibling. | |
| 418 children_.weak_clear(); | |
| 419 children_.insert(children_.end(), | |
| 420 sorted_children.begin(), | |
| 421 sorted_children.begin() + split_index); | |
| 422 sibling->children_.insert(sibling->children_.end(), | |
| 423 sorted_children.begin() + split_index, | |
| 424 sorted_children.end()); | |
| 425 | |
| 426 // Fix up sibling parentage or it's gonna be an awkward Thanksgiving. | |
| 427 for (size_t i = 0; i < sibling->children_.size(); ++i) { | |
| 428 sibling->children_[i]->parent_ = sibling; | |
| 429 } | |
| 430 | |
| 431 return sibling; | |
| 432 } | |
| 433 | |
| 434 void RTree::Node::SetRect(const Rect& rect) { | |
| 435 // Record nodes only, please. | |
| 436 DCHECK(key_); | |
| 437 rect_ = rect; | |
| 438 } | |
| 439 | |
| 440 // Returns all contained record_node values for this node and all children. | |
| 441 void RTree::Node::GetAllValues(std::set<const void*>* matches_out) const { | |
| 442 if (key_) { | |
| 443 DCHECK_EQ(level_, -1); | |
| 444 matches_out->insert(key_); | |
| 445 } else { | |
| 446 for (size_t i = 0; i < children_.size(); ++i) { | |
| 447 Node* node = children_[i]; | |
| 448 // Sanity-check our children. | |
| 449 DCHECK_EQ(node->parent_, this); | |
| 450 DCHECK_EQ(level_ - 1, node->level_); | |
| 451 DCHECK(rect_.Contains(node->rect_)); | |
| 452 node->GetAllValues(matches_out); | |
| 453 } | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 // static | |
| 458 bool RTree::Node::CompareVertical(Node* a, Node* b) { | |
| 459 // Sort nodes by top coordinate first. | |
| 460 if (a->rect_.y() < b->rect_.y()) { | |
| 461 return true; | |
| 462 } else if (a->rect_.y() == b->rect_.y()) { | |
| 463 // If top coordinate is equal, sort by lowest bottom coordinate. | |
| 464 return a->rect_.height() < b->rect_.height(); | |
| 465 } | |
| 466 return false; | |
| 467 } | |
| 468 | |
| 469 // static | |
| 470 bool RTree::Node::CompareHorizontal(Node* a, Node* b) { | |
| 471 // Sort nodes by left coordinate first. | |
| 472 if (a->rect_.x() < b->rect_.x()) { | |
| 473 return true; | |
| 474 } else if (a->rect_.x() == b->rect_.x()) { | |
| 475 // If left coordinate is equal, sort by lowest right coordinate. | |
| 476 return a->rect_.width() < b->rect_.width(); | |
| 477 } | |
| 478 return false; | |
| 479 } | |
| 480 | |
| 481 // Sort these two nodes by the distance of the center of their rects from the | |
| 482 // center of their parent's rect. We don't bother with square roots because we | |
| 483 // are only comparing the two values for sorting purposes. | |
| 484 // static | |
| 485 bool RTree::Node::CompareCenterDistanceFromParent(Node* a, Node* b) { | |
| 486 // This comparison assumes the nodes have the same parent. | |
| 487 DCHECK(a->parent_ == b->parent_); | |
| 488 // This comparison requires that each node have a parent. | |
| 489 DCHECK(a->parent_); | |
| 490 // Sanity-check level_ of these nodes is equal. | |
| 491 DCHECK_EQ(a->level_, b->level_); | |
| 492 // Also the parent of the nodes should have level one higher. | |
| 493 DCHECK_EQ(a->level_, a->parent_->level_ - 1); | |
| 494 | |
| 495 // Find the parent. | |
| 496 Node* p = a->parent(); | |
| 497 | |
| 498 Vector2d p_center = CenterOfRect(p->rect_); | |
| 499 Vector2d a_center = CenterOfRect(a->rect_); | |
| 500 Vector2d b_center = CenterOfRect(b->rect_); | |
| 501 | |
| 502 return (a_center - p_center).LengthSquared() < | |
| 503 (b_center - p_center).LengthSquared(); | |
| 504 } | |
| 505 | |
| 506 size_t RTree::Node::ChooseSplitIndex(size_t min_children, | |
| 507 size_t max_children, | |
| 508 const std::vector<Rect>& low_bounds, | |
| 509 const std::vector<Rect>& high_bounds) { | |
| 510 int smallest_overlap_area = std::numeric_limits<int>::max(); | |
| 511 int smallest_combined_area = std::numeric_limits<int>::max(); | |
| 512 size_t optimal_split_index = 0; | |
| 513 for (size_t p = min_children; p < max_children - min_children; ++p) { | |
| 514 Rect overlap_bounds = low_bounds[p]; | |
| 515 overlap_bounds.Union(high_bounds[p]); | |
| 516 int overlap_area = overlap_bounds.size().GetArea(); | |
| 517 if (overlap_area < smallest_overlap_area) { | |
| 518 smallest_overlap_area = overlap_area; | |
| 519 smallest_combined_area = | |
| 520 low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea(); | |
| 521 optimal_split_index = p; | |
| 522 } else if (overlap_area == smallest_overlap_area) { | |
| 523 // Break ties with smallest combined area of the two bounding boxes. | |
| 524 int combined_area = | |
| 525 low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea(); | |
| 526 if (combined_area < smallest_combined_area) { | |
| 527 smallest_combined_area = combined_area; | |
| 528 optimal_split_index = p; | |
| 529 } | |
| 530 } | |
| 531 } | |
| 532 | |
| 533 // optimal_split_index currently points at the last element in the first set, | |
| 534 // so advance it by 1 to point at the first element in the second set. | |
| 535 return optimal_split_index + 1; | |
| 536 } | |
| 537 | |
| 538 void RTree::Node::RecomputeBoundsNoParents() { | |
| 539 // Clear our rectangle, then reset it to union of our children. | |
| 540 rect_.SetRect(0, 0, 0, 0); | |
| 541 for (size_t i = 0; i < children_.size(); ++i) { | |
| 542 rect_.Union(children_[i]->rect_); | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 RTree::RTree(size_t min_children, size_t max_children) | |
| 547 : root_(new Node(0)), | |
| 548 min_children_(min_children), | |
| 549 max_children_(max_children) { | |
| 550 // R-Trees require min_children >= 2 | |
| 551 DCHECK_GE(min_children_, 2U); | |
| 552 // R-Trees also require min_children <= max_children / 2 | |
| 553 DCHECK_LE(min_children_, max_children_ / 2U); | |
| 554 root_.reset(new Node(0)); | |
| 555 } | |
| 556 | |
| 557 RTree::~RTree() { | |
| 558 Clear(); | |
| 559 } | |
| 560 | |
| 561 void RTree::Insert(const Rect& rect, const void* key) { | |
| 562 // Non-NULL keys, please. | |
| 563 DCHECK(key); | |
| 564 | |
| 565 Node* record_node = NULL; | |
| 566 // Check if this key is already present in the tree. | |
| 567 std::map<const void*, Node*>::iterator it = record_map_.find(key); | |
| 568 if (it != record_map_.end()) { | |
| 569 // We will re-use this node structure, regardless of re-insert or return. | |
| 570 record_node = it->second; | |
| 571 // If the new rect and the current rect are identical we can skip rest of | |
| 572 // Insert() as nothing has changed. | |
| 573 if (record_node->rect() == rect) | |
| 574 return; | |
| 575 | |
| 576 // Remove the node from the tree in its current position. | |
| 577 RemoveNode(record_node); | |
| 578 | |
| 579 // If we are replacing this key with an empty rectangle we just remove the | |
| 580 // old node from the list and return, thus preventing insertion of empty | |
| 581 // rectangles into our spatial database. | |
| 582 if (rect.IsEmpty()) { | |
| 583 record_map_.erase(it); | |
| 584 delete record_node; | |
| 585 return; | |
| 586 } | |
| 587 | |
| 588 // Reset the rectangle to the new value. | |
| 589 record_node->SetRect(rect); | |
| 590 } else { | |
| 591 if (rect.IsEmpty()) | |
| 592 return; | |
| 593 // Build a new record Node for insertion in to tree. | |
| 594 record_node = new Node(rect, key); | |
| 595 // Add this new node to our map, for easy retrieval later. | |
| 596 record_map_.insert(std::make_pair(key, record_node)); | |
| 597 } | |
| 598 | |
| 599 // Call internal Insert with this new node and allowing all re-inserts. | |
| 600 int starting_level = -1; | |
| 601 InsertNode(record_node, &starting_level); | |
| 602 } | |
| 603 | |
| 604 void RTree::Remove(const void* key) { | |
| 605 // Search the map for the leaf parent that has the provided record. | |
| 606 std::map<const void*, Node*>::iterator it = record_map_.find(key); | |
| 607 // If not in the map it's not in the tree, we're done. | |
| 608 if (it == record_map_.end()) | |
| 609 return; | |
| 610 | |
| 611 Node* node = it->second; | |
| 612 // Remove this node from the map. | |
| 613 record_map_.erase(it); | |
| 614 // Now remove it from the RTree. | |
| 615 RemoveNode(node); | |
| 616 delete node; | |
| 617 | |
| 618 // Lastly check the root. If it has only one non-leaf child, delete it and | |
| 619 // replace it with its child. | |
| 620 if (root_->count() == 1 && root_->level() > 0) | |
| 621 root_.reset(root_->RemoveAndReturnLastChild()); | |
| 622 } | |
| 623 | |
| 624 void RTree::Query(const Rect& query_rect, | |
| 625 std::set<const void*>* matches_out) const { | |
| 626 root_->Query(query_rect, matches_out); | |
| 627 } | |
| 628 | |
| 629 void RTree::Clear() { | |
| 630 record_map_.clear(); | |
| 631 root_.reset(new Node(0)); | |
| 632 } | |
| 633 | |
| 634 void RTree::InsertNode(Node* node, int* highest_reinsert_level) { | |
| 635 // Find the most appropriate parent to insert node into. | |
| 636 Node* parent = root_->ChooseSubtree(node); | |
| 637 DCHECK(parent); | |
| 638 // Verify ChooseSubtree returned a Node at the correct level. | |
| 639 DCHECK_EQ(parent->level(), node->level() + 1); | |
| 640 Node* insert_node = node; | |
| 641 Node* insert_parent = parent; | |
| 642 Node* needs_bounds_recomputed = insert_parent->parent(); | |
| 643 std::vector<Node*> reinserts; | |
| 644 // Attempt to insert the Node, if this overflows the Node we must handle it. | |
| 645 while (insert_parent && | |
| 646 insert_parent->AddChild(insert_node) > max_children_) { | |
| 647 // If we have yet to re-insert nodes at this level during this data insert, | |
| 648 // and we're not at the root, R*-Tree calls for re-insertion of some of the | |
| 649 // nodes, resulting in a better balance on the tree. | |
| 650 if (insert_parent->parent() && | |
| 651 insert_parent->level() > *highest_reinsert_level) { | |
| 652 insert_parent->RemoveNodesForReinsert(max_children_ / 3, &reinserts); | |
| 653 // Adjust highest_reinsert_level to this level. | |
| 654 *highest_reinsert_level = insert_parent->level(); | |
| 655 // We didn't create any new nodes so we have nothing new to insert. | |
| 656 insert_node = NULL; | |
| 657 // RemoveNodesForReinsert() does not recompute bounds, so mark it. | |
| 658 needs_bounds_recomputed = insert_parent; | |
| 659 break; | |
| 660 } | |
| 661 | |
| 662 // Split() will create a sibling to insert_parent both of which will have | |
| 663 // valid bounds, but this invalidates their parent's bounds. | |
| 664 insert_node = insert_parent->Split(min_children_, max_children_); | |
| 665 insert_parent = insert_parent->parent(); | |
| 666 needs_bounds_recomputed = insert_parent; | |
| 667 } | |
| 668 | |
| 669 // If we have a Node to insert, and we hit the root of the current tree, | |
| 670 // we create a new root which is the parent of the current root and the | |
| 671 // insert_node | |
| 672 if (!insert_parent && insert_node) { | |
| 673 Node* old_root = root_.release(); | |
| 674 root_.reset(new Node(old_root->level() + 1)); | |
| 675 root_->AddChild(old_root); | |
| 676 root_->AddChild(insert_node); | |
| 677 } | |
| 678 | |
| 679 // Recompute bounds along insertion path. | |
| 680 if (needs_bounds_recomputed) { | |
| 681 needs_bounds_recomputed->RecomputeBounds(); | |
| 682 } | |
| 683 | |
| 684 // Complete re-inserts, if any. | |
| 685 for (size_t i = 0; i < reinserts.size(); ++i) { | |
| 686 InsertNode(reinserts[i], highest_reinsert_level); | |
| 687 } | |
| 688 } | |
| 689 | |
| 690 void RTree::RemoveNode(Node* node) { | |
| 691 // We need to remove this node from its parent. | |
| 692 Node* parent = node->parent(); | |
| 693 // Record nodes are never allowed as the root, so we should always have a | |
| 694 // parent. | |
| 695 DCHECK(parent); | |
| 696 // Should always be a leaf that had the record. | |
| 697 DCHECK_EQ(parent->level(), 0); | |
| 698 std::vector<Node*> orphans; | |
| 699 Node* child = node; | |
| 700 | |
| 701 // Traverse up the tree, removing the child from each parent and deleting | |
| 702 // parent nodes, until we either encounter the root of the tree or a parent | |
| 703 // that still has sufficient children. | |
| 704 while (parent && parent->RemoveChild(child, &orphans) < min_children_) { | |
| 705 if (child != node) { | |
| 706 delete child; | |
| 707 } | |
| 708 child = parent; | |
| 709 parent = parent->parent(); | |
| 710 } | |
| 711 | |
| 712 // If we stopped deleting nodes up the tree before encountering the root, | |
| 713 // we'll need to fix up the bounds from the first parent we didn't delete | |
| 714 // up to the root. | |
| 715 if (parent) { | |
| 716 parent->RecomputeBounds(); | |
| 717 } | |
| 718 | |
| 719 // Now re-insert each of the orphaned nodes back into the tree. | |
| 720 for (size_t i = 0; i < orphans.size(); ++i) { | |
| 721 int starting_level = -1; | |
| 722 InsertNode(orphans[i], &starting_level); | |
| 723 } | |
| 724 } | |
| 725 | |
| 726 } // namespace gfx | |
| OLD | NEW |