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

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

Issue 269513002: readability review for luken (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: ready for next round of feedbac 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
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gfx/geometry/r_tree_base.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10
11 // Helpers --------------------------------------------------------------------
12
13 namespace {
14
Peter Kasting 2014/05/16 01:41:05 Nit: Either eliminate this blank line, or add one
luken 2014/05/21 20:19:36 Done.
15 // Returns a Vector2d to allow us to do arithmetic on the result such as
16 // computing distances between centers.
17 gfx::Vector2d CenterOfRect(const gfx::Rect& rect) {
18 return rect.OffsetFromOrigin() +
19 gfx::Vector2d(rect.width() / 2, rect.height() / 2);
Peter Kasting 2014/05/16 01:41:05 Nit: The Google style guide is unclear here, but C
luken 2014/05/21 20:19:36 Done.
20 }
21 }
22
23 namespace gfx {
24
25
26 // RTreeBase::NodeBase --------------------------------------------------------
27
28 RTreeBase::NodeBase::~NodeBase() {
29 }
30
31 void RTreeBase::NodeBase::RecomputeBoundsUpToRoot() {
32 RecomputeLocalBounds();
33 if (parent_)
34 parent_->RecomputeBoundsUpToRoot();
35 }
36
37 RTreeBase::NodeBase::NodeBase(const Rect& rect, NodeBase* parent)
38 : rect_(rect), parent_(parent) {
Peter Kasting 2014/05/16 01:41:05 Nit: Another unclear rule, but I read the style gu
luken 2014/05/21 20:19:36 Done.
39 }
40
41
42 // RTreeBase::RecordBase ------------------------------------------------------
43
44 RTreeBase::RecordBase::RecordBase(const Rect& rect) : NodeBase(rect, NULL) {
45 }
46
47 RTreeBase::RecordBase::~RecordBase() {
48 }
49
50 void RTreeBase::RecordBase::SetRect(const Rect& rect) {
51 rect_ = rect;
Peter Kasting 2014/05/16 01:41:05 This should probably be inlined into the header as
luken 2014/05/21 20:19:36 Done.
52 }
53
54 void RTreeBase::RecordBase::Query(const Rect& query_rect,
55 Records* matches_out) const {
56 if (!rect_.Intersects(query_rect))
Peter Kasting 2014/05/16 01:41:05 Nit: It seems to read more clearly to me to revers
luken 2014/05/21 20:19:36 Done.
57 return;
58
59 matches_out->push_back(this);
60 }
61
62 scoped_ptr<RTreeBase::NodeBase>
63 RTreeBase::RecordBase::RemoveAndReturnLastChild() {
64 return scoped_ptr<NodeBase>();
65 }
66
67 const int RTreeBase::RecordBase::level() const {
68 return -1;
69 }
70
71 void RTreeBase::RecordBase::RecomputeLocalBounds() {
72 }
Peter Kasting 2014/05/16 01:41:05 Perhaps the base class should define this empty im
luken 2014/05/21 20:19:36 Done.
73
74 void RTreeBase::RecordBase::GetAllValues(Records* matches_out) const {
75 matches_out->push_back(this);
76 }
77
78
79 // RTreeBase::Node ------------------------------------------------------------
80
81 RTreeBase::Node::Node() : Node(0) {
Peter Kasting 2014/05/16 01:41:05 Isn't calling one constructor from another C++11-o
luken 2014/05/21 20:19:36 Done.
82 }
83
84 RTreeBase::Node::~Node() {
85 }
86
87 scoped_ptr<RTreeBase::Node> RTreeBase::Node::MakeParent() {
88 DCHECK(!parent_);
89 scoped_ptr<Node> new_parent(new Node(level_ + 1));
90 new_parent->AddChild(scoped_ptr<NodeBase>(this));
91 return new_parent.Pass();
92 }
93
94 scoped_ptr<RTreeBase::Node> RTreeBase::Node::MakeSibling() {
95 scoped_ptr<Node> new_sibling(new Node(level_));
96 return new_sibling.Pass();
97 }
98
99 void RTreeBase::Node::Query(const Rect& query_rect,
100 Records* matches_out) const {
101 // Check own bounding box for intersection, can cull all children if no
102 // intersection.
103 if (!rect_.Intersects(query_rect))
104 return;
105
106 // Conversely if we are completely contained within the query rect we can
107 // confidently skip all bounds checks for ourselves and all our children.
108 if (query_rect.Contains(rect_)) {
109 GetAllValues(matches_out);
110 return;
111 }
112
113 // We intersect the query rect but we are not are not contained within it.
114 // We must query each of our children in turn.
115 for (Nodes::const_iterator i = children_.begin(); i != children_.end(); ++i) {
Peter Kasting 2014/05/16 01:41:05 Nit: Avoid braces since the loop header and body a
luken 2014/05/21 20:19:36 Done.
116 (*i)->Query(query_rect, matches_out);
117 }
118 }
119
120 void RTreeBase::Node::RemoveNodesForReinsert(size_t number_to_remove,
121 Nodes* nodes) {
122 DCHECK_LE(number_to_remove, children_.size());
123
124 std::sort(children_.begin(),
Peter Kasting 2014/05/16 01:41:05 You can use partial_sort() instead of sort() here
luken 2014/05/21 20:19:36 Neat, didn't know about that. Done.
125 children_.end(),
126 &RTreeBase::Node::CompareCenterDistanceFromParent);
127
128 // Move the lowest-distance nodes to the returned vector.
129 nodes->insert(
130 nodes->end(), children_.begin(), children_.begin() + number_to_remove);
131 children_.weak_erase(children_.begin(), children_.begin() + number_to_remove);
132 }
133
134 size_t RTreeBase::Node::RemoveChild(NodeBase* child_node, Nodes* orphans) {
135 DCHECK_EQ(child_node->parent(), this);
Peter Kasting 2014/05/16 01:41:05 Nit: (expected, actual)
luken 2014/05/21 20:19:36 Done.
136
137 scoped_ptr<NodeBase> orphan = child_node->RemoveAndReturnLastChild();
Peter Kasting 2014/05/16 01:41:05 Nit: See previous comment suggesting constructor-s
luken 2014/05/21 20:19:36 Done.
138 while (orphan) {
139 orphans->push_back(orphan.release());
140 orphan = child_node->RemoveAndReturnLastChild();
Peter Kasting 2014/05/16 01:41:05 Curiosity: This will push the children onto the ou
luken 2014/05/21 20:19:36 The nodes are sorted by 3 different criteria: lowe
Peter Kasting 2014/05/29 00:32:25 This is an excellent argument, consider adding it
141 }
142
143 for (Nodes::iterator i = children_.begin(); i != children_.end(); ++i) {
Peter Kasting 2014/05/16 01:41:05 How about using std::find? It ought to make this
luken 2014/05/21 20:19:36 Done.
144 if (*i == child_node) {
145 children_.weak_erase(i);
146 break;
147 }
148 }
149
150 return children_.size();
151 }
152
153 scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::RemoveAndReturnLastChild() {
154 if (children_.empty())
155 return scoped_ptr<NodeBase>();
156
157 scoped_ptr<NodeBase> last_child(children_.back());
158 children_.weak_erase(children_.end() - 1);
159 last_child->SetParent(NULL);
160 return last_child.Pass();
161 }
162
163 RTreeBase::Node* RTreeBase::Node::ChooseSubtree(NodeBase* node) {
164 DCHECK(node);
165 // Should never be called on a node at equal or lower level in the tree than
166 // the node to insert.
167 DCHECK_GT(level_, node->level());
168
169 // If we are a parent of nodes on the provided node level, we are done.
170 if (level_ == node->level() + 1)
171 return this;
172
173 // Precompute a vector of expanded rects, used both by LeastOverlapIncrease
Peter Kasting 2014/05/16 01:41:05 Nit: both by -> by both
luken 2014/05/21 20:19:36 Done.
174 // and LeastAreaEnlargement.
175 std::vector<Rect> expanded_rects;
Peter Kasting 2014/05/16 01:41:05 Use your Rects typedef (many places across the fil
luken 2014/05/21 20:19:36 Done.
176 expanded_rects.reserve(children_.size());
177 for (Nodes::iterator i = children_.begin(); i != children_.end(); ++i) {
178 expanded_rects.push_back(UnionRects(node->rect(), (*i)->rect()));
179 }
180
181 Node* best_candidate = NULL;
182 // For parents of leaf nodes, we pick the node that will cause the least
183 // increase in overlap by the addition of this new node. This may detect a
184 // tie, in which case it will return NULL.
185 if (level_ == 1)
186 best_candidate = LeastOverlapIncrease(node->rect(), expanded_rects);
187
188 // For non-parents of leaf nodes, or for parents of leaf nodes with ties in
189 // overlap increase, we choose the subtree with least area enlargement caused
190 // by the addition of the new node.
191 if (!best_candidate)
192 best_candidate = LeastAreaEnlargement(node->rect(), expanded_rects);
193
194 DCHECK(best_candidate);
195 return best_candidate->ChooseSubtree(node);
196 }
197
198 size_t RTreeBase::Node::AddChild(scoped_ptr<NodeBase> node) {
199 DCHECK(node);
200 // Sanity-check that the level of the child being added is one less than ours.
201 DCHECK_EQ(level_ - 1, node->level());
202 node->SetParent(this);
203 rect_.Union(node->rect());
204 children_.push_back(node.release());
205 return children_.size();
206 }
207
208 RTreeBase::Node* RTreeBase::Node::Split(size_t min_children,
209 size_t max_children) {
210 // We should have too many children to begin with.
211 DCHECK_GT(children_.size(), max_children);
212
213 // Determine if we should split along the horizontal or vertical axis.
214 std::vector<NodeBase*> vertical_sort(children_.get());
Peter Kasting 2014/05/16 01:41:05 Random thought: scoped_vector.h really ought to de
luken 2014/05/21 20:19:36 It's a good idea. crbug.com/375480 filed. I'll tak
215 std::vector<NodeBase*> horizontal_sort(children_.get());
216 std::sort(vertical_sort.begin(),
217 vertical_sort.end(),
218 &RTreeBase::Node::CompareVertical);
219 std::sort(horizontal_sort.begin(),
220 horizontal_sort.end(),
221 &RTreeBase::Node::CompareHorizontal);
222
223 std::vector<Rect> low_vertical_bounds;
224 std::vector<Rect> low_horizontal_bounds;
225 BuildLowBounds(vertical_sort,
226 horizontal_sort,
227 &low_vertical_bounds,
228 &low_horizontal_bounds);
229
230 std::vector<Rect> high_vertical_bounds;
231 std::vector<Rect> high_horizontal_bounds;
232 BuildHighBounds(vertical_sort,
233 horizontal_sort,
234 &high_vertical_bounds,
235 &high_horizontal_bounds);
236
237 size_t end_index = max_children - min_children;
Peter Kasting 2014/05/16 01:41:05 If we have more children than |max_children|, then
luken 2014/05/21 20:19:36 That's a good point. This code only ever gets call
238 bool is_vertical_split =
239 SmallestMarginSum(min_children,
240 end_index,
241 low_horizontal_bounds,
242 high_horizontal_bounds) <
243 SmallestMarginSum(
244 min_children, end_index, low_vertical_bounds, high_vertical_bounds);
Peter Kasting 2014/05/16 01:41:05 Nit: Wrap and indent both calls the same way.
luken 2014/05/21 20:19:36 Done.
245
246 // Choose split index along chosen axis and perform the split.
247 const Rects& low_bounds(is_vertical_split ? low_vertical_bounds
248 : low_horizontal_bounds);
Peter Kasting 2014/05/16 01:41:05 Nit: This is a clang-format bug; wrap like this in
luken 2014/05/21 20:19:36 Done.
249 const Rects& high_bounds(is_vertical_split ? high_vertical_bounds
250 : high_horizontal_bounds);
251 size_t split_index =
252 ChooseSplitIndex(min_children, max_children, low_bounds, high_bounds);
253
254 const std::vector<NodeBase*>& sort(is_vertical_split ? vertical_sort
255 : horizontal_sort);
256 return DivideChildren(low_bounds, high_bounds, sort, split_index);
257 }
258
259 const int RTreeBase::Node::level() const {
260 return level_;
261 }
262
263 RTreeBase::Node::Node(int level) : NodeBase(Rect(), NULL), level_(level) {
264 }
265
266 // static
267 bool RTreeBase::Node::CompareVertical(NodeBase* a, NodeBase* b) {
268 const Rect& a_rect = a->rect();
269 const Rect& b_rect = b->rect();
270 return (a_rect.y() < b_rect.y()) ||
271 ((a_rect.y() == b_rect.y()) && (a_rect.height() < b_rect.height()));
272 }
273
274 // static
275 bool RTreeBase::Node::CompareHorizontal(NodeBase* a, NodeBase* b) {
276 const Rect& a_rect = a->rect();
277 const Rect& b_rect = b->rect();
278 return (a_rect.x() < b_rect.x()) ||
279 ((a_rect.x() == b_rect.x()) && (a_rect.width() < b_rect.width()));
280 }
281
282 // static
283 bool RTreeBase::Node::CompareCenterDistanceFromParent(NodeBase* a,
284 NodeBase* b) {
285 DCHECK(a->parent());
286 DCHECK_EQ(a->parent(), b->parent());
287
288 const NodeBase* p = a->parent();
Peter Kasting 2014/05/16 01:41:05 Nit: You can put this above the DCHECKs and then u
luken 2014/05/21 20:19:36 Done.
289
290 Vector2d p_center = CenterOfRect(p->rect());
291 Vector2d a_center = CenterOfRect(a->rect());
292 Vector2d b_center = CenterOfRect(b->rect());
293
294 // We don't bother with square roots because we are only comparing the two
295 // values for sorting purposes.
296 return (a_center - p_center).LengthSquared() <
297 (b_center - p_center).LengthSquared();
298 }
299
300 // static
301 void RTreeBase::Node::BuildLowBounds(
302 const std::vector<NodeBase*>& vertical_sort,
303 const std::vector<NodeBase*>& horizontal_sort,
304 std::vector<Rect>* vertical_bounds,
305 std::vector<Rect>* horizontal_bounds) {
306 Rect vertical_bounds_rect;
307 vertical_bounds->reserve(vertical_sort.size());
308 for (std::vector<NodeBase*>::const_iterator i = vertical_sort.begin();
309 i != vertical_sort.end();
310 ++i) {
311 vertical_bounds_rect.Union((*i)->rect());
312 vertical_bounds->push_back(vertical_bounds_rect);
313 }
314
315 Rect horizontal_bounds_rect;
316 horizontal_bounds->reserve(horizontal_sort.size());
317 for (std::vector<NodeBase*>::const_iterator i = horizontal_sort.begin();
318 i != horizontal_sort.end();
319 ++i) {
320 horizontal_bounds_rect.Union((*i)->rect());
321 horizontal_bounds->push_back(horizontal_bounds_rect);
322 }
323 }
324
325 // static
326 void RTreeBase::Node::BuildHighBounds(
327 const std::vector<NodeBase*>& vertical_sort,
328 const std::vector<NodeBase*>& horizontal_sort,
329 std::vector<Rect>* vertical_bounds,
330 std::vector<Rect>* horizontal_bounds) {
331 Rect vertical_bounds_rect;
332 vertical_bounds->reserve(vertical_sort.size());
333 for (std::vector<NodeBase*>::const_reverse_iterator i =
334 vertical_sort.rbegin();
335 i != vertical_sort.rend();
336 ++i) {
337 vertical_bounds_rect.Union((*i)->rect());
338 vertical_bounds->push_back(vertical_bounds_rect);
339 }
340 std::reverse(vertical_bounds->begin(), vertical_bounds->end());
341
342 Rect horizontal_bounds_rect;
343 horizontal_bounds->reserve(horizontal_sort.size());
344 for (std::vector<NodeBase*>::const_reverse_iterator i =
345 horizontal_sort.rbegin();
346 i != horizontal_sort.rend();
347 ++i) {
348 horizontal_bounds_rect.Union((*i)->rect());
349 horizontal_bounds->push_back(horizontal_bounds_rect);
350 }
351 std::reverse(horizontal_bounds->begin(), horizontal_bounds->end());
352 }
353
354 size_t RTreeBase::Node::ChooseSplitIndex(size_t min_children,
355 size_t max_children,
Peter Kasting 2014/05/16 01:41:05 |max_children| is only used to compute the end ind
luken 2014/05/21 20:19:36 Done.
356 const std::vector<Rect>& low_bounds,
357 const std::vector<Rect>& high_bounds) {
358 DCHECK_EQ(low_bounds.size(), high_bounds.size());
359 DCHECK_LT(min_children, low_bounds.size());
360 DCHECK_LT(min_children, max_children - min_children);
361
362 int smallest_overlap_area =
363 UnionRects(low_bounds[min_children], high_bounds[min_children])
364 .size()
365 .GetArea();
Peter Kasting 2014/05/16 01:41:05 Nit: Personally, I'd wrap this as: int smallest
luken 2014/05/21 20:19:36 Done.
366 int smallest_combined_area = low_bounds[min_children].size().GetArea() +
367 high_bounds[min_children].size().GetArea();
Peter Kasting 2014/05/16 01:41:05 Nit: Again, I'd indent this 4, not even.
luken 2014/05/21 20:19:36 Done.
368 size_t optimal_split_index = min_children;
369 // We stop looking for indicides at max_children - min_children to prevent
370 // choosing an index that will result in the second node having less than
371 // |min_children| after the split.
372 for (size_t p = min_children + 1; p < max_children - min_children; ++p) {
373 const int overlap_area =
374 UnionRects(low_bounds[p], high_bounds[p]).size().GetArea();
375 const int combined_area =
376 low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea();
377 if ((overlap_area < smallest_overlap_area) ||
378 ((overlap_area == smallest_overlap_area) &&
379 (combined_area < smallest_combined_area))) {
380 smallest_overlap_area = overlap_area;
381 smallest_combined_area = combined_area;
382 optimal_split_index = p;
383 }
384 }
385
386 // optimal_split_index currently points at the last element in the first set,
387 // so advance it by 1 to point at the first element in the second set.
388 return optimal_split_index + 1;
389 }
390
391 // static
392 int RTreeBase::Node::SmallestMarginSum(size_t start_index,
393 size_t end_index,
394 const Rects& low_bounds,
395 const Rects& high_bounds) {
396 DCHECK_EQ(low_bounds.size(), high_bounds.size());
397 DCHECK_LT(start_index, low_bounds.size());
398 DCHECK_LE(start_index, end_index);
399 DCHECK_LE(end_index, low_bounds.size());
400 std::vector<Rect>::const_iterator i(low_bounds.begin() + start_index);
401 std::vector<Rect>::const_iterator j(high_bounds.begin() + start_index);
402 int smallest_sum = i->width() + i->height() + j->width() + j->height();
403 for (; i != (low_bounds.begin() + end_index); ++i, ++j) {
404 smallest_sum = std::min(
405 smallest_sum, i->width() + i->height() + j->width() + j->height());
406 }
407 return smallest_sum;
408 }
409
410 void RTreeBase::Node::RecomputeLocalBounds() {
411 rect_.SetRect(0, 0, 0, 0);
412 for (size_t i = 0; i < children_.size(); ++i) {
413 rect_.Union(children_[i]->rect());
414 }
415 }
416
417 void RTreeBase::Node::GetAllValues(Records* matches_out) const {
418 for (Nodes::const_iterator i = children_.begin(); i != children_.end(); ++i) {
419 (*i)->GetAllValues(matches_out);
420 }
421 }
422
423 int RTreeBase::Node::OverlapIncreaseToAdd(const Rect& rect,
424 size_t candidate,
425 const Rect& expanded_rect) const {
426 DCHECK_LT(candidate, children_.size());
427 NodeBase* candidate_node = children_[candidate];
Peter Kasting 2014/05/16 01:41:05 Seems like instead of passing in |candidate|, the
luken 2014/05/21 20:19:36 Done.
428
429 // Early-out option for when rect is contained completely within candidate.
Peter Kasting 2014/05/16 01:41:05 Nit: rect -> |rect|, candidate -> the candidate
luken 2014/05/21 20:19:36 Done.
430 if (candidate_node->rect().Contains(rect)) {
431 return 0;
432 }
433
434 int total_original_overlap = 0;
435 int total_expanded_overlap = 0;
436
437 // Now calculate overlap with all other rects in this node.
438 for (size_t i = 0; i < children_.size(); ++i) {
439 // Skip calculating overlap with the candidate rect.
440 if (i == candidate)
441 continue;
442 NodeBase* overlap_node = children_[i];
443 Rect overlap_rect = candidate_node->rect();
Peter Kasting 2014/05/16 01:41:05 Nit: Use IntersectRects() in this loop to simplify
luken 2014/05/21 20:19:36 Done.
444 overlap_rect.Intersect(overlap_node->rect());
445 total_original_overlap += overlap_rect.size().GetArea();
446 Rect expanded_overlap_rect = expanded_rect;
447 expanded_overlap_rect.Intersect(overlap_node->rect());
448 total_expanded_overlap += expanded_overlap_rect.size().GetArea();
449 }
450
451 return total_expanded_overlap - total_original_overlap;
452 }
453
454 RTreeBase::Node* RTreeBase::Node::DivideChildren(
455 const std::vector<Rect>& low_bounds,
456 const std::vector<Rect>& high_bounds,
457 const std::vector<NodeBase*>& sorted_children,
458 size_t split_index) {
459 DCHECK_EQ(low_bounds.size(), high_bounds.size());
460 DCHECK_EQ(low_bounds.size(), sorted_children.size());
461 DCHECK_LT(split_index, low_bounds.size());
462
463 Node* sibling = new Node(level_);
464 sibling->parent_ = parent_;
465 rect_ = low_bounds[split_index - 1];
Peter Kasting 2014/05/16 01:41:05 Looks like this requires an assertion that split_i
luken 2014/05/21 20:19:36 Done.
466 sibling->rect_ = high_bounds[split_index];
467
468 // Our own children_ vector is unsorted, so we wipe it out and divide the
469 // sorted bounds rects between ourselves and our sibling.
470 children_.weak_clear();
471 children_.insert(children_.end(),
472 sorted_children.begin(),
473 sorted_children.begin() + split_index);
474 sibling->children_.insert(sibling->children_.end(),
475 sorted_children.begin() + split_index,
476 sorted_children.end());
477
478 for (size_t i = 0; i < sibling->children_.size(); ++i) {
479 sibling->children_[i]->SetParent(sibling);
480 }
481
482 return sibling;
483 }
484
485 RTreeBase::Node* RTreeBase::Node::LeastOverlapIncrease(
486 const Rect& node_rect,
487 const std::vector<Rect>& expanded_rects) {
488 NodeBase* best_node = children_.front();
489 int least_overlap_increase =
490 OverlapIncreaseToAdd(node_rect, 0, expanded_rects[0]);
491 for (size_t i = 1; i < children_.size(); ++i) {
492 int overlap_increase =
493 OverlapIncreaseToAdd(node_rect, i, expanded_rects[i]);
494 if (overlap_increase < least_overlap_increase) {
495 least_overlap_increase = overlap_increase;
496 best_node = children_[i];
497 } else if (overlap_increase == least_overlap_increase) {
498 // If we are tied at zero there is no possible better overlap increase,
499 // so we can report a tie early.
500 if (overlap_increase == 0)
501 return NULL;
502
503 best_node = NULL;
504 }
505 }
506
507 // Ensure that our children are always Nodes and not Records.
508 DCHECK_GE(level_, 1);
509 return static_cast<Node*>(best_node);
510 }
511
512 RTreeBase::Node* RTreeBase::Node::LeastAreaEnlargement(
513 const Rect& node_rect,
514 const std::vector<Rect>& expanded_rects) {
515 DCHECK(!children_.empty());
516 NodeBase* best_node = children_.front();
517 int least_area_enlargement =
518 expanded_rects[0].size().GetArea() - best_node->rect().size().GetArea();
Peter Kasting 2014/05/16 01:41:05 Seems like we also should have an assertion that |
luken 2014/05/21 20:19:36 Done.
519 for (size_t i = 1; i < children_.size(); ++i) {
520 NodeBase* candidate_node = children_[i];
521 int area_change = expanded_rects[i].size().GetArea() -
522 candidate_node->rect().size().GetArea();
523 DCHECK_GE(area_change, 0);
524 if (area_change < least_area_enlargement) {
525 best_node = candidate_node;
526 least_area_enlargement = area_change;
527 } else if (area_change == least_area_enlargement) {
528 // Ties are broken by choosing the entry with the least area.
529 DCHECK(best_node);
Peter Kasting 2014/05/16 01:41:05 This DCHECK seems unnecessary since |best_node| ne
luken 2014/05/21 20:19:36 Done.
530 if (candidate_node->rect().size().GetArea() <
531 best_node->rect().size().GetArea()) {
532 best_node = candidate_node;
533 }
534 }
535 }
536
537 // Ensure that our children are always Nodes and not Records.
538 DCHECK_GE(level_, 1);
539 return static_cast<Node*>(best_node);
540 }
541
Peter Kasting 2014/05/16 01:41:05 Nit: Two blank lines here, if you're using two bla
luken 2014/05/21 20:19:36 Done.
542 // RTree ----------------------------------------------------------------------
Peter Kasting 2014/05/16 01:41:05 RTreeBase
luken 2014/05/21 20:19:36 Done.
543
544 RTreeBase::RTreeBase(size_t min_children, size_t max_children)
545 : root_(new Node()),
546 min_children_(min_children),
547 max_children_(max_children) {
548 // R-Trees require min_children >= 2
Peter Kasting 2014/05/16 01:41:05 These two comments merely duplicate the code; remo
luken 2014/05/21 20:19:36 Done.
549 DCHECK_GE(min_children_, 2U);
550 // R-Trees also require min_children <= max_children / 2
551 DCHECK_LE(min_children_, max_children_ / 2U);
552 }
553
554 RTreeBase::~RTreeBase() {
555 }
556
557 void RTreeBase::InsertNode(NodeBase* node, int* highest_reinsert_level) {
558 // Find the most appropriate parent to insert node into.
559 Node* parent = root_->ChooseSubtree(node);
560 DCHECK(parent);
561 // Verify ChooseSubtree returned a Node at the correct level.
562 DCHECK_EQ(parent->level(), node->level() + 1);
563 NodeBase* insert_node = node;
564 Node* insert_parent = static_cast<Node*>(parent);
565 NodeBase* needs_bounds_recomputed = insert_parent->parent();
566 ScopedVector<NodeBase> reinserts;
Peter Kasting 2014/05/16 01:41:05 Use Node::Nodes as the type here to match the type
luken 2014/05/21 20:19:36 Done.
567 // Attempt to insert the Node, if this overflows the Node we must handle it.
568 while (insert_parent &&
569 insert_parent->AddChild(scoped_ptr<NodeBase>(insert_node)) >
Peter Kasting 2014/05/16 01:41:05 Nit: Consider using make_scoped_ptr(insert_node) t
luken 2014/05/21 20:19:36 Done.
570 max_children_) {
571 // If we have yet to re-insert nodes at this level during this data insert,
572 // and we're not at the root, R*-Tree calls for re-insertion of some of the
573 // nodes, resulting in a better balance on the tree.
574 if (insert_parent->parent() &&
575 insert_parent->level() > *highest_reinsert_level) {
576 insert_parent->RemoveNodesForReinsert(max_children_ / 3, &reinserts);
577 // Adjust highest_reinsert_level to this level.
578 *highest_reinsert_level = insert_parent->level();
579 // We didn't create any new nodes so we have nothing new to insert.
580 insert_node = NULL;
581 // RemoveNodesForReinsert() does not recompute bounds, so mark it.
582 needs_bounds_recomputed = insert_parent;
583 break;
584 }
585
586 // Split() will create a sibling to insert_parent both of which will have
587 // valid bounds, but this invalidates their parent's bounds.
588 insert_node = insert_parent->Split(min_children_, max_children_);
589 insert_parent = static_cast<Node*>(insert_parent->parent());
590 needs_bounds_recomputed = insert_parent;
591 }
592
593 // If we have a Node to insert, and we hit the root of the current tree,
594 // we create a new root which is the parent of the current root and the
595 // insert_node
Peter Kasting 2014/05/16 01:41:05 Nit: Trailing period.
luken 2014/05/21 20:19:36 Done.
596 if (!insert_parent && insert_node) {
597 Node* old_root = root_.release();
598 root_ = old_root->MakeParent();
Peter Kasting 2014/05/16 01:41:05 Nit: Could just be root_ = root_.release()->M
luken 2014/05/21 20:19:36 Done.
599 root_->AddChild(scoped_ptr<NodeBase>(insert_node));
600 }
601
602 // Recompute bounds along insertion path.
603 if (needs_bounds_recomputed) {
604 needs_bounds_recomputed->RecomputeBoundsUpToRoot();
605 }
606
607 // Complete re-inserts, if any.
608 for (size_t i = 0; i < reinserts.size(); ++i) {
Peter Kasting 2014/05/16 01:41:05 Nit: Prefer iterators to indexes where possible.
luken 2014/05/21 20:19:36 Done.
609 InsertNode(reinserts[i], highest_reinsert_level);
610 }
611
612 // Clear out reinserts without deleting any of the children, as they have been
613 // re-inserted into the tree.
614 reinserts.weak_clear();
615 }
616
617 void RTreeBase::RemoveNode(NodeBase* node) {
618 // We need to remove this node from its parent.
619 Node* parent = static_cast<Node*>(node->parent());
620 // Record nodes are never allowed as the root, so we should always have a
621 // parent.
622 DCHECK(parent);
623 // Should always be a leaf that had the record.
624 DCHECK_EQ(parent->level(), 0);
Peter Kasting 2014/05/16 01:41:05 Nit: (expected, actual)
luken 2014/05/21 20:19:36 Done.
625 ScopedVector<NodeBase> orphans;
626 NodeBase* child = node;
627
628 // Traverse up the tree, removing the child from each parent and deleting
629 // parent nodes, until we either encounter the root of the tree or a parent
630 // that still has sufficient children.
631 while (parent) {
632 size_t children_remaining = parent->RemoveChild(child, &orphans);
633 if (child != node)
634 delete child;
635
636 if (children_remaining >= min_children_)
637 break;
638
639 child = parent;
640 parent = static_cast<Node*>(parent->parent());
641 }
642
643 // If we stopped deleting nodes up the tree before encountering the root,
644 // we'll need to fix up the bounds from the first parent we didn't delete
645 // up to the root.
646 if (parent) {
647 parent->RecomputeBoundsUpToRoot();
648 }
649
650 // Now re-insert each of the orphaned nodes back into the tree.
651 for (size_t i = 0; i < orphans.size(); ++i) {
652 int starting_level = -1;
653 InsertNode(orphans[i], &starting_level);
654 }
655
656 // Clear out the orphans list without deleting any of the children, as they
657 // have been re-inserted into the tree.
658 orphans.weak_clear();
659 }
660
661 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698