OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/geometry/r_tree.h" | 5 #include "ui/gfx/geometry/r_tree.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 | 11 |
12 namespace { | 12 namespace { |
Peter Kasting
2014/05/02 18:04:57
Nit: Totally optional, but in files that include d
luken
2014/05/08 00:00:08
Done.
| |
13 | 13 |
14 // Returns the center coordinates of the given rectangle. | 14 // Returns the center coordinates of the given rectangle. |
Peter Kasting
2014/05/02 18:04:57
Nit: Comment not necessary (we can tell this from
luken
2014/05/08 00:00:08
Done.
| |
15 gfx::Vector2d CenterOfRect(const gfx::Rect& rect) { | 15 gfx::Vector2d CenterOfRect(const gfx::Rect& rect) { |
Peter Kasting
2014/05/02 18:04:57
It seems odd that this returns a vector instead of
luken
2014/05/08 00:00:08
Done.
| |
16 return rect.OffsetFromOrigin() + | 16 return rect.OffsetFromOrigin() + |
17 gfx::Vector2d(rect.width() / 2, rect.height() / 2); | 17 gfx::Vector2d(rect.width() / 2, rect.height() / 2); |
18 } | 18 } |
19 | |
19 } | 20 } |
20 | 21 |
21 namespace gfx { | 22 namespace gfx { |
22 | 23 |
23 RTree::Node::Node(int level) : level_(level), parent_(NULL), key_(0) { | 24 RTree::Node::Node(int level) : level_(level), parent_(NULL), key_(0) { |
24 } | 25 } |
25 | 26 |
26 RTree::Node::Node(const Rect& rect, intptr_t key) | 27 RTree::Node::Node(const Rect& rect, intptr_t key) |
27 : rect_(rect), level_(-1), parent_(NULL), key_(key) { | 28 : rect_(rect), level_(-1), parent_(NULL), key_(key) { |
Peter Kasting
2014/05/02 18:04:57
From http://google-styleguide.googlecode.com/svn/t
luken
2014/05/08 00:00:08
clang format wants to move them all back to one li
| |
28 } | 29 } |
29 | 30 |
30 RTree::Node::~Node() { | 31 RTree::Node::~Node() { |
31 Clear(); | 32 Clear(); |
32 } | 33 } |
33 | 34 |
34 void RTree::Node::Clear() { | 35 void RTree::Node::Clear() { |
35 // Iterate through children and delete them all. | 36 // Iterate through children and delete them all. |
Peter Kasting
2014/05/02 18:04:57
Documenting what ScopedVector::clear() does doesn'
luken
2014/05/08 00:00:08
Done.
| |
36 children_.clear(); | 37 children_.clear(); |
37 key_ = 0; | 38 key_ = 0; |
38 } | 39 } |
39 | 40 |
40 void RTree::Node::Query(const Rect& query_rect, | 41 void RTree::Node::Query(const Rect& query_rect, |
41 base::hash_set<intptr_t>* matches_out) const { | 42 base::hash_set<intptr_t>* matches_out) const { |
Peter Kasting
2014/05/02 18:04:57
You should probably add to the comment in the head
luken
2014/05/08 00:00:08
Done.
| |
42 // Check own bounding box for intersection, can cull all children if no | 43 // Check own bounding box for intersection, can cull all children if no |
43 // intersection. | 44 // intersection. |
44 if (!rect_.Intersects(query_rect)) { | 45 if (!rect_.Intersects(query_rect)) { |
Peter Kasting
2014/05/02 18:04:57
This style is legal, but in Chrome code we normall
luken
2014/05/08 00:00:08
Done.
| |
45 return; | 46 return; |
46 } | 47 } |
47 | 48 |
48 // Conversely if we are completely contained within the query rect we can | 49 // Conversely if we are completely contained within the query rect we can |
49 // confidently skip all bounds checks for ourselves and all our children. | 50 // confidently skip all bounds checks for ourselves and all our children. |
50 if (query_rect.Contains(rect_)) { | 51 if (query_rect.Contains(rect_)) { |
51 GetAllValues(matches_out); | 52 GetAllValues(matches_out); |
52 return; | 53 return; |
53 } | 54 } |
54 | 55 |
55 // We intersect the query rect but we are not are not contained within it. | 56 // We intersect the query rect but we are not are not contained within it. |
56 // If we are a record node, then add our record value. Otherwise we must | 57 // If we are a record node, then add our record value. Otherwise we must |
57 // query each of our children in turn. | 58 // query each of our children in turn. |
58 if (key_) { | 59 if (key_) { |
59 DCHECK_EQ(level_, -1); | 60 DCHECK_EQ(level_, -1); |
Peter Kasting
2014/05/02 18:04:57
Nit: (expected, actual) for DCHECK_EQ and DCHECK_N
luken
2014/05/08 00:00:08
I will remove needless DCHECKs and fix ordering on
| |
60 matches_out->insert(key_); | 61 matches_out->insert(key_); |
61 } else { | 62 } else { |
62 for (size_t i = 0; i < children_.size(); ++i) { | 63 for (size_t i = 0; i < children_.size(); ++i) { |
Peter Kasting
2014/05/02 18:04:57
Prefer using iterators over indexes (primarily in
luken
2014/05/08 00:00:08
Done.
| |
63 // Sanity-check our children. | 64 // Sanity-check our children. |
64 Node* node = children_[i]; | 65 Node* node = children_[i]; |
Peter Kasting
2014/05/02 18:04:57
This really should be a const Node* (or, if using
luken
2014/05/08 00:00:08
Done.
| |
65 DCHECK_EQ(node->parent_, this); | 66 DCHECK_EQ(node->parent_, this); |
66 DCHECK_EQ(level_ - 1, node->level_); | 67 DCHECK_EQ(level_ - 1, node->level_); |
Peter Kasting
2014/05/02 18:04:57
Again, these first two checks don't seem to have a
luken
2014/05/08 00:00:08
Done.
| |
67 DCHECK(rect_.Contains(node->rect_)); | 68 DCHECK(rect_.Contains(node->rect_)); |
68 node->Query(query_rect, matches_out); | 69 node->Query(query_rect, matches_out); |
69 } | 70 } |
70 } | 71 } |
71 } | 72 } |
72 | 73 |
73 void RTree::Node::RecomputeBounds() { | 74 void RTree::Node::RecomputeBounds() { |
74 RecomputeBoundsNoParents(); | 75 RecomputeBoundsNoParents(); |
75 // Recompute our parent's bounds recursively up to the root. | 76 // Recompute our parent's bounds recursively up to the root. |
76 if (parent_) { | 77 if (parent_) { |
77 parent_->RecomputeBounds(); | 78 parent_->RecomputeBounds(); |
78 } | 79 } |
79 } | 80 } |
80 | 81 |
81 void RTree::Node::RemoveNodesForReinsert(size_t number_to_remove, | 82 void RTree::Node::RemoveNodesForReinsert(size_t number_to_remove, |
82 ScopedVector<Node>* nodes) { | 83 ScopedVector<Node>* nodes) { |
83 DCHECK_GE(children_.size(), number_to_remove); | 84 DCHECK_GE(children_.size(), number_to_remove); |
Peter Kasting
2014/05/02 18:04:57
For DCHECK_GE() and similar, write in "natural" or
luken
2014/05/08 00:00:08
Done.
| |
84 | 85 |
85 // Sort our children by their distance from the center of their rectangles to | 86 // Sort our children by their distance from the center of their rectangles to |
86 // the center of our bounding rectangle. | 87 // the center of our bounding rectangle. |
Peter Kasting
2014/05/02 18:04:57
Nit: This comment (and others below, see subsequen
luken
2014/05/08 00:00:08
Done.
| |
87 std::sort(children_.begin(), | 88 std::sort(children_.begin(), |
88 children_.end(), | 89 children_.end(), |
89 &RTree::Node::CompareCenterDistanceFromParent); | 90 &RTree::Node::CompareCenterDistanceFromParent); |
90 | 91 |
91 // Add lowest distance nodes from our children list to the returned vector. | 92 // Add lowest distance nodes from our children list to the returned vector. |
Peter Kasting
2014/05/02 18:04:57
Nit: If you say "Move the lowest-distance children
luken
2014/05/08 00:00:08
Done.
| |
92 nodes->insert( | 93 nodes->insert( |
93 nodes->end(), children_.begin(), children_.begin() + number_to_remove); | 94 nodes->end(), children_.begin(), children_.begin() + number_to_remove); |
Peter Kasting
2014/05/02 18:04:57
Nit: This is clang-format's preferred formatting h
luken
2014/05/08 00:00:08
Done.
| |
94 // Remove those same nodes from our list, without deleting them. | 95 // Remove those same nodes from our list, without deleting them. |
95 children_.weak_erase(children_.begin(), children_.begin() + number_to_remove); | 96 children_.weak_erase(children_.begin(), children_.begin() + number_to_remove); |
96 } | 97 } |
97 | 98 |
98 size_t RTree::Node::RemoveChild(Node* child_node, ScopedVector<Node>* orphans) { | 99 size_t RTree::Node::RemoveChild(Node* child_node, ScopedVector<Node>* orphans) { |
99 // Should actually be one of our children. | 100 // Should actually be one of our children. |
100 DCHECK_EQ(child_node->parent_, this); | 101 DCHECK_EQ(child_node->parent_, this); |
101 | 102 |
102 // Add children of child_node to the orphans vector. | 103 // Add children of child_node to the orphans vector. |
Peter Kasting
2014/05/02 18:04:57
Nit: Same comments as above... I won't make notes
luken
2014/05/08 00:00:08
Done.
| |
103 orphans->insert(orphans->end(), | 104 orphans->insert(orphans->end(), |
104 child_node->children_.begin(), | 105 child_node->children_.begin(), |
105 child_node->children_.end()); | 106 child_node->children_.end()); |
106 // Remove without deletion those children from the child_node vector. | 107 // Remove without deletion those children from the child_node vector. |
107 child_node->children_.weak_clear(); | 108 child_node->children_.weak_clear(); |
108 | 109 |
109 // Find an iterator to this Node in our own children_ vector. | 110 // Find an iterator to this Node in our own children_ vector. |
110 ScopedVector<Node>::iterator child_it = children_.end(); | 111 ScopedVector<Node>::iterator child_it = children_.end(); |
111 for (size_t i = 0; i < children_.size(); ++i) { | 112 for (size_t i = 0; i < children_.size(); ++i) { |
112 if (children_[i] == child_node) { | 113 if (children_[i] == child_node) { |
113 child_it = children_.begin() + i; | 114 child_it = children_.begin() + i; |
Peter Kasting
2014/05/02 18:04:57
Nit: Again, using an iterator for the loop above w
luken
2014/05/08 00:00:08
Done.
| |
114 break; | 115 break; |
115 } | 116 } |
116 } | 117 } |
117 // Should have found the pointer in our children_ vector. | 118 // Should have found the pointer in our children_ vector. |
118 DCHECK(child_it != children_.end()); | 119 DCHECK(child_it != children_.end()); |
119 // Remove without deleting the child node from our children_ vector. | 120 // Remove without deleting the child node from our children_ vector. |
120 children_.weak_erase(child_it); | 121 children_.weak_erase(child_it); |
121 | 122 |
122 return children_.size(); | 123 return children_.size(); |
123 } | 124 } |
124 | 125 |
125 scoped_ptr<RTree::Node> RTree::Node::RemoveAndReturnLastChild() { | 126 scoped_ptr<RTree::Node> RTree::Node::RemoveAndReturnLastChild() { |
126 if (!children_.size()) | 127 if (!children_.size()) |
Peter Kasting
2014/05/02 18:04:57
Use empty() instead of !size().
luken
2014/05/08 00:00:08
Done.
| |
127 return scoped_ptr<Node>(); | 128 return scoped_ptr<Node>(); |
128 | 129 |
129 scoped_ptr<Node> last_child(children_[children_.size() - 1]); | 130 scoped_ptr<Node> last_child(children_[children_.size() - 1]); |
Peter Kasting
2014/05/02 18:04:57
Use .back() instead of [children_.size() - 1].
luken
2014/05/08 00:00:08
Done.
| |
130 DCHECK_EQ(last_child->parent_, this); | 131 DCHECK_EQ(last_child->parent_, this); |
Peter Kasting
2014/05/02 18:04:57
This DCHECK is arguable -- at least it's not total
luken
2014/05/08 00:00:08
Done.
| |
131 children_.weak_erase(children_.begin() + children_.size() - 1); | 132 children_.weak_erase(children_.begin() + children_.size() - 1); |
Peter Kasting
2014/05/02 18:04:57
Use children_.end() - 1 instead of children_.begin
luken
2014/05/08 00:00:08
Done.
| |
132 // Invalidate parent, as this child may even become the new root. | 133 // Invalidate parent, as this child may even become the new root. |
Peter Kasting
2014/05/02 18:04:57
I'd have expected the |parent_| field to get clear
luken
2014/05/08 00:00:08
Done.
| |
133 last_child->parent_ = NULL; | 134 last_child->parent_ = NULL; |
134 return last_child.Pass(); | 135 return last_child.Pass(); |
135 } | 136 } |
136 | 137 |
137 // Uses the R*-Tree algorithm CHOOSELEAF proposed by Beckmann et al. | 138 // Uses the R*-Tree algorithm CHOOSELEAF proposed by Beckmann et al. |
138 RTree::Node* RTree::Node::ChooseSubtree(Node* node) { | 139 RTree::Node* RTree::Node::ChooseSubtree(Node* node) { |
139 // Should never be called on a record node. | 140 // Should never be called on a record node. |
140 DCHECK(!key_); | 141 DCHECK(!key_); |
Peter Kasting
2014/05/02 18:04:57
The second DCHECK seems sufficient. This method d
luken
2014/05/08 00:00:08
Done.
| |
141 DCHECK(level_ >= 0); | 142 DCHECK(level_ >= 0); |
Peter Kasting
2014/05/02 18:04:57
DCHECK_GE
luken
2014/05/08 00:00:08
Done.
| |
142 DCHECK(node); | 143 DCHECK(node); |
Peter Kasting
2014/05/02 18:04:57
Nit: Consider putting this DCHECK above the commen
luken
2014/05/08 00:00:08
Done.
| |
143 | 144 |
144 // If we are a parent of nodes on the provided node level, we are done. | 145 // If we are a parent of nodes on the provided node level, we are done. |
Peter Kasting
2014/05/02 18:04:57
What if we're _at_ the node's level, or below it?
luken
2014/05/08 00:00:08
It does, I corrected the DCHECK above to account,
| |
145 if (level_ == node->level_ + 1) | 146 if (level_ == node->level_ + 1) |
146 return this; | 147 return this; |
147 | 148 |
148 // We are an internal node, and thus guaranteed to have children. | 149 // We are an internal node, and thus guaranteed to have children. |
149 DCHECK_GT(children_.size(), 0U); | 150 DCHECK_GT(children_.size(), 0U); |
Peter Kasting
2014/05/02 18:04:57
Use !empty(). But really, I don't see how this fu
luken
2014/05/08 00:00:08
Done.
| |
150 | 151 |
151 // Iterate over all children to find best candidate for insertion. | 152 // Iterate over all children to find best candidate for insertion. |
Peter Kasting
2014/05/02 18:04:57
This method doesn't iterate, so this comment doesn
luken
2014/05/08 00:00:08
Done.
| |
152 Node* best_candidate = NULL; | 153 Node* best_candidate = NULL; |
Peter Kasting
2014/05/02 18:04:57
From http://google-styleguide.googlecode.com/svn/t
luken
2014/05/08 00:00:08
Done.
| |
153 | 154 |
154 // Precompute a vector of expanded rects, used both by LeastOverlapIncrease | 155 // Precompute a vector of expanded rects, used both by LeastOverlapIncrease |
155 // and LeastAreaEnlargement. | 156 // and LeastAreaEnlargement. |
156 std::vector<Rect> expanded_rects; | 157 std::vector<Rect> expanded_rects; |
157 expanded_rects.reserve(children_.size()); | 158 expanded_rects.reserve(children_.size()); |
158 for (size_t i = 0; i < children_.size(); ++i) { | 159 for (size_t i = 0; i < children_.size(); ++i) { |
159 Rect expanded_rect(node->rect_); | 160 Rect expanded_rect(node->rect_); |
160 expanded_rect.Union(children_[i]->rect_); | 161 expanded_rect.Union(children_[i]->rect_); |
161 expanded_rects.push_back(expanded_rect); | 162 expanded_rects.push_back(expanded_rect); |
Peter Kasting
2014/05/02 18:04:57
This can be simplified using the helpers in ui/gfx
luken
2014/05/08 00:00:08
Done.
| |
162 } | 163 } |
163 | 164 |
164 // For parents of leaf nodes, we pick the node that will cause the least | 165 // For parents of leaf nodes, we pick the node that will cause the least |
165 // increase in overlap by the addition of this new node. This may detect a | 166 // increase in overlap by the addition of this new node. This may detect a |
166 // tie, in which case it will return NULL. | 167 // tie, in which case it will return NULL. |
167 if (level_ == 1) | 168 if (level_ == 1) |
168 best_candidate = LeastOverlapIncrease(node->rect_, expanded_rects); | 169 best_candidate = LeastOverlapIncrease(node->rect_, expanded_rects); |
169 | 170 |
170 // For non-parents of leaf nodes, or for parents of leaf nodes with ties in | 171 // For non-parents of leaf nodes, or for parents of leaf nodes with ties in |
171 // overlap increase, we choose the subtree with least area enlargement caused | 172 // overlap increase, we choose the subtree with least area enlargement caused |
172 // by the addition of the new node. | 173 // by the addition of the new node. |
173 if (!best_candidate) | 174 if (!best_candidate) |
174 best_candidate = LeastAreaEnlargement(node->rect_, expanded_rects); | 175 best_candidate = LeastAreaEnlargement(node->rect_, expanded_rects); |
175 | 176 |
176 DCHECK(best_candidate); | 177 DCHECK(best_candidate); |
177 return best_candidate->ChooseSubtree(node); | 178 return best_candidate->ChooseSubtree(node); |
178 } | 179 } |
179 | 180 |
180 RTree::Node* RTree::Node::LeastAreaEnlargement( | 181 RTree::Node* RTree::Node::LeastAreaEnlargement( |
Peter Kasting
2014/05/02 18:04:57
Keep .cc function definition order the same as the
| |
181 const Rect& node_rect, | 182 const Rect& node_rect, |
182 const std::vector<Rect>& expanded_rects) { | 183 const std::vector<Rect>& expanded_rects) { |
183 Node* best_node = NULL; | 184 Node* best_node = NULL; |
184 int least_area_enlargement = std::numeric_limits<int>::max(); | 185 int least_area_enlargement = std::numeric_limits<int>::max(); |
Peter Kasting
2014/05/02 18:04:57
Nit: I suggest this:
Node* best_node = children
luken
2014/05/08 00:00:08
I got rid of the INT_MAX. I'd prefer to keep with
Peter Kasting
2014/05/08 18:08:21
Ah, sorry, I think I missed that. Using an index
luken
2014/05/14 00:12:04
Done.
| |
185 for (size_t i = 0; i < children_.size(); ++i) { | 186 for (size_t i = 0; i < children_.size(); ++i) { |
186 Node* candidate_node = children_[i]; | 187 Node* candidate_node = children_[i]; |
187 int area_change = expanded_rects[i].size().GetArea() - | 188 int area_change = expanded_rects[i].size().GetArea() - |
Peter Kasting
2014/05/02 18:04:57
Can area change be negative? (I assume not.) May
luken
2014/05/08 00:00:08
You are correct, by definition of Union area chang
| |
188 candidate_node->rect_.size().GetArea(); | 189 candidate_node->rect_.size().GetArea(); |
Peter Kasting
2014/05/02 18:04:57
Nit: I believe this should be indented 4 rather th
luken
2014/05/08 00:00:08
Done.
| |
189 if (area_change < least_area_enlargement) { | 190 if (area_change < least_area_enlargement) { |
190 best_node = candidate_node; | 191 best_node = candidate_node; |
191 least_area_enlargement = area_change; | 192 least_area_enlargement = area_change; |
192 } else if (area_change == least_area_enlargement) { | 193 } else if (area_change == least_area_enlargement) { |
193 // Ties are broken by choosing entry with least area. | 194 // Ties are broken by choosing entry with least area. |
Peter Kasting
2014/05/02 18:04:57
Nit Add articles ("the" two places)
luken
2014/05/08 00:00:08
Done.
| |
194 DCHECK(best_node); | 195 DCHECK(best_node); |
195 if (candidate_node->rect_.size().GetArea() < | 196 if (candidate_node->rect_.size().GetArea() < |
196 best_node->rect_.size().GetArea()) { | 197 best_node->rect_.size().GetArea()) { |
197 best_node = candidate_node; | 198 best_node = candidate_node; |
198 } | 199 } |
199 } | 200 } |
200 } | 201 } |
201 | 202 |
202 DCHECK(best_node); | 203 DCHECK(best_node); |
Peter Kasting
2014/05/02 18:04:57
If |children_| is empty, we'll fail this. It seem
luken
2014/05/08 00:00:08
Done.
| |
203 return best_node; | 204 return best_node; |
204 } | 205 } |
205 | 206 |
206 RTree::Node* RTree::Node::LeastOverlapIncrease( | 207 RTree::Node* RTree::Node::LeastOverlapIncrease( |
207 const Rect& node_rect, | 208 const Rect& node_rect, |
208 const std::vector<Rect>& expanded_rects) { | 209 const std::vector<Rect>& expanded_rects) { |
209 Node* best_node = NULL; | 210 Node* best_node = NULL; |
210 bool has_tied_node = false; | 211 bool has_tied_node = false; |
Peter Kasting
2014/05/02 18:04:57
You don't actually need this if you follow the sam
luken
2014/05/08 00:00:08
Done.
| |
211 int least_overlap_increase = std::numeric_limits<int>::max(); | 212 int least_overlap_increase = std::numeric_limits<int>::max(); |
212 for (size_t i = 0; i < children_.size(); ++i) { | 213 for (size_t i = 0; i < children_.size(); ++i) { |
213 int overlap_increase = | 214 int overlap_increase = |
214 OverlapIncreaseToAdd(node_rect, i, expanded_rects[i]); | 215 OverlapIncreaseToAdd(node_rect, i, expanded_rects[i]); |
215 if (overlap_increase < least_overlap_increase) { | 216 if (overlap_increase < least_overlap_increase) { |
216 least_overlap_increase = overlap_increase; | 217 least_overlap_increase = overlap_increase; |
217 best_node = children_[i]; | 218 best_node = children_[i]; |
218 has_tied_node = false; | 219 has_tied_node = false; |
219 } else if (overlap_increase == least_overlap_increase) { | 220 } else if (overlap_increase == least_overlap_increase) { |
220 has_tied_node = true; | 221 has_tied_node = true; |
Peter Kasting
2014/05/02 18:04:57
Nit: This can go below the conditional (more effic
luken
2014/05/08 00:00:08
Done.
| |
221 // If we are tied at zero there is no possible better overlap increase, | 222 // If we are tied at zero there is no possible better overlap increase, |
222 // so we can report a tie early. | 223 // so we can report a tie early. |
223 if (overlap_increase == 0) { | 224 if (overlap_increase == 0) { |
224 return NULL; | 225 return NULL; |
225 } | 226 } |
226 } | 227 } |
227 } | 228 } |
228 | 229 |
229 // If we ended up with a tie return NULL to report it. | 230 // If we ended up with a tie return NULL to report it. |
230 if (has_tied_node) | 231 if (has_tied_node) |
231 return NULL; | 232 return NULL; |
232 | 233 |
233 return best_node; | 234 return best_node; |
234 } | 235 } |
235 | 236 |
236 int RTree::Node::OverlapIncreaseToAdd(const Rect& rect, | 237 int RTree::Node::OverlapIncreaseToAdd(const Rect& rect, |
237 size_t candidate, | 238 size_t candidate, |
238 const Rect& expanded_rect) { | 239 const Rect& expanded_rect) { |
239 Node* candidate_node = children_[candidate]; | 240 Node* candidate_node = children_[candidate]; |
Peter Kasting
2014/05/02 18:04:57
This definitely deserves a DCHECK that |candidate|
luken
2014/05/08 00:00:08
Done.
| |
240 | 241 |
241 // Early-out option for when rect is contained completely within candidate. | 242 // Early-out option for when rect is contained completely within candidate. |
242 if (candidate_node->rect_.Contains(rect)) { | 243 if (candidate_node->rect_.Contains(rect)) { |
243 return 0; | 244 return 0; |
244 } | 245 } |
245 | 246 |
246 int total_original_overlap = 0; | 247 int total_original_overlap = 0; |
247 int total_expanded_overlap = 0; | 248 int total_expanded_overlap = 0; |
248 | 249 |
249 // Now calculate overlap with all other rects in this node. | 250 // Now calculate overlap with all other rects in this node. |
250 for (size_t i = 0; i < children_.size(); ++i) { | 251 for (size_t i = 0; i < children_.size(); ++i) { |
251 // Skip calculating overlap with the candidate rect. | 252 // Skip calculating overlap with the candidate rect. |
252 if (i == candidate) | 253 if (i == candidate) |
253 continue; | 254 continue; |
254 Node* overlap_node = children_[i]; | 255 Node* overlap_node = children_[i]; |
255 Rect overlap_rect = candidate_node->rect_; | 256 Rect overlap_rect = candidate_node->rect_; |
256 overlap_rect.Intersect(overlap_node->rect_); | 257 overlap_rect.Intersect(overlap_node->rect_); |
257 total_original_overlap += overlap_rect.size().GetArea(); | 258 total_original_overlap += overlap_rect.size().GetArea(); |
258 Rect expanded_overlap_rect = expanded_rect; | 259 Rect expanded_overlap_rect = expanded_rect; |
259 expanded_overlap_rect.Intersect(overlap_node->rect_); | 260 expanded_overlap_rect.Intersect(overlap_node->rect_); |
260 total_expanded_overlap += expanded_overlap_rect.size().GetArea(); | 261 total_expanded_overlap += expanded_overlap_rect.size().GetArea(); |
261 } | 262 } |
262 | 263 |
263 // Compare this overlap increase with best one to date, update best. | 264 // Compare this overlap increase with best one to date, update best. |
Peter Kasting
2014/05/02 18:04:57
This comment doesn't seem to be describing the cod
luken
2014/05/08 00:00:08
Done.
| |
264 int overlap_increase = total_expanded_overlap - total_original_overlap; | 265 int overlap_increase = total_expanded_overlap - total_original_overlap; |
Peter Kasting
2014/05/02 18:04:57
Nit: Just return this directly, don't create a tem
luken
2014/05/14 00:12:04
Done.
| |
265 return overlap_increase; | 266 return overlap_increase; |
266 } | 267 } |
267 | 268 |
268 size_t RTree::Node::AddChild(Node* node) { | 269 size_t RTree::Node::AddChild(Node* node) { |
269 DCHECK(node); | 270 DCHECK(node); |
270 // Sanity-check that the level of the child being added is one more than ours. | 271 // Sanity-check that the level of the child being added is one more than ours. |
Peter Kasting
2014/05/02 18:04:57
It's actually one less.
luken
2014/05/08 00:00:08
Done.
| |
271 DCHECK_EQ(level_ - 1, node->level_); | 272 DCHECK_EQ(level_ - 1, node->level_); |
272 node->parent_ = this; | 273 node->parent_ = this; |
273 children_.push_back(node); | 274 children_.push_back(node); |
274 rect_.Union(node->rect_); | 275 rect_.Union(node->rect_); |
275 return children_.size(); | 276 return children_.size(); |
276 } | 277 } |
277 | 278 |
278 RTree::Node* RTree::Node::Split(size_t min_children, size_t max_children) { | 279 RTree::Node* RTree::Node::Split(size_t min_children, size_t max_children) { |
279 // Please don't attempt to split a record Node. | 280 // Please don't attempt to split a record Node. |
Peter Kasting
2014/05/02 18:04:57
Since record nodes have no children, this DCHECK i
luken
2014/05/08 00:00:08
Done.
| |
280 DCHECK(!key_); | 281 DCHECK(!key_); |
281 // We should have too many children to begin with. | 282 // We should have too many children to begin with. |
282 DCHECK_GT(children_.size(), max_children); | 283 DCHECK_GT(children_.size(), max_children); |
283 // First determine if splitting along the horizontal or vertical axis. We | 284 // First determine if splitting along the horizontal or vertical axis. We |
Peter Kasting
2014/05/02 18:04:57
Nit: splitting -> we should split
luken
2014/05/08 00:00:08
Done.
| |
284 // sort the rectangles of our children by lower then upper values along both | 285 // sort the rectangles of our children by lower then upper values along both |
285 // horizontal and vertical axes. | 286 // horizontal and vertical axes. |
286 std::vector<Node*> vertical_sort(children_.get()); | 287 std::vector<Node*> vertical_sort(children_.get()); |
287 std::vector<Node*> horizontal_sort(children_.get()); | 288 std::vector<Node*> horizontal_sort(children_.get()); |
288 std::sort(vertical_sort.begin(), | 289 std::sort(vertical_sort.begin(), |
289 vertical_sort.end(), | 290 vertical_sort.end(), |
290 &RTree::Node::CompareVertical); | 291 &RTree::Node::CompareVertical); |
291 std::sort(horizontal_sort.begin(), | 292 std::sort(horizontal_sort.begin(), |
292 horizontal_sort.end(), | 293 horizontal_sort.end(), |
293 &RTree::Node::CompareHorizontal); | 294 &RTree::Node::CompareHorizontal); |
294 | 295 |
295 // We will be examining the bounding boxes of different splits of our children | 296 // We will be examining the bounding boxes of different splits of our children |
296 // sorted along each axis. Here we precompute the bounding boxes of these | 297 // sorted along each axis. Here we precompute the bounding boxes of these |
297 // distributions. For the low bounds the ith element can be considered the | 298 // distributions. For the low bounds the ith element can be considered the |
298 // union of all rects [0,i] in the relevant sorted axis array. | 299 // union of all rects [0,i] in the relevant sorted axis array. |
Peter Kasting
2014/05/02 18:04:57
Nit: Try to avoid duplicating commentary here and
luken
2014/05/08 00:00:08
Done.
| |
299 std::vector<Rect> low_vertical_bounds; | 300 std::vector<Rect> low_vertical_bounds; |
300 std::vector<Rect> low_horizontal_bounds; | 301 std::vector<Rect> low_horizontal_bounds; |
301 BuildLowBounds(vertical_sort, | 302 BuildLowBounds(vertical_sort, |
302 horizontal_sort, | 303 horizontal_sort, |
303 &low_vertical_bounds, | 304 &low_vertical_bounds, |
304 &low_horizontal_bounds); | 305 &low_horizontal_bounds); |
305 | 306 |
306 // For the high bounds the ith element can be considered the union of all | 307 // For the high bounds the ith element can be considered the union of all |
307 // rects [i, children_.size()) in the relevant sorted axis array. | 308 // rects [i, children_.size()) in the relevant sorted axis array. |
308 std::vector<Rect> high_vertical_bounds; | 309 std::vector<Rect> high_vertical_bounds; |
(...skipping 19 matching lines...) Expand all Loading... | |
328 low_vertical_bounds, high_vertical_bounds, vertical_sort, split_index); | 329 low_vertical_bounds, high_vertical_bounds, vertical_sort, split_index); |
329 } else { | 330 } else { |
330 size_t split_index = ChooseSplitIndex(min_children, | 331 size_t split_index = ChooseSplitIndex(min_children, |
331 max_children, | 332 max_children, |
332 low_horizontal_bounds, | 333 low_horizontal_bounds, |
333 high_horizontal_bounds); | 334 high_horizontal_bounds); |
334 sibling = DivideChildren(low_horizontal_bounds, | 335 sibling = DivideChildren(low_horizontal_bounds, |
335 high_horizontal_bounds, | 336 high_horizontal_bounds, |
336 horizontal_sort, | 337 horizontal_sort, |
337 split_index); | 338 split_index); |
338 } | 339 } |
Peter Kasting
2014/05/02 18:04:57
I suggest the alternate formulation below.
Not on
luken
2014/05/08 00:00:08
Done.
| |
339 | 340 |
340 return sibling; | 341 return sibling; |
341 } | 342 } |
342 | 343 |
343 // static | 344 // static |
344 void RTree::Node::BuildLowBounds(const std::vector<Node*>& vertical_sort, | 345 void RTree::Node::BuildLowBounds(const std::vector<Node*>& vertical_sort, |
345 const std::vector<Node*>& horizontal_sort, | 346 const std::vector<Node*>& horizontal_sort, |
346 std::vector<Rect>* vertical_bounds, | 347 std::vector<Rect>* vertical_bounds, |
347 std::vector<Rect>* horizontal_bounds) { | 348 std::vector<Rect>* horizontal_bounds) { |
348 DCHECK_EQ(vertical_sort.size(), horizontal_sort.size()); | 349 DCHECK_EQ(vertical_sort.size(), horizontal_sort.size()); |
349 Rect vertical_bounds_rect; | 350 Rect vertical_bounds_rect; |
350 Rect horizontal_bounds_rect; | 351 Rect horizontal_bounds_rect; |
351 vertical_bounds->reserve(vertical_sort.size()); | 352 vertical_bounds->reserve(vertical_sort.size()); |
352 horizontal_bounds->reserve(horizontal_sort.size()); | 353 horizontal_bounds->reserve(horizontal_sort.size()); |
353 for (size_t i = 0; i < vertical_sort.size(); ++i) { | 354 for (size_t i = 0; i < vertical_sort.size(); ++i) { |
Peter Kasting
2014/05/02 18:04:57
Nit: I would split this into two loops (horizontal
luken
2014/05/08 00:00:08
Done.
| |
354 vertical_bounds_rect.Union(vertical_sort[i]->rect_); | 355 vertical_bounds_rect.Union(vertical_sort[i]->rect_); |
355 horizontal_bounds_rect.Union(horizontal_sort[i]->rect_); | 356 horizontal_bounds_rect.Union(horizontal_sort[i]->rect_); |
356 vertical_bounds->push_back(vertical_bounds_rect); | 357 vertical_bounds->push_back(vertical_bounds_rect); |
357 horizontal_bounds->push_back(horizontal_bounds_rect); | 358 horizontal_bounds->push_back(horizontal_bounds_rect); |
358 } | 359 } |
359 } | 360 } |
360 | 361 |
361 // static | 362 // static |
362 void RTree::Node::BuildHighBounds(const std::vector<Node*>& vertical_sort, | 363 void RTree::Node::BuildHighBounds(const std::vector<Node*>& vertical_sort, |
363 const std::vector<Node*>& horizontal_sort, | 364 const std::vector<Node*>& horizontal_sort, |
364 std::vector<Rect>* vertical_bounds, | 365 std::vector<Rect>* vertical_bounds, |
365 std::vector<Rect>* horizontal_bounds) { | 366 std::vector<Rect>* horizontal_bounds) { |
366 DCHECK_EQ(vertical_sort.size(), horizontal_sort.size()); | 367 DCHECK_EQ(vertical_sort.size(), horizontal_sort.size()); |
367 Rect vertical_bounds_rect; | 368 Rect vertical_bounds_rect; |
368 Rect horizontal_bounds_rect; | 369 Rect horizontal_bounds_rect; |
369 vertical_bounds->resize(vertical_sort.size()); | 370 vertical_bounds->resize(vertical_sort.size()); |
370 horizontal_bounds->resize(horizontal_sort.size()); | 371 horizontal_bounds->resize(horizontal_sort.size()); |
371 for (int i = static_cast<int>(vertical_sort.size()) - 1; i >= 0; --i) { | 372 for (int i = static_cast<int>(vertical_sort.size()) - 1; i >= 0; --i) { |
Peter Kasting
2014/05/02 18:04:57
Nit: I would again use two loops. For maximum saf
luken
2014/05/08 00:00:08
Done.
| |
372 vertical_bounds_rect.Union(vertical_sort[i]->rect_); | 373 vertical_bounds_rect.Union(vertical_sort[i]->rect_); |
373 horizontal_bounds_rect.Union(horizontal_sort[i]->rect_); | 374 horizontal_bounds_rect.Union(horizontal_sort[i]->rect_); |
374 vertical_bounds->at(i) = vertical_bounds_rect; | 375 vertical_bounds->at(i) = vertical_bounds_rect; |
375 horizontal_bounds->at(i) = horizontal_bounds_rect; | 376 horizontal_bounds->at(i) = horizontal_bounds_rect; |
376 } | 377 } |
377 } | 378 } |
378 | 379 |
379 // static | 380 // static |
380 bool RTree::Node::ChooseSplitAxis( | 381 bool RTree::Node::ChooseSplitAxis( |
381 const std::vector<Rect>& low_vertical_bounds, | 382 const std::vector<Rect>& low_vertical_bounds, |
382 const std::vector<Rect>& high_vertical_bounds, | 383 const std::vector<Rect>& high_vertical_bounds, |
383 const std::vector<Rect>& low_horizontal_bounds, | 384 const std::vector<Rect>& low_horizontal_bounds, |
384 const std::vector<Rect>& high_horizontal_bounds, | 385 const std::vector<Rect>& high_horizontal_bounds, |
385 size_t min_children, | 386 size_t min_children, |
386 size_t max_children) { | 387 size_t max_children) { |
Peter Kasting
2014/05/02 18:04:57
If you wrote a helper function,
int SmallestMargi
luken
2014/05/08 00:00:08
Done.
| |
387 // Examine the possible distributions of each sorted list by iterating through | 388 // Examine the possible distributions of each sorted list by iterating through |
388 // valid split points p, min_children <= p <= max_children - min_children, and | 389 // valid split points p, min_children <= p <= max_children - min_children, and |
Peter Kasting
2014/05/02 18:04:57
This looks weird to me. I would think "max_childr
luken
2014/05/08 00:00:08
This code is now deprecated, but we really do need
Peter Kasting
2014/05/08 18:08:21
OK, so the node we're splitting is assumed to have
luken
2014/05/14 00:12:04
It's assumed to have max_children + 1 nodes, but y
| |
389 // computing the sums of the margins of the bounding boxes in each group. | 390 // computing the sums of the margins of the bounding boxes in each group. |
390 // Smallest margin sum will determine split axis. | 391 // Smallest margin sum will determine split axis. |
391 int smallest_horizontal_margin_sum = std::numeric_limits<int>::max(); | 392 int smallest_horizontal_margin_sum = std::numeric_limits<int>::max(); |
392 int smallest_vertical_margin_sum = std::numeric_limits<int>::max(); | 393 int smallest_vertical_margin_sum = std::numeric_limits<int>::max(); |
393 for (size_t p = min_children; p < max_children - min_children; ++p) { | 394 for (size_t p = min_children; p < max_children - min_children; ++p) { |
394 int horizontal_margin_sum = | 395 int horizontal_margin_sum = |
395 low_horizontal_bounds[p].width() + low_horizontal_bounds[p].height() + | 396 low_horizontal_bounds[p].width() + low_horizontal_bounds[p].height() + |
396 high_horizontal_bounds[p].width() + high_horizontal_bounds[p].height(); | 397 high_horizontal_bounds[p].width() + high_horizontal_bounds[p].height(); |
397 int vertical_margin_sum = | 398 int vertical_margin_sum = |
398 low_vertical_bounds[p].width() + low_vertical_bounds[p].height() + | 399 low_vertical_bounds[p].width() + low_vertical_bounds[p].height() + |
(...skipping 11 matching lines...) Expand all Loading... | |
410 // distributed to the two Nodes. | 411 // distributed to the two Nodes. |
411 bool is_vertical_split = | 412 bool is_vertical_split = |
412 smallest_vertical_margin_sum < smallest_horizontal_margin_sum; | 413 smallest_vertical_margin_sum < smallest_horizontal_margin_sum; |
413 return is_vertical_split; | 414 return is_vertical_split; |
414 } | 415 } |
415 | 416 |
416 RTree::Node* RTree::Node::DivideChildren( | 417 RTree::Node* RTree::Node::DivideChildren( |
417 const std::vector<Rect>& low_bounds, | 418 const std::vector<Rect>& low_bounds, |
418 const std::vector<Rect>& high_bounds, | 419 const std::vector<Rect>& high_bounds, |
419 const std::vector<Node*>& sorted_children, | 420 const std::vector<Node*>& sorted_children, |
420 size_t split_index) { | 421 size_t split_index) { |
Peter Kasting
2014/05/02 18:04:57
I suspect you want the following DCHECKs here:
luken
2014/05/08 00:00:08
Done.
| |
421 Node* sibling = new Node(level_); | 422 Node* sibling = new Node(level_); |
422 sibling->parent_ = parent_; | 423 sibling->parent_ = parent_; |
423 rect_ = low_bounds[split_index - 1]; | 424 rect_ = low_bounds[split_index - 1]; |
424 sibling->rect_ = high_bounds[split_index]; | 425 sibling->rect_ = high_bounds[split_index]; |
425 // Our own children_ vector is unsorted, so we wipe it out and divide the | 426 // Our own children_ vector is unsorted, so we wipe it out and divide the |
Peter Kasting
2014/05/02 18:04:57
Nit: In general, if you're writing a comment about
luken
2014/05/08 00:00:08
Done.
| |
426 // sorted bounds rects between ourselves and our sibling. | 427 // sorted bounds rects between ourselves and our sibling. |
427 children_.weak_clear(); | 428 children_.weak_clear(); |
428 children_.insert(children_.end(), | 429 children_.insert(children_.end(), |
429 sorted_children.begin(), | 430 sorted_children.begin(), |
430 sorted_children.begin() + split_index); | 431 sorted_children.begin() + split_index); |
431 sibling->children_.insert(sibling->children_.end(), | 432 sibling->children_.insert(sibling->children_.end(), |
432 sorted_children.begin() + split_index, | 433 sorted_children.begin() + split_index, |
433 sorted_children.end()); | 434 sorted_children.end()); |
434 | 435 |
435 // Fix up sibling parentage or it's gonna be an awkward Thanksgiving. | 436 // Fix up sibling parentage or it's gonna be an awkward Thanksgiving. |
Peter Kasting
2014/05/02 18:04:57
Remove this comment; the code is clear enough.
luken
2014/05/08 00:00:08
Done.
| |
436 for (size_t i = 0; i < sibling->children_.size(); ++i) { | 437 for (size_t i = 0; i < sibling->children_.size(); ++i) { |
437 sibling->children_[i]->parent_ = sibling; | 438 sibling->children_[i]->parent_ = sibling; |
438 } | 439 } |
439 | 440 |
440 return sibling; | 441 return sibling; |
441 } | 442 } |
442 | 443 |
443 void RTree::Node::SetRect(const Rect& rect) { | 444 void RTree::Node::SetRect(const Rect& rect) { |
444 // Record nodes only, please. | 445 // Record nodes only, please. |
445 DCHECK(key_); | 446 DCHECK(key_); |
446 rect_ = rect; | 447 rect_ = rect; |
447 } | 448 } |
448 | 449 |
449 // Returns all contained record_node values for this node and all children. | 450 // Returns all contained record_node values for this node and all children. |
Peter Kasting
2014/05/02 18:04:57
Remove this comment, you say something similar in
luken
2014/05/08 00:00:08
Done.
| |
450 void RTree::Node::GetAllValues(base::hash_set<intptr_t>* matches_out) const { | 451 void RTree::Node::GetAllValues(base::hash_set<intptr_t>* matches_out) const { |
451 if (key_) { | 452 if (key_) { |
452 DCHECK_EQ(level_, -1); | 453 DCHECK_EQ(level_, -1); |
Peter Kasting
2014/05/02 18:04:57
Again, this is not necessary.
luken
2014/05/08 00:00:08
Done.
| |
453 matches_out->insert(key_); | 454 matches_out->insert(key_); |
454 } else { | 455 } else { |
455 for (size_t i = 0; i < children_.size(); ++i) { | 456 for (size_t i = 0; i < children_.size(); ++i) { |
456 Node* node = children_[i]; | 457 Node* node = children_[i]; |
457 // Sanity-check our children. | 458 // Sanity-check our children. |
458 DCHECK_EQ(node->parent_, this); | 459 DCHECK_EQ(node->parent_, this); |
459 DCHECK_EQ(level_ - 1, node->level_); | 460 DCHECK_EQ(level_ - 1, node->level_); |
460 DCHECK(rect_.Contains(node->rect_)); | 461 DCHECK(rect_.Contains(node->rect_)); |
Peter Kasting
2014/05/02 18:04:57
None of these three DCHECKs seems to have anything
luken
2014/05/08 00:00:08
Done.
| |
461 node->GetAllValues(matches_out); | 462 node->GetAllValues(matches_out); |
462 } | 463 } |
463 } | 464 } |
464 } | 465 } |
465 | 466 |
466 // static | 467 // static |
467 bool RTree::Node::CompareVertical(Node* a, Node* b) { | 468 bool RTree::Node::CompareVertical(Node* a, Node* b) { |
468 // Sort nodes by top coordinate first. | 469 // Sort nodes by top coordinate first. |
Peter Kasting
2014/05/02 18:04:57
These comments pretty much duplicate the code. It
luken
2014/05/08 00:00:08
Done.
| |
469 if (a->rect_.y() < b->rect_.y()) { | 470 if (a->rect_.y() < b->rect_.y()) { |
470 return true; | 471 return true; |
471 } else if (a->rect_.y() == b->rect_.y()) { | 472 } else if (a->rect_.y() == b->rect_.y()) { |
Peter Kasting
2014/05/02 18:04:57
From http://dev.chromium.org/developers/coding-sty
luken
2014/05/08 00:00:08
Done.
| |
472 // If top coordinate is equal, sort by lowest bottom coordinate. | 473 // If top coordinate is equal, sort by lowest bottom coordinate. |
473 return a->rect_.height() < b->rect_.height(); | 474 return a->rect_.height() < b->rect_.height(); |
474 } | 475 } |
475 return false; | 476 return false; |
Peter Kasting
2014/05/02 18:04:57
Nit: The second half of this function could just b
luken
2014/05/08 00:00:08
Done.
| |
476 } | 477 } |
477 | 478 |
478 // static | 479 // static |
479 bool RTree::Node::CompareHorizontal(Node* a, Node* b) { | 480 bool RTree::Node::CompareHorizontal(Node* a, Node* b) { |
Peter Kasting
2014/05/02 18:04:57
Similar comments apply to this function.
luken
2014/05/08 00:00:08
Done.
| |
480 // Sort nodes by left coordinate first. | 481 // Sort nodes by left coordinate first. |
481 if (a->rect_.x() < b->rect_.x()) { | 482 if (a->rect_.x() < b->rect_.x()) { |
482 return true; | 483 return true; |
483 } else if (a->rect_.x() == b->rect_.x()) { | 484 } else if (a->rect_.x() == b->rect_.x()) { |
484 // If left coordinate is equal, sort by lowest right coordinate. | 485 // If left coordinate is equal, sort by lowest right coordinate. |
485 return a->rect_.width() < b->rect_.width(); | 486 return a->rect_.width() < b->rect_.width(); |
486 } | 487 } |
487 return false; | 488 return false; |
488 } | 489 } |
489 | 490 |
490 // Sort these two nodes by the distance of the center of their rects from the | 491 // Sort these two nodes by the distance of the center of their rects from the |
491 // center of their parent's rect. We don't bother with square roots because we | 492 // center of their parent's rect. We don't bother with square roots because we |
492 // are only comparing the two values for sorting purposes. | 493 // are only comparing the two values for sorting purposes. |
Peter Kasting
2014/05/02 18:04:57
This second sentence belongs in the code, directly
luken
2014/05/08 00:00:08
Done.
| |
493 // static | 494 // static |
494 bool RTree::Node::CompareCenterDistanceFromParent(Node* a, Node* b) { | 495 bool RTree::Node::CompareCenterDistanceFromParent(Node* a, Node* b) { |
495 // This comparison assumes the nodes have the same parent. | 496 // This comparison assumes the nodes have the same parent. |
Peter Kasting
2014/05/02 18:04:57
All four of the comments here simply duplicate the
luken
2014/05/08 00:00:08
Done.
| |
496 DCHECK(a->parent_ == b->parent_); | 497 DCHECK(a->parent_ == b->parent_); |
Peter Kasting
2014/05/02 18:04:57
Nit: DCHECK_EQ
luken
2014/05/08 00:00:08
Done.
| |
497 // This comparison requires that each node have a parent. | 498 // This comparison requires that each node have a parent. |
498 DCHECK(a->parent_); | 499 DCHECK(a->parent_); |
Peter Kasting
2014/05/02 18:04:57
Tiny nit: I suggest putting this DCHECK first (so
luken
2014/05/08 00:00:08
Done.
| |
499 // Sanity-check level_ of these nodes is equal. | 500 // Sanity-check level_ of these nodes is equal. |
500 DCHECK_EQ(a->level_, b->level_); | 501 DCHECK_EQ(a->level_, b->level_); |
Peter Kasting
2014/05/02 18:04:57
This function doesn't require either of these next
luken
2014/05/08 00:00:08
Done.
| |
501 // Also the parent of the nodes should have level one higher. | 502 // Also the parent of the nodes should have level one higher. |
502 DCHECK_EQ(a->level_, a->parent_->level_ - 1); | 503 DCHECK_EQ(a->level_, a->parent_->level_ - 1); |
503 | 504 |
504 // Find the parent. | 505 // Find the parent. |
Peter Kasting
2014/05/02 18:04:57
Comment duplicates the code, remove it.
luken
2014/05/08 00:00:08
Done.
| |
505 Node* p = a->parent(); | 506 Node* p = a->parent(); |
506 | 507 |
507 Vector2d p_center = CenterOfRect(p->rect_); | 508 Vector2d p_center = CenterOfRect(p->rect_); |
508 Vector2d a_center = CenterOfRect(a->rect_); | 509 Vector2d a_center = CenterOfRect(a->rect_); |
509 Vector2d b_center = CenterOfRect(b->rect_); | 510 Vector2d b_center = CenterOfRect(b->rect_); |
510 | 511 |
511 return (a_center - p_center).LengthSquared() < | 512 return (a_center - p_center).LengthSquared() < |
512 (b_center - p_center).LengthSquared(); | 513 (b_center - p_center).LengthSquared(); |
513 } | 514 } |
514 | 515 |
515 size_t RTree::Node::ChooseSplitIndex(size_t min_children, | 516 size_t RTree::Node::ChooseSplitIndex(size_t min_children, |
516 size_t max_children, | 517 size_t max_children, |
517 const std::vector<Rect>& low_bounds, | 518 const std::vector<Rect>& low_bounds, |
518 const std::vector<Rect>& high_bounds) { | 519 const std::vector<Rect>& high_bounds) { |
Peter Kasting
2014/05/02 18:04:57
Again, this function probably deserves DCHECKs lik
luken
2014/05/08 00:00:08
DCHECKs added.
Index is correct. I'll add a comme
| |
519 int smallest_overlap_area = std::numeric_limits<int>::max(); | 520 int smallest_overlap_area = std::numeric_limits<int>::max(); |
Peter Kasting
2014/05/02 18:04:57
This whole block can be simplified:
int smalles
luken
2014/05/08 00:00:08
Done, although my version only computed combined_a
| |
520 int smallest_combined_area = std::numeric_limits<int>::max(); | 521 int smallest_combined_area = std::numeric_limits<int>::max(); |
521 size_t optimal_split_index = 0; | 522 size_t optimal_split_index = 0; |
522 for (size_t p = min_children; p < max_children - min_children; ++p) { | 523 for (size_t p = min_children; p < max_children - min_children; ++p) { |
523 Rect overlap_bounds = low_bounds[p]; | 524 Rect overlap_bounds = low_bounds[p]; |
524 overlap_bounds.Union(high_bounds[p]); | 525 overlap_bounds.Union(high_bounds[p]); |
525 int overlap_area = overlap_bounds.size().GetArea(); | 526 int overlap_area = overlap_bounds.size().GetArea(); |
526 if (overlap_area < smallest_overlap_area) { | 527 if (overlap_area < smallest_overlap_area) { |
527 smallest_overlap_area = overlap_area; | 528 smallest_overlap_area = overlap_area; |
528 smallest_combined_area = | 529 smallest_combined_area = |
529 low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea(); | 530 low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea(); |
530 optimal_split_index = p; | 531 optimal_split_index = p; |
531 } else if (overlap_area == smallest_overlap_area) { | 532 } else if (overlap_area == smallest_overlap_area) { |
532 // Break ties with smallest combined area of the two bounding boxes. | 533 // Break ties with smallest combined area of the two bounding boxes. |
533 int combined_area = | 534 int combined_area = |
534 low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea(); | 535 low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea(); |
535 if (combined_area < smallest_combined_area) { | 536 if (combined_area < smallest_combined_area) { |
536 smallest_combined_area = combined_area; | 537 smallest_combined_area = combined_area; |
537 optimal_split_index = p; | 538 optimal_split_index = p; |
538 } | 539 } |
539 } | 540 } |
540 } | 541 } |
541 | 542 |
542 // optimal_split_index currently points at the last element in the first set, | 543 // optimal_split_index currently points at the last element in the first set, |
543 // so advance it by 1 to point at the first element in the second set. | 544 // so advance it by 1 to point at the first element in the second set. |
544 return optimal_split_index + 1; | 545 return optimal_split_index + 1; |
545 } | 546 } |
546 | 547 |
547 void RTree::Node::RecomputeBoundsNoParents() { | 548 void RTree::Node::RecomputeBoundsNoParents() { |
548 // Clear our rectangle, then reset it to union of our children. | 549 // Clear our rectangle, then reset it to union of our children. |
Peter Kasting
2014/05/02 18:04:57
This comment isn't necessary.
luken
2014/05/08 00:00:08
Done.
| |
549 rect_.SetRect(0, 0, 0, 0); | 550 rect_.SetRect(0, 0, 0, 0); |
550 for (size_t i = 0; i < children_.size(); ++i) { | 551 for (size_t i = 0; i < children_.size(); ++i) { |
551 rect_.Union(children_[i]->rect_); | 552 rect_.Union(children_[i]->rect_); |
552 } | 553 } |
553 } | 554 } |
554 | 555 |
555 RTree::RTree(size_t min_children, size_t max_children) | 556 RTree::RTree(size_t min_children, size_t max_children) |
556 : root_(new Node(0)), | 557 : root_(new Node(0)), |
557 min_children_(min_children), | 558 min_children_(min_children), |
558 max_children_(max_children) { | 559 max_children_(max_children) { |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 int starting_level = -1; | 737 int starting_level = -1; |
737 InsertNode(orphans[i], &starting_level); | 738 InsertNode(orphans[i], &starting_level); |
738 } | 739 } |
739 | 740 |
740 // Clear out the orphans list without deleting any of the children, as they | 741 // Clear out the orphans list without deleting any of the children, as they |
741 // have been re-inserted into the tree. | 742 // have been re-inserted into the tree. |
742 orphans.weak_clear(); | 743 orphans.weak_clear(); |
743 } | 744 } |
744 | 745 |
745 } // namespace gfx | 746 } // namespace gfx |
OLD | NEW |