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 gfx { | |
| 13 | |
| 14 RTree::Node::Node(int level) | |
| 15 : base::LinkNode<Node>(), | |
| 16 level_(level), | |
| 17 count_(0), | |
| 18 parent_(NULL), | |
| 19 key_(NULL) {} | |
| 20 | |
| 21 RTree::Node::Node(const Rect& rect, void* key) | |
| 22 : base::LinkNode<Node>(), | |
| 23 rect_(rect), | |
| 24 level_(-1), | |
| 25 count_(0), | |
| 26 parent_(NULL), | |
| 27 key_(key) {} | |
| 28 | |
| 29 RTree::Node::~Node() { | |
| 30 Clear(); | |
| 31 } | |
| 32 | |
| 33 void RTree::Node::Clear() { | |
| 34 // Iterate through children and delete them all. | |
| 35 while (children_.head() != children_.end()) { | |
| 36 base::LinkNode<Node>* node = children_.head(); | |
| 37 node->RemoveFromList(); | |
| 38 delete node->value(); | |
| 39 } | |
| 40 key_ = NULL; | |
| 41 } | |
| 42 | |
| 43 void RTree::Node::Query( | |
| 44 const Rect& query_rect, std::set<void*>* matches_out) const { | |
| 45 // Check own bounding box for intersection, can cull all children if no | |
| 46 // intersection. | |
| 47 if (!rect_.Intersects(query_rect)) { | |
| 48 return; | |
| 49 } | |
| 50 | |
| 51 // Conversely if we are completely contained within the query rect we can | |
| 52 // confidently skip all bounds checks for ourselves and all our children. | |
| 53 if (query_rect.Contains(rect_)) { | |
| 54 GetAllValues(matches_out); | |
| 55 return; | |
| 56 } | |
| 57 | |
| 58 // We intersect the query rect but we are not are not contained within it. | |
| 59 // If we are a record node, then add our record value. Otherwise we must | |
| 60 // query each of our children in turn. | |
| 61 if (key_) { | |
| 62 DCHECK_EQ(level_, -1); | |
| 63 matches_out->insert(key_); | |
| 64 } else { | |
| 65 for (base::LinkNode<Node>* link_node = children_.head(); | |
| 66 link_node != children_.end(); | |
| 67 link_node = link_node->next()) { | |
| 68 Node* node = link_node->value(); | |
| 69 // Sanity-check our children. | |
| 70 DCHECK_EQ(node->parent_, this); | |
| 71 DCHECK_EQ(level_ - 1, node->level_); | |
| 72 DCHECK(rect_.Contains(node->rect_)); | |
| 73 node->Query(query_rect, matches_out); | |
| 74 } | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 void RTree::Node::RecomputeBounds() { | |
| 79 RecomputeBoundsNoParents(); | |
| 80 // Recompute our parent's bounds recursively up to the root. | |
| 81 if (parent_) { | |
| 82 parent_->RecomputeBounds(); | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 void RTree::Node::RemoveNodesForReinsert( | |
| 87 size_t number_to_remove, std::list<Node*>* nodes) { | |
|
piman
2014/04/21 23:59:31
Why not std::vector<Node*>? You know the size ahea
luken
2014/04/28 01:33:34
Done.
| |
| 88 DCHECK_GE(count_, number_to_remove); | |
| 89 // Sort our children in descending order of distance from our bounding | |
| 90 // rect center to their bounding rect center. | |
| 91 std::vector<Node*> center_sort; | |
| 92 center_sort.reserve(count_); | |
| 93 // copy points to our children into each array. | |
| 94 for (base::LinkNode<Node>* link_node = children_.head(); | |
| 95 link_node != children_.end(); | |
| 96 link_node = link_node->next()) { | |
| 97 center_sort.push_back(link_node->value()); | |
| 98 } | |
| 99 DCHECK_EQ(count_, center_sort.size()); | |
| 100 std::sort(center_sort.begin(), | |
| 101 center_sort.end(), | |
| 102 &RTree::Node::CompareCenterDistanceFromParent); | |
| 103 // Remove the highest distance nodes from our children list, and then add them | |
| 104 // to the returned list. | |
| 105 for (size_t i = 0; i < number_to_remove; ++i) { | |
| 106 center_sort[i]->RemoveFromList(); | |
| 107 nodes->push_back(center_sort[i]); | |
| 108 } | |
| 109 // Update our internal references including bounds. | |
| 110 count_ = count_ - number_to_remove; | |
| 111 } | |
| 112 | |
| 113 size_t RTree::Node::RemoveChild(Node* child_node, std::list<Node*>* orphans) { | |
|
piman
2014/04/21 23:59:31
std::vector here too? You also know the size.
luken
2014/04/28 01:33:34
Done.
| |
| 114 // Should actually be one of our children. | |
| 115 DCHECK_EQ(child_node->parent_, this); | |
| 116 // Remove any children of this child and append to orphans list. | |
| 117 Node* orphan = child_node->RemoveAndReturnFirstChild(); | |
| 118 while (orphan) { | |
| 119 orphans->push_back(orphan); | |
| 120 orphan = child_node->RemoveAndReturnFirstChild(); | |
| 121 } | |
|
piman
2014/04/21 23:59:31
It seems like we could simply walk the list of chi
luken
2014/04/28 01:33:34
Done.
| |
| 122 child_node->RemoveFromList(); | |
| 123 count_--; | |
| 124 return count_; | |
| 125 } | |
| 126 | |
| 127 RTree::Node* RTree::Node::RemoveAndReturnFirstChild() { | |
| 128 if (children_.head() == children_.end()) { | |
| 129 return NULL; | |
| 130 } | |
| 131 Node* first_child = children_.head()->value(); | |
| 132 DCHECK_EQ(first_child->parent_, this); | |
| 133 first_child->RemoveFromList(); | |
|
piman
2014/04/21 23:59:31
Do we need to --count_ ?
luken
2014/04/28 01:33:34
Done.
| |
| 134 // Invalidate parent, as this child may even become the new root. | |
| 135 first_child->parent_ = NULL; | |
| 136 return first_child; | |
| 137 } | |
| 138 | |
| 139 // Uses the R*-Tree algorithm CHOOSELEAF proposed by Beckmann et al. | |
| 140 RTree::Node* RTree::Node::ChooseSubtree(Node* node) { | |
| 141 // Should never be called on a record node. | |
| 142 DCHECK(!key_); | |
| 143 DCHECK(level_ >= 0); | |
| 144 DCHECK(node); | |
| 145 | |
| 146 // If we are a parent of nodes on the provided node level, we are done. | |
| 147 if (level_ == node->level_ + 1) { | |
| 148 return this; | |
| 149 } | |
| 150 // We are an internal node, and thus guaranteed to have children. | |
| 151 DCHECK(children_.head() != children_.end()); | |
| 152 | |
| 153 // Iterate over all children to find best candidate for insertion. | |
| 154 Node* best_candidate = NULL; | |
| 155 int least_overlap_increase = std::numeric_limits<int>::max(); | |
| 156 int least_area_change = std::numeric_limits<int>::max(); | |
| 157 for (base::LinkNode<Node>* link_node = children_.head(); | |
| 158 link_node != children_.end(); | |
| 159 link_node = link_node->next()) { | |
| 160 Node* candidate_node = link_node->value(); | |
| 161 // All of our children should be at our level - 1. | |
| 162 DCHECK_EQ(level_ - 1, candidate_node->level_); | |
| 163 // All of our children should have us as a parent. | |
| 164 DCHECK_EQ(this, candidate_node->parent_); | |
| 165 int overlap_increase = std::numeric_limits<int>::max(); | |
| 166 // For Nodes whose children are leaves, we calculate minimum overlap | |
| 167 // increase caused by addition of this new record Node. | |
| 168 if (!candidate_node->level_) { | |
|
piman
2014/04/21 23:59:31
This is a loop constant (given checks above). Can
luken
2014/04/28 01:33:34
So the algorithm calls for node selection using mi
| |
| 169 // Expand candidate rect to include the new node rect. | |
| 170 Rect expanded_rect = candidate_node->rect_; | |
| 171 expanded_rect.Union(node->rect_); | |
|
piman
2014/04/21 23:59:31
If node->rect_ is fully contained in candidate_nod
luken
2014/04/28 01:33:34
Yes, good observation, done.
| |
| 172 int total_original_overlap = 0; | |
| 173 int total_expanded_overlap = 0; | |
| 174 | |
| 175 // Now calculate overlap with all other rects in this node. | |
| 176 for (base::LinkNode<Node>* overlap_link_node = children_.head(); | |
| 177 overlap_link_node != children_.end(); | |
| 178 overlap_link_node = overlap_link_node->next()) { | |
| 179 Node* overlap_node = overlap_link_node->value(); | |
| 180 // Skip calculating overlap with the candidate rect. | |
| 181 if (overlap_node == candidate_node) { | |
| 182 continue; | |
| 183 } | |
| 184 Rect overlap_rect = candidate_node->rect_; | |
| 185 overlap_rect.Intersect(overlap_node->rect_); | |
| 186 total_original_overlap += overlap_rect.width() * overlap_rect.height(); | |
|
piman
2014/04/21 23:59:31
nit: overlap_rect.size().GetArea()
(other places t
luken
2014/04/28 01:33:34
Done.
| |
| 187 Rect expanded_overlap_rect = expanded_rect; | |
| 188 expanded_overlap_rect.Intersect(overlap_node->value()->rect_); | |
|
piman
2014/04/21 23:59:31
overlap_node->rect_?
luken
2014/04/28 01:33:34
Done.
| |
| 189 total_expanded_overlap += | |
| 190 expanded_overlap_rect.width() * expanded_overlap_rect.height(); | |
| 191 } | |
| 192 | |
| 193 // Compare this overlap increase with best one to date, update best. | |
| 194 overlap_increase = total_expanded_overlap - total_original_overlap; | |
| 195 if (overlap_increase < least_overlap_increase) { | |
| 196 best_candidate = candidate_node->value(); | |
|
piman
2014/04/21 23:59:31
no ->value()
luken
2014/04/28 01:33:34
Done.
| |
| 197 least_overlap_increase = overlap_increase; | |
| 198 least_area_change = AreaChangeToAdd(candidate_node->rect_, node->rect_); | |
|
piman
2014/04/21 23:59:31
AreaChangeToAdd computes the union bounds, that we
piman
2014/04/21 23:59:31
you probably want a continue here.
the rest of the
luken
2014/04/28 01:33:34
I don't quite understand this. This code is not in
luken
2014/04/28 01:33:34
Done.
| |
| 199 } | |
| 200 } | |
| 201 | |
| 202 // For non-leaf internal nodes, or for leafs that are tied, we choose least | |
| 203 // area enlargement required to add this rect. | |
| 204 if (candidate_node->level_ > 0 || | |
| 205 overlap_increase == least_overlap_increase) { | |
|
piman
2014/04/21 23:59:31
This is always true if candidate_node->level_ > 0
luken
2014/04/28 01:33:34
The candidadate_node->level_ == 0 case needs this
| |
| 206 int candidate_area_change = | |
| 207 AreaChangeToAdd(candidate_node->rect_, node->rect_); | |
|
piman
2014/04/21 23:59:31
You already computed expanded_rect in the (candida
luken
2014/04/28 01:33:34
Done.
| |
| 208 if (candidate_area_change < least_area_change) { | |
| 209 best_candidate = candidate_node; | |
| 210 least_area_change = candidate_area_change; | |
| 211 } else if (candidate_area_change == least_area_change) { | |
| 212 // It is assumed we will always tie with a valid candidate. | |
| 213 DCHECK(best_candidate); | |
| 214 // Ties are broken by choosing entry with least area | |
| 215 if (candidate_node->rect_.width() * candidate_node->rect_.height() < | |
| 216 best_candidate->rect_.width() * best_candidate->rect_.height()) { | |
| 217 best_candidate = candidate_node; | |
| 218 } | |
| 219 } | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 DCHECK(best_candidate); | |
| 224 return best_candidate->ChooseSubtree(node); | |
| 225 } | |
| 226 | |
| 227 size_t RTree::Node::AddNode(Node* node) { | |
| 228 DCHECK(node); | |
| 229 // Sanity-check that the level of the child being added is one more than ours. | |
| 230 DCHECK_EQ(level_ - 1, node->level_); | |
| 231 node->parent_ = this; | |
| 232 children_.Append(node); | |
| 233 ++count_; | |
| 234 rect_.Union(node->rect_); | |
| 235 return count_; | |
| 236 } | |
| 237 | |
| 238 RTree::Node* RTree::Node::Split(size_t min_children, size_t max_children) { | |
| 239 // Please don't attempt to split a record Node. | |
| 240 DCHECK(!key_); | |
| 241 // We should have the correct number of children to begin with. | |
| 242 DCHECK_GT(count_, max_children); | |
| 243 // First determine if splitting along the horizontal or vertical axis. We | |
| 244 // sort the rectangles of our children by lower then upper values along each | |
| 245 // axis. | |
| 246 std::vector<Node*> horizontal_sort; | |
| 247 std::vector<Node*> vertical_sort; | |
| 248 horizontal_sort.reserve(count_); | |
| 249 vertical_sort.reserve(count_); | |
| 250 // Copy pointers to our children into each array. | |
| 251 for (base::LinkNode<Node>* link_node = children_.head(); | |
| 252 link_node != children_.end(); | |
| 253 link_node = link_node->next()) { | |
| 254 Node* node = link_node->value(); | |
| 255 DCHECK_EQ(node->parent_, this); | |
| 256 DCHECK_EQ(level_ - 1, node->level_); | |
| 257 horizontal_sort.push_back(node); | |
| 258 vertical_sort.push_back(node); | |
| 259 } | |
| 260 DCHECK_EQ(count_, horizontal_sort.size()); | |
| 261 std::sort(horizontal_sort.begin(), | |
| 262 horizontal_sort.end(), | |
| 263 &RTree::Node::CompareHorizontal); | |
| 264 std::sort(vertical_sort.begin(), | |
| 265 vertical_sort.end(), | |
| 266 &RTree::Node::CompareVertical); | |
| 267 | |
| 268 // We will be examining the bounding boxes of different splits of our children | |
| 269 // sorted along each axis. Here we precompute the bounding boxes of these | |
| 270 // distributions. For the low bounds the ith element can be considered the | |
| 271 // union of all rects [0,i] in the relevant sorted axis array. | |
| 272 std::vector<Rect> low_horizontal_bounds; | |
| 273 std::vector<Rect> low_vertical_bounds; | |
| 274 Rect horizontal_bounds; | |
| 275 Rect vertical_bounds; | |
| 276 low_horizontal_bounds.reserve(count_); | |
| 277 low_vertical_bounds.reserve(count_); | |
| 278 for (size_t i = 0; i < count_; ++i) { | |
| 279 horizontal_bounds.Union(horizontal_sort[i]->rect_); | |
| 280 vertical_bounds.Union(vertical_sort[i]->rect_); | |
| 281 low_horizontal_bounds.push_back(horizontal_bounds); | |
| 282 low_vertical_bounds.push_back(vertical_bounds); | |
| 283 } | |
| 284 // For the high bounds the ith element can be considered the union of all | |
| 285 // rects [i, count_) in the relevant sorted axis array. | |
| 286 std::vector<Rect> high_horizontal_bounds; | |
| 287 std::vector<Rect> high_vertical_bounds; | |
| 288 horizontal_bounds.SetRect(0, 0, 0, 0); | |
| 289 vertical_bounds.SetRect(0, 0, 0, 0); | |
| 290 high_horizontal_bounds.resize(count_); | |
| 291 high_vertical_bounds.resize(count_); | |
| 292 for (int j = static_cast<int>(count_) - 1; j >= 0; --j) { | |
| 293 horizontal_bounds.Union(horizontal_sort[j]->rect_); | |
| 294 vertical_bounds.Union(vertical_sort[j]->rect_); | |
| 295 high_horizontal_bounds[j] = horizontal_bounds; | |
| 296 high_vertical_bounds[j] = vertical_bounds; | |
| 297 } | |
| 298 | |
| 299 // Examine the possible distributions of each sorted list by iterating through | |
| 300 // valid split points p, min_children <= p <= max_children - min_children, and | |
| 301 // computing the sums of the margins of the required bounding boxes in each | |
| 302 // group. Smallest margin sum will determine split axis. | |
| 303 int smallest_horizontal_margin_sum = std::numeric_limits<int>::max(); | |
| 304 int smallest_vertical_margin_sum = std::numeric_limits<int>::max(); | |
| 305 for (size_t p = min_children; p < max_children - min_children; ++p) { | |
| 306 int horizontal_margin_sum = | |
| 307 low_horizontal_bounds[p].width() + low_horizontal_bounds[p].height() + | |
| 308 high_horizontal_bounds[p].width() + high_horizontal_bounds[p].height(); | |
| 309 int vertical_margin_sum = | |
| 310 low_vertical_bounds[p].width() + low_vertical_bounds[p].height() + | |
| 311 high_vertical_bounds[p].width() + high_vertical_bounds[p].height(); | |
| 312 // Update margin minima if necessary. | |
| 313 smallest_horizontal_margin_sum = | |
| 314 std::min(horizontal_margin_sum, smallest_horizontal_margin_sum); | |
| 315 smallest_vertical_margin_sum = | |
| 316 std::min(vertical_margin_sum, smallest_vertical_margin_sum); | |
| 317 } | |
| 318 | |
| 319 // Split along the axis perpendicular to the axis with the overall smallest | |
| 320 // margin sum. Meaning the axis sort resulting in two boxes with the smallest | |
| 321 // combined margin will become the axis along which the sorted rectangles are | |
| 322 // distributed to the two Nodes. | |
| 323 bool is_vertical_split = | |
| 324 smallest_vertical_margin_sum < smallest_horizontal_margin_sum; | |
| 325 | |
| 326 // Lastly we determine optimal index. | |
| 327 size_t optimal_split_index; | |
| 328 if (is_vertical_split) { | |
| 329 optimal_split_index = CalculateOptimalSplitIndex(min_children, | |
| 330 max_children, | |
| 331 &low_vertical_bounds, | |
| 332 &high_vertical_bounds); | |
| 333 } else { | |
| 334 optimal_split_index = CalculateOptimalSplitIndex(min_children, | |
| 335 max_children, | |
| 336 &low_horizontal_bounds, | |
| 337 &high_horizontal_bounds); | |
| 338 } | |
| 339 | |
| 340 // We have the optimal sort axis as well as the optimal index. Create the | |
| 341 // new Node and give it the latter half of our children. | |
| 342 Node* sibling = new Node(level_); | |
| 343 sibling->parent_ = parent_; | |
| 344 sibling->count_ = count_ - optimal_split_index - 1; | |
| 345 count_ = optimal_split_index + 1; | |
| 346 if (is_vertical_split) { | |
| 347 rect_ = low_vertical_bounds[optimal_split_index]; | |
| 348 sibling->rect_ = high_vertical_bounds[optimal_split_index + 1]; | |
| 349 // Give these children to our sibling. | |
| 350 for (size_t i = optimal_split_index + 1; i < vertical_sort.size(); ++i) { | |
| 351 Node* neice = vertical_sort[i]; | |
| 352 neice->RemoveFromList(); | |
| 353 neice->parent_ = sibling; | |
| 354 sibling->children_.Append(neice); | |
| 355 } | |
| 356 } else { | |
| 357 rect_ = low_horizontal_bounds[optimal_split_index]; | |
| 358 sibling->rect_ = high_horizontal_bounds[optimal_split_index + 1]; | |
| 359 for (size_t i = optimal_split_index + 1; i < horizontal_sort.size(); ++i) { | |
| 360 Node* nephew = horizontal_sort[i]; | |
| 361 nephew->RemoveFromList(); | |
| 362 nephew->parent_ = sibling; | |
| 363 sibling->children_.Append(nephew); | |
| 364 } | |
| 365 } | |
| 366 | |
| 367 return sibling; | |
| 368 } | |
| 369 | |
| 370 void RTree::Node::SetRect(const Rect& rect) { | |
| 371 // Record nodes only, please. | |
| 372 DCHECK(key_); | |
| 373 rect_ = rect; | |
| 374 } | |
| 375 | |
| 376 RTree::Node* RTree::Node::parent() const { | |
| 377 return parent_; | |
| 378 } | |
| 379 | |
| 380 int RTree::Node::level() const { | |
| 381 return level_; | |
| 382 } | |
| 383 | |
| 384 const Rect& RTree::Node::rect() const { | |
| 385 return rect_; | |
| 386 } | |
| 387 | |
| 388 size_t RTree::Node::count() const { | |
| 389 return count_; | |
| 390 } | |
| 391 | |
| 392 bool RTree::Node::Validate(size_t min_children, size_t max_children) const { | |
|
piman
2014/04/21 23:59:31
You can never return anything but true (by inducti
luken
2014/04/28 01:33:34
Yeah I didn't know that we run unit tests in relea
| |
| 393 // We don't call Validate() directly on Record nodes. | |
| 394 DCHECK(!key_); | |
| 395 // Need to have at least one child. | |
| 396 DCHECK_NE(children_.head(), children_.end()); | |
| 397 // Independently compute a bounding rectangle, and make sure it is identical | |
| 398 // to our current bounding rectangle. | |
| 399 Rect bounds(0, 0, 0, 0); | |
| 400 size_t check_count = 0; | |
| 401 for (base::LinkNode<Node>* link_node = children_.head(); | |
| 402 link_node != children_.end(); | |
| 403 link_node = link_node->next()) { | |
| 404 check_count++; | |
| 405 Node* node = link_node->value(); | |
| 406 bounds.Union(node->rect_); | |
| 407 DCHECK_EQ(node->parent_, this); | |
| 408 DCHECK_LE(node->count_, max_children); | |
| 409 DCHECK_EQ(level_ - 1, node->level_); | |
| 410 if (level_) { | |
| 411 DCHECK_GE(node->count_, min_children); | |
| 412 if (!node->Validate(min_children, max_children)) { | |
| 413 return false; | |
| 414 } | |
| 415 } else { | |
| 416 DCHECK_EQ(node->count_, 0U); | |
| 417 DCHECK_EQ(node->children_.head(), node->children_.end()); | |
| 418 DCHECK(node->key_); | |
| 419 } | |
| 420 } | |
| 421 DCHECK_EQ(count_, check_count); | |
| 422 DCHECK(!rect_.IsEmpty()); | |
| 423 DCHECK(rect_ == bounds); | |
| 424 return true; | |
| 425 } | |
| 426 | |
| 427 // Returns all contained record_node values for this node and all children. | |
| 428 void RTree::Node::GetAllValues(std::set<void*>* matches_out) const { | |
| 429 if (key_) { | |
| 430 DCHECK_EQ(level_, -1); | |
| 431 matches_out->insert(key_); | |
| 432 } else { | |
| 433 for (base::LinkNode<Node>* link_node = children_.head(); | |
| 434 link_node != children_.end(); | |
| 435 link_node = link_node->next()) { | |
| 436 Node* node = link_node->value(); | |
| 437 // Sanity-check our children. | |
| 438 DCHECK_EQ(node->parent_, this); | |
| 439 DCHECK_EQ(level_ - 1, node->level_); | |
| 440 DCHECK(rect_.Contains(node->rect_)); | |
| 441 node->GetAllValues(matches_out); | |
| 442 } | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 // static | |
| 447 int RTree::Node::AreaChangeToAdd(const Rect& bounds, const Rect& rect) { | |
|
piman
2014/04/21 23:59:31
nit: might as well make it a free function (in ano
luken
2014/04/28 01:33:34
Done.
| |
| 448 // Quick test for containment of rect in bounds, resulting in 0 area change. | |
| 449 if (bounds.Contains(rect)) { | |
| 450 return 0; | |
| 451 } | |
| 452 int current_area = bounds.width() * bounds.height(); | |
| 453 Rect test_rect(bounds); | |
| 454 // Expand a copy of bounds to contain the new rectangle. | |
| 455 test_rect.Union(rect); | |
| 456 return (test_rect.width() * test_rect.height()) - current_area; | |
| 457 } | |
| 458 | |
| 459 // static | |
| 460 bool RTree::Node::CompareVertical(Node* a, Node* b) { | |
| 461 // Sort nodes by top coordinate first. | |
| 462 if (a->rect_.y() < b->rect_.y()) { | |
| 463 return true; | |
| 464 } else if (a->rect_.y() == b->rect_.y()) { | |
| 465 // If top coordinate is equal, sort by lowest bottom coordinate. | |
| 466 return a->rect_.bottom() < b->rect_.bottom(); | |
|
piman
2014/04/21 23:59:31
test height() instead of bottom(), since the latte
luken
2014/04/28 01:33:34
Done.
| |
| 467 } | |
| 468 return false; | |
| 469 } | |
| 470 | |
| 471 // static | |
| 472 bool RTree::Node::CompareHorizontal(Node* a, Node* b) { | |
| 473 // Sort nodes by left coordinate first. | |
| 474 if (a->rect_.x() < b->rect_.x()) { | |
| 475 return true; | |
| 476 } else if (a->rect_.x() == b->rect_.x()) { | |
| 477 // If left coordinate is equal, sort by lowest right coordinate. | |
| 478 return a->rect_.right() < b->rect_.right(); | |
|
piman
2014/04/21 23:59:31
test width() instead of right().
luken
2014/04/28 01:33:34
Done.
| |
| 479 } | |
| 480 return false; | |
| 481 } | |
| 482 | |
| 483 // Sort these two nodes by the distance of the center of their rects from the | |
| 484 // center of their parent's rect. We don't bother with square roots because we | |
| 485 // are only comparing the two values for sorting purposes. | |
| 486 // static | |
| 487 bool RTree::Node::CompareCenterDistanceFromParent(Node* a, Node* b) { | |
| 488 // This comparison assumes the nodes have the same parent. | |
| 489 DCHECK(a->parent_ == b->parent_); | |
| 490 // This comparison requires that each node have a parent. | |
| 491 DCHECK(a->parent_); | |
| 492 // Sanity-check level_ of these nodes is equal. | |
| 493 DCHECK_EQ(a->level_, b->level_); | |
| 494 // Also the parent of the nodes should have level one higher. | |
| 495 DCHECK_EQ(a->level_, a->parent_->level_ - 1); | |
| 496 | |
| 497 // Find the parent. | |
| 498 Node* p = a->parent(); | |
| 499 | |
| 500 // First we calculate the center of the parent rectangle. | |
| 501 int p_center_x = p->rect_.x() + (p->rect_.width() / 2); | |
| 502 int p_center_y = p->rect_.y() + (p->rect_.height() / 2); | |
|
piman
2014/04/21 23:59:31
nit: it would be more readable to make a free inli
luken
2014/04/28 01:33:34
Done.
| |
| 503 | |
| 504 // Next we calculate the squared distance of a's center to p's center. | |
| 505 int a_dist_sq_x = a->rect_.x() + (a->rect_.width() / 2) - p_center_x; | |
| 506 a_dist_sq_x *= a_dist_sq_x; | |
| 507 int a_dist_sq_y = a->rect_.y() + (a->rect_.height() / 2) - p_center_y; | |
| 508 a_dist_sq_y *= a_dist_sq_y; | |
| 509 | |
| 510 // Now we do the same for b. | |
| 511 int b_dist_sq_x = b->rect_.x() + (b->rect_.width() / 2) - p_center_x; | |
| 512 b_dist_sq_x *= b_dist_sq_x; | |
| 513 int b_dist_sq_y = b->rect_.y() + (b->rect_.height() / 2) - p_center_y; | |
| 514 b_dist_sq_y *= b_dist_sq_y; | |
| 515 | |
| 516 // We are sorting by greatest to least distance so we invert the logic on the | |
| 517 // comparison. | |
| 518 return (a_dist_sq_x + a_dist_sq_y) > (b_dist_sq_x + b_dist_sq_y); | |
| 519 } | |
| 520 | |
| 521 size_t RTree::Node::CalculateOptimalSplitIndex( | |
| 522 size_t min_children, | |
| 523 size_t max_children, | |
| 524 const std::vector<Rect>* low_bounds, | |
| 525 const std::vector<Rect>* high_bounds) { | |
| 526 int smallest_overlap_area = std::numeric_limits<int>::max(); | |
| 527 int smallest_combined_area = std::numeric_limits<int>::max(); | |
| 528 size_t optimal_split_index = 0; | |
| 529 for (size_t p = min_children; p < max_children - min_children; ++p) { | |
| 530 Rect overlap_bounds = low_bounds->at(p); | |
| 531 overlap_bounds.Union(high_bounds->at(p)); | |
| 532 int overlap_area = overlap_bounds.width() * overlap_bounds.height(); | |
| 533 if (overlap_area < smallest_overlap_area) { | |
| 534 smallest_overlap_area = overlap_area; | |
| 535 smallest_combined_area = | |
| 536 (low_bounds->at(p).width() * low_bounds->at(p).height()) + | |
| 537 (high_bounds->at(p).width() * high_bounds->at(p).height()); | |
| 538 optimal_split_index = p; | |
| 539 } else if (overlap_area == smallest_overlap_area) { | |
| 540 // Break ties with smallest combined area of the two bounding boxes. | |
| 541 int combined_area = | |
| 542 (low_bounds->at(p).width() * low_bounds->at(p).height()) + | |
| 543 (high_bounds->at(p).width() * high_bounds->at(p).height()); | |
| 544 if (combined_area < smallest_combined_area) { | |
| 545 smallest_combined_area = combined_area; | |
| 546 optimal_split_index = p; | |
| 547 } | |
| 548 } | |
| 549 } | |
| 550 | |
| 551 return optimal_split_index; | |
| 552 } | |
| 553 | |
| 554 void RTree::Node::RecomputeBoundsNoParents() { | |
| 555 // Clear our rectangle, then reset it to union of our children. | |
| 556 rect_.SetRect(0, 0, 0, 0); | |
| 557 for (base::LinkNode<Node>* node = children_.head(); node != children_.end(); | |
| 558 node = node->next()) { | |
| 559 rect_.Union(node->value()->rect_); | |
| 560 } | |
| 561 } | |
| 562 | |
| 563 RTree::RTree(size_t min_children, size_t max_children) | |
| 564 : root_(NULL), min_children_(min_children), max_children_(max_children) { | |
| 565 // R-Trees require min_children >= 2 | |
| 566 DCHECK_GE(min_children_, 2U); | |
| 567 // R-Trees also require min_children <= max_children / 2 | |
| 568 DCHECK_LE(min_children_, max_children_ / 2U); | |
| 569 } | |
| 570 | |
| 571 RTree::~RTree() { | |
| 572 Clear(); | |
| 573 } | |
| 574 | |
| 575 void RTree::Insert(const Rect& rect, void* key) { | |
| 576 // Non-NULL keys, please. | |
| 577 DCHECK(key); | |
| 578 | |
| 579 // An empty rectangle will never intersect with any other rectangle, and so | |
| 580 // has no purpose within a spatial database. | |
| 581 if (rect.IsEmpty()) | |
| 582 return; | |
|
piman
2014/04/21 23:59:31
That goes contrary to the tests below.
Either remo
luken
2014/04/28 01:33:34
yes, this one is a bug, good catch, removed. I add
| |
| 583 | |
| 584 Node* record_node = NULL; | |
| 585 // Check if this key is already present in the tree. | |
| 586 std::map<void*, Node*>::iterator it = record_map_.find(key); | |
| 587 if (it != record_map_.end()) { | |
| 588 // We will re-use this node structure, regardless of re-insert or return. | |
| 589 record_node = it->second; | |
| 590 // If the new rect and the current rect are identical we can skip rest of | |
| 591 // Insert() as nothing has changed. | |
| 592 if (record_node->rect() == rect) { | |
| 593 return; | |
| 594 } | |
| 595 | |
| 596 // Remove the node from the tree in its current position. | |
| 597 Remove(record_node); | |
| 598 | |
| 599 // If we are replacing this key with an empty rectangle we just remove the | |
| 600 // old node from the list and return, thus preventing insertion of empty | |
| 601 // rectangles into our spatial database. | |
| 602 if (rect.IsEmpty()) { | |
| 603 record_map_.erase(it); | |
| 604 delete record_node; | |
| 605 return; | |
| 606 } | |
| 607 | |
| 608 // Reset the rectangle to the new value. | |
| 609 record_node->SetRect(rect); | |
| 610 } else { | |
| 611 if (rect.IsEmpty()) { | |
| 612 return; | |
| 613 } | |
| 614 // Build a new record Node for insertion in to tree. | |
| 615 record_node = new Node(rect, key); | |
| 616 // Add this new node to our map, for easy retrieval later. | |
| 617 record_map_.insert(std::make_pair(key, record_node)); | |
| 618 } | |
| 619 | |
| 620 // Make a root_ if needed. | |
| 621 if (!root_) { | |
| 622 root_ = new Node(0); | |
|
piman
2014/04/21 23:59:31
Should we just do this in the constructor, and sav
luken
2014/04/28 01:33:34
Done.
| |
| 623 } | |
| 624 | |
| 625 // Call internal Insert with this new node and no re-inserts for this | |
| 626 // of a data node having happened yet. | |
| 627 int starting_level = -1; | |
| 628 Insert(record_node, &starting_level); | |
| 629 } | |
| 630 | |
| 631 void RTree::Remove(void* key) { | |
| 632 // Search the map for the leaf parent that has the provided record. | |
| 633 std::map<void*, Node*>::iterator it = record_map_.find(key); | |
| 634 // If not in the map it's not in the tree, we're done. | |
| 635 if (it == record_map_.end()) { | |
| 636 return; | |
| 637 } | |
| 638 Node* node = it->second; | |
| 639 // Remove this node from the map. | |
| 640 record_map_.erase(it); | |
| 641 // Now remove it from the RTree. | |
| 642 Remove(node); | |
| 643 delete node; | |
| 644 | |
| 645 // Lastly check the root. If it has only one non-leaf child, delete it and | |
| 646 // replace it with its child. If it has no children, we can delete the | |
| 647 // entire empty tree. | |
| 648 if (root_->count() == 1 && root_->level() > 0) { | |
| 649 Node* new_root = root_->RemoveAndReturnFirstChild(); | |
| 650 DCHECK(new_root); | |
| 651 delete root_; | |
| 652 root_ = new_root; | |
| 653 } else if (root_->count() == 0) { | |
| 654 delete root_; | |
| 655 root_ = NULL; | |
| 656 } | |
| 657 } | |
| 658 | |
| 659 void RTree::Query(const Rect& query_rect, std::set<void*>* matches_out) const { | |
| 660 if (root_) { | |
| 661 root_->Query(query_rect, matches_out); | |
| 662 } | |
| 663 } | |
| 664 | |
| 665 void RTree::Clear() { | |
| 666 record_map_.clear(); | |
| 667 delete root_; | |
| 668 root_ = NULL; | |
| 669 } | |
| 670 | |
| 671 void RTree::Insert(Node* node, int* highest_reinsert_level) { | |
| 672 // Internal Insert always assumes that a root has been created. | |
| 673 DCHECK(root_); | |
| 674 // Find the most appropriate parent to insert node into. | |
| 675 Node* parent = root_->ChooseSubtree(node); | |
| 676 DCHECK(parent); | |
| 677 // Verify ChooseSubtree returned a Node at the correct level. | |
| 678 DCHECK_EQ(parent->level(), node->level() + 1); | |
| 679 Node* insert_node = node; | |
| 680 Node* insert_parent = parent; | |
| 681 Node* needs_bounds_recomputed = insert_parent->parent(); | |
| 682 std::list<Node*> reinserts; | |
| 683 // Attempt to insert the Node, if this overflows the Node we must handle it. | |
| 684 while (insert_parent && insert_parent->AddNode(insert_node) > max_children_) { | |
| 685 // If we have yet to re-insert nodes at this level during this data insert, | |
| 686 // and we're not at the root, R*-Tree calls for re-insertion of some of the | |
| 687 // nodes, resulting in a better balance on the tree. | |
| 688 if (insert_parent->parent() && | |
| 689 insert_parent->level() > *highest_reinsert_level) { | |
| 690 insert_parent->RemoveNodesForReinsert(max_children_ / 3, &reinserts); | |
| 691 // Adjust highest_reinsert_level to this level. | |
| 692 *highest_reinsert_level = insert_parent->level(); | |
| 693 // We didn't create any new nodes so we have nothing new to insert. | |
| 694 insert_node = NULL; | |
| 695 // RemoveNodesForReinsert() does not recompute bounds, so mark it. | |
| 696 needs_bounds_recomputed = insert_parent; | |
| 697 break; | |
| 698 } | |
| 699 | |
| 700 // Split() will create a sibling to insert_parent both of which will have | |
| 701 // valid bounds, but this invalidates their parent's bounds. | |
| 702 insert_node = insert_parent->Split(min_children_, max_children_); | |
| 703 insert_parent = insert_parent->parent(); | |
| 704 needs_bounds_recomputed = insert_parent; | |
| 705 } | |
| 706 | |
| 707 // If we have a Node to insert, and we hit the root of the current tree, | |
| 708 // we create a new root which is the parent of the current root and the | |
| 709 // insert_node | |
| 710 if (!insert_parent && insert_node) { | |
| 711 Node* old_root = root_; | |
| 712 root_ = new Node(old_root->level() + 1); | |
| 713 root_->AddNode(old_root); | |
| 714 root_->AddNode(insert_node); | |
| 715 } | |
| 716 | |
| 717 // Recompute bounds along insertion path. | |
| 718 if (needs_bounds_recomputed) { | |
|
piman
2014/04/21 23:59:31
In which case can this be NULL?
luken
2014/04/28 01:33:34
Two I can think of:
a) inserting direct child of
| |
| 719 needs_bounds_recomputed->RecomputeBounds(); | |
|
piman
2014/04/21 23:59:31
If we have reinserts, we'll recompute bounds for p
luken
2014/04/28 01:33:34
Insert() and Remove() as described in both the R-T
| |
| 720 } | |
| 721 | |
| 722 // Complete reinserts, if any. | |
| 723 for (std::list<Node*>::iterator it = reinserts.begin(); | |
| 724 it != reinserts.end(); | |
| 725 it++) { | |
| 726 Insert((*it), highest_reinsert_level); | |
|
piman
2014/04/21 23:59:31
nit: () superfluous
luken
2014/04/28 01:33:34
Done.
| |
| 727 } | |
| 728 } | |
| 729 | |
| 730 void RTree::Remove(Node* node) { | |
| 731 // We need to remove this node from its parent. | |
| 732 Node* parent = node->parent(); | |
| 733 // Record nodes are never allowed as the root, so we should always have a | |
| 734 // parent. | |
| 735 DCHECK(parent); | |
| 736 // Should always be a leaf that had the record. | |
| 737 DCHECK_EQ(parent->level(), 0); | |
| 738 std::list<Node*> orphans; | |
| 739 Node* child = node; | |
| 740 | |
| 741 // Traverse up the tree, removing the child from each parent and deleting | |
| 742 // parent nodes, until we either encounter the root of the tree or a parent | |
| 743 // that still has sufficient children. | |
| 744 while (parent && parent->RemoveChild(child, &orphans) < min_children_) { | |
| 745 if (child != node) { | |
| 746 delete child; | |
| 747 } | |
| 748 child = parent; | |
| 749 parent = parent->parent(); | |
| 750 } | |
| 751 | |
| 752 // If we stopped deleting nodes up the tree before encountering the root, | |
| 753 // we'll need to fix up the bounds from the first parent we didn't delete | |
| 754 // up to the root. | |
| 755 if (parent) { | |
| 756 parent->RecomputeBounds(); | |
| 757 } | |
| 758 | |
| 759 // Now re-insert each of the orphaned nodes back into the tree. | |
| 760 for (std::list<Node*>::iterator it = orphans.begin(); it != orphans.end(); | |
| 761 it++) { | |
| 762 int starting_level = -1; | |
| 763 Insert((*it), &starting_level); | |
|
piman
2014/04/21 23:59:31
nit: no need for extra ()
luken
2014/04/28 01:33:34
Done.
| |
| 764 } | |
| 765 } | |
| 766 | |
| 767 bool RTree::Validate() const { | |
| 768 if (!root_) { | |
| 769 return true; | |
| 770 } | |
| 771 // Root is special in that it needs to have at least one child but can | |
| 772 // have less than min_children. | |
| 773 DCHECK_GE(root_->count(), 1U); | |
| 774 DCHECK_LE(root_->count(), max_children_); | |
| 775 return root_->Validate(min_children_, max_children_); | |
| 776 } | |
| 777 | |
| 778 } // namespace gfx | |
| OLD | NEW |