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 |