Chromium Code Reviews| 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 |