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

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

Issue 245763002: Adds an RTree data structure to gfx/geometry (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: adds OWNERS change Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698