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

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: ready for review, thanks Created 6 years, 7 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
« no previous file with comments | « ui/gfx/geometry/r_tree.h ('k') | ui/gfx/geometry/r_tree_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 {
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
OLDNEW
« no previous file with comments | « ui/gfx/geometry/r_tree.h ('k') | ui/gfx/geometry/r_tree_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698