| Index: ui/gfx/geometry/r_tree.cc
|
| diff --git a/ui/gfx/geometry/r_tree.cc b/ui/gfx/geometry/r_tree.cc
|
| deleted file mode 100644
|
| index 7fa095575b1710eac0ec402788061d19451476ca..0000000000000000000000000000000000000000
|
| --- a/ui/gfx/geometry/r_tree.cc
|
| +++ /dev/null
|
| @@ -1,750 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "ui/gfx/geometry/r_tree.h"
|
| -
|
| -#include <algorithm>
|
| -#include <limits>
|
| -
|
| -#include "base/logging.h"
|
| -
|
| -namespace {
|
| -
|
| -// Returns the center coordinates of the given rectangle.
|
| -gfx::Vector2d CenterOfRect(const gfx::Rect& rect) {
|
| - return rect.OffsetFromOrigin() +
|
| - gfx::Vector2d(rect.width() / 2, rect.height() / 2);
|
| -}
|
| -}
|
| -
|
| -namespace gfx {
|
| -
|
| -RTree::Node::Node(int level) : level_(level), parent_(NULL), key_(0) {
|
| -}
|
| -
|
| -RTree::Node::Node(const Rect& rect, intptr_t key)
|
| - : rect_(rect), level_(-1), parent_(NULL), key_(key) {
|
| -}
|
| -
|
| -RTree::Node::~Node() {
|
| - Clear();
|
| -}
|
| -
|
| -void RTree::Node::Clear() {
|
| - // Iterate through children and delete them all.
|
| - children_.clear();
|
| - key_ = 0;
|
| -}
|
| -
|
| -void RTree::Node::Query(const Rect& query_rect,
|
| - base::hash_set<intptr_t>* matches_out) const {
|
| - // Check own bounding box for intersection, can cull all children if no
|
| - // intersection.
|
| - if (!rect_.Intersects(query_rect)) {
|
| - return;
|
| - }
|
| -
|
| - // Conversely if we are completely contained within the query rect we can
|
| - // confidently skip all bounds checks for ourselves and all our children.
|
| - if (query_rect.Contains(rect_)) {
|
| - GetAllValues(matches_out);
|
| - return;
|
| - }
|
| -
|
| - // We intersect the query rect but we are not are not contained within it.
|
| - // If we are a record node, then add our record value. Otherwise we must
|
| - // query each of our children in turn.
|
| - if (key_) {
|
| - DCHECK_EQ(level_, -1);
|
| - matches_out->insert(key_);
|
| - } else {
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - // Sanity-check our children.
|
| - Node* node = children_[i];
|
| - DCHECK_EQ(node->parent_, this);
|
| - DCHECK_EQ(level_ - 1, node->level_);
|
| - DCHECK(rect_.Contains(node->rect_));
|
| - node->Query(query_rect, matches_out);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void RTree::Node::RecomputeBounds() {
|
| - RecomputeBoundsNoParents();
|
| - // Recompute our parent's bounds recursively up to the root.
|
| - if (parent_) {
|
| - parent_->RecomputeBounds();
|
| - }
|
| -}
|
| -
|
| -void RTree::Node::RemoveNodesForReinsert(size_t number_to_remove,
|
| - ScopedVector<Node>* nodes) {
|
| - DCHECK_GE(children_.size(), number_to_remove);
|
| -
|
| - // Sort our children by their distance from the center of their rectangles to
|
| - // the center of our bounding rectangle.
|
| - std::sort(children_.begin(),
|
| - children_.end(),
|
| - &RTree::Node::CompareCenterDistanceFromParent);
|
| -
|
| - // Add lowest distance nodes from our children list to the returned vector.
|
| - nodes->insert(
|
| - nodes->end(), children_.begin(), children_.begin() + number_to_remove);
|
| - // Remove those same nodes from our list, without deleting them.
|
| - children_.weak_erase(children_.begin(), children_.begin() + number_to_remove);
|
| -}
|
| -
|
| -size_t RTree::Node::RemoveChild(Node* child_node, ScopedVector<Node>* orphans) {
|
| - // Should actually be one of our children.
|
| - DCHECK_EQ(child_node->parent_, this);
|
| -
|
| - // Add children of child_node to the orphans vector.
|
| - orphans->insert(orphans->end(),
|
| - child_node->children_.begin(),
|
| - child_node->children_.end());
|
| - // Remove without deletion those children from the child_node vector.
|
| - child_node->children_.weak_clear();
|
| -
|
| - // Find an iterator to this Node in our own children_ vector.
|
| - ScopedVector<Node>::iterator child_it = children_.end();
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - if (children_[i] == child_node) {
|
| - child_it = children_.begin() + i;
|
| - break;
|
| - }
|
| - }
|
| - // Should have found the pointer in our children_ vector.
|
| - DCHECK(child_it != children_.end());
|
| - // Remove without deleting the child node from our children_ vector.
|
| - children_.weak_erase(child_it);
|
| -
|
| - return children_.size();
|
| -}
|
| -
|
| -scoped_ptr<RTree::Node> RTree::Node::RemoveAndReturnLastChild() {
|
| - if (!children_.size())
|
| - return scoped_ptr<Node>();
|
| -
|
| - scoped_ptr<Node> last_child(children_[children_.size() - 1]);
|
| - DCHECK_EQ(last_child->parent_, this);
|
| - children_.weak_erase(children_.begin() + children_.size() - 1);
|
| - // Invalidate parent, as this child may even become the new root.
|
| - last_child->parent_ = NULL;
|
| - return last_child.Pass();
|
| -}
|
| -
|
| -// Uses the R*-Tree algorithm CHOOSELEAF proposed by Beckmann et al.
|
| -RTree::Node* RTree::Node::ChooseSubtree(Node* node) {
|
| - // Should never be called on a record node.
|
| - DCHECK(!key_);
|
| - DCHECK(level_ >= 0);
|
| - DCHECK(node);
|
| -
|
| - // If we are a parent of nodes on the provided node level, we are done.
|
| - if (level_ == node->level_ + 1)
|
| - return this;
|
| -
|
| - // We are an internal node, and thus guaranteed to have children.
|
| - DCHECK_GT(children_.size(), 0U);
|
| -
|
| - // Iterate over all children to find best candidate for insertion.
|
| - Node* best_candidate = NULL;
|
| -
|
| - // Precompute a vector of expanded rects, used both by LeastOverlapIncrease
|
| - // and LeastAreaEnlargement.
|
| - std::vector<Rect> expanded_rects;
|
| - expanded_rects.reserve(children_.size());
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - Rect expanded_rect(node->rect_);
|
| - expanded_rect.Union(children_[i]->rect_);
|
| - expanded_rects.push_back(expanded_rect);
|
| - }
|
| -
|
| - // For parents of leaf nodes, we pick the node that will cause the least
|
| - // increase in overlap by the addition of this new node. This may detect a
|
| - // tie, in which case it will return NULL.
|
| - if (level_ == 1)
|
| - best_candidate = LeastOverlapIncrease(node->rect_, expanded_rects);
|
| -
|
| - // For non-parents of leaf nodes, or for parents of leaf nodes with ties in
|
| - // overlap increase, we choose the subtree with least area enlargement caused
|
| - // by the addition of the new node.
|
| - if (!best_candidate)
|
| - best_candidate = LeastAreaEnlargement(node->rect_, expanded_rects);
|
| -
|
| - DCHECK(best_candidate);
|
| - return best_candidate->ChooseSubtree(node);
|
| -}
|
| -
|
| -RTree::Node* RTree::Node::LeastAreaEnlargement(
|
| - const Rect& node_rect,
|
| - const std::vector<Rect>& expanded_rects) {
|
| - Node* best_node = NULL;
|
| - int least_area_enlargement = std::numeric_limits<int>::max();
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - Node* candidate_node = children_[i];
|
| - int area_change = expanded_rects[i].size().GetArea() -
|
| - candidate_node->rect_.size().GetArea();
|
| - if (area_change < least_area_enlargement) {
|
| - best_node = candidate_node;
|
| - least_area_enlargement = area_change;
|
| - } else if (area_change == least_area_enlargement) {
|
| - // Ties are broken by choosing entry with least area.
|
| - DCHECK(best_node);
|
| - if (candidate_node->rect_.size().GetArea() <
|
| - best_node->rect_.size().GetArea()) {
|
| - best_node = candidate_node;
|
| - }
|
| - }
|
| - }
|
| -
|
| - DCHECK(best_node);
|
| - return best_node;
|
| -}
|
| -
|
| -RTree::Node* RTree::Node::LeastOverlapIncrease(
|
| - const Rect& node_rect,
|
| - const std::vector<Rect>& expanded_rects) {
|
| - Node* best_node = NULL;
|
| - bool has_tied_node = false;
|
| - int least_overlap_increase = std::numeric_limits<int>::max();
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - int overlap_increase =
|
| - OverlapIncreaseToAdd(node_rect, i, expanded_rects[i]);
|
| - if (overlap_increase < least_overlap_increase) {
|
| - least_overlap_increase = overlap_increase;
|
| - best_node = children_[i];
|
| - has_tied_node = false;
|
| - } else if (overlap_increase == least_overlap_increase) {
|
| - has_tied_node = true;
|
| - // If we are tied at zero there is no possible better overlap increase,
|
| - // so we can report a tie early.
|
| - if (overlap_increase == 0) {
|
| - return NULL;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // If we ended up with a tie return NULL to report it.
|
| - if (has_tied_node)
|
| - return NULL;
|
| -
|
| - return best_node;
|
| -}
|
| -
|
| -int RTree::Node::OverlapIncreaseToAdd(const Rect& rect,
|
| - size_t candidate,
|
| - const Rect& expanded_rect) {
|
| - Node* candidate_node = children_[candidate];
|
| -
|
| - // Early-out option for when rect is contained completely within candidate.
|
| - if (candidate_node->rect_.Contains(rect)) {
|
| - return 0;
|
| - }
|
| -
|
| - int total_original_overlap = 0;
|
| - int total_expanded_overlap = 0;
|
| -
|
| - // Now calculate overlap with all other rects in this node.
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - // Skip calculating overlap with the candidate rect.
|
| - if (i == candidate)
|
| - continue;
|
| - Node* overlap_node = children_[i];
|
| - Rect overlap_rect = candidate_node->rect_;
|
| - overlap_rect.Intersect(overlap_node->rect_);
|
| - total_original_overlap += overlap_rect.size().GetArea();
|
| - Rect expanded_overlap_rect = expanded_rect;
|
| - expanded_overlap_rect.Intersect(overlap_node->rect_);
|
| - total_expanded_overlap += expanded_overlap_rect.size().GetArea();
|
| - }
|
| -
|
| - // Compare this overlap increase with best one to date, update best.
|
| - int overlap_increase = total_expanded_overlap - total_original_overlap;
|
| - return overlap_increase;
|
| -}
|
| -
|
| -size_t RTree::Node::AddChild(Node* node) {
|
| - DCHECK(node);
|
| - // Sanity-check that the level of the child being added is one more than ours.
|
| - DCHECK_EQ(level_ - 1, node->level_);
|
| - node->parent_ = this;
|
| - children_.push_back(node);
|
| - rect_.Union(node->rect_);
|
| - return children_.size();
|
| -}
|
| -
|
| -RTree::Node* RTree::Node::Split(size_t min_children, size_t max_children) {
|
| - // Please don't attempt to split a record Node.
|
| - DCHECK(!key_);
|
| - // We should have too many children to begin with.
|
| - DCHECK_GT(children_.size(), max_children);
|
| - // First determine if splitting along the horizontal or vertical axis. We
|
| - // sort the rectangles of our children by lower then upper values along both
|
| - // horizontal and vertical axes.
|
| - std::vector<Node*> vertical_sort(children_.get());
|
| - std::vector<Node*> horizontal_sort(children_.get());
|
| - std::sort(vertical_sort.begin(),
|
| - vertical_sort.end(),
|
| - &RTree::Node::CompareVertical);
|
| - std::sort(horizontal_sort.begin(),
|
| - horizontal_sort.end(),
|
| - &RTree::Node::CompareHorizontal);
|
| -
|
| - // We will be examining the bounding boxes of different splits of our children
|
| - // sorted along each axis. Here we precompute the bounding boxes of these
|
| - // distributions. For the low bounds the ith element can be considered the
|
| - // union of all rects [0,i] in the relevant sorted axis array.
|
| - std::vector<Rect> low_vertical_bounds;
|
| - std::vector<Rect> low_horizontal_bounds;
|
| - BuildLowBounds(vertical_sort,
|
| - horizontal_sort,
|
| - &low_vertical_bounds,
|
| - &low_horizontal_bounds);
|
| -
|
| - // For the high bounds the ith element can be considered the union of all
|
| - // rects [i, children_.size()) in the relevant sorted axis array.
|
| - std::vector<Rect> high_vertical_bounds;
|
| - std::vector<Rect> high_horizontal_bounds;
|
| - BuildHighBounds(vertical_sort,
|
| - horizontal_sort,
|
| - &high_vertical_bounds,
|
| - &high_horizontal_bounds);
|
| -
|
| - bool is_vertical_split = ChooseSplitAxis(low_vertical_bounds,
|
| - high_vertical_bounds,
|
| - low_horizontal_bounds,
|
| - high_horizontal_bounds,
|
| - min_children,
|
| - max_children);
|
| -
|
| - // Lastly we determine optimal index and do the split.
|
| - Node* sibling = NULL;
|
| - if (is_vertical_split) {
|
| - size_t split_index = ChooseSplitIndex(
|
| - min_children, max_children, low_vertical_bounds, high_vertical_bounds);
|
| - sibling = DivideChildren(
|
| - low_vertical_bounds, high_vertical_bounds, vertical_sort, split_index);
|
| - } else {
|
| - size_t split_index = ChooseSplitIndex(min_children,
|
| - max_children,
|
| - low_horizontal_bounds,
|
| - high_horizontal_bounds);
|
| - sibling = DivideChildren(low_horizontal_bounds,
|
| - high_horizontal_bounds,
|
| - horizontal_sort,
|
| - split_index);
|
| - }
|
| -
|
| - return sibling;
|
| -}
|
| -
|
| -// static
|
| -void RTree::Node::BuildLowBounds(const std::vector<Node*>& vertical_sort,
|
| - const std::vector<Node*>& horizontal_sort,
|
| - std::vector<Rect>* vertical_bounds,
|
| - std::vector<Rect>* horizontal_bounds) {
|
| - DCHECK_EQ(vertical_sort.size(), horizontal_sort.size());
|
| - Rect vertical_bounds_rect;
|
| - Rect horizontal_bounds_rect;
|
| - vertical_bounds->reserve(vertical_sort.size());
|
| - horizontal_bounds->reserve(horizontal_sort.size());
|
| - for (size_t i = 0; i < vertical_sort.size(); ++i) {
|
| - vertical_bounds_rect.Union(vertical_sort[i]->rect_);
|
| - horizontal_bounds_rect.Union(horizontal_sort[i]->rect_);
|
| - vertical_bounds->push_back(vertical_bounds_rect);
|
| - horizontal_bounds->push_back(horizontal_bounds_rect);
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void RTree::Node::BuildHighBounds(const std::vector<Node*>& vertical_sort,
|
| - const std::vector<Node*>& horizontal_sort,
|
| - std::vector<Rect>* vertical_bounds,
|
| - std::vector<Rect>* horizontal_bounds) {
|
| - DCHECK_EQ(vertical_sort.size(), horizontal_sort.size());
|
| - Rect vertical_bounds_rect;
|
| - Rect horizontal_bounds_rect;
|
| - vertical_bounds->resize(vertical_sort.size());
|
| - horizontal_bounds->resize(horizontal_sort.size());
|
| - for (int i = static_cast<int>(vertical_sort.size()) - 1; i >= 0; --i) {
|
| - vertical_bounds_rect.Union(vertical_sort[i]->rect_);
|
| - horizontal_bounds_rect.Union(horizontal_sort[i]->rect_);
|
| - vertical_bounds->at(i) = vertical_bounds_rect;
|
| - horizontal_bounds->at(i) = horizontal_bounds_rect;
|
| - }
|
| -}
|
| -
|
| -// static
|
| -bool RTree::Node::ChooseSplitAxis(
|
| - const std::vector<Rect>& low_vertical_bounds,
|
| - const std::vector<Rect>& high_vertical_bounds,
|
| - const std::vector<Rect>& low_horizontal_bounds,
|
| - const std::vector<Rect>& high_horizontal_bounds,
|
| - size_t min_children,
|
| - size_t max_children) {
|
| - // Examine the possible distributions of each sorted list by iterating through
|
| - // valid split points p, min_children <= p <= max_children - min_children, and
|
| - // computing the sums of the margins of the bounding boxes in each group.
|
| - // Smallest margin sum will determine split axis.
|
| - int smallest_horizontal_margin_sum = std::numeric_limits<int>::max();
|
| - int smallest_vertical_margin_sum = std::numeric_limits<int>::max();
|
| - for (size_t p = min_children; p < max_children - min_children; ++p) {
|
| - int horizontal_margin_sum =
|
| - low_horizontal_bounds[p].width() + low_horizontal_bounds[p].height() +
|
| - high_horizontal_bounds[p].width() + high_horizontal_bounds[p].height();
|
| - int vertical_margin_sum =
|
| - low_vertical_bounds[p].width() + low_vertical_bounds[p].height() +
|
| - high_vertical_bounds[p].width() + high_vertical_bounds[p].height();
|
| - // Update margin minima if necessary.
|
| - smallest_horizontal_margin_sum =
|
| - std::min(horizontal_margin_sum, smallest_horizontal_margin_sum);
|
| - smallest_vertical_margin_sum =
|
| - std::min(vertical_margin_sum, smallest_vertical_margin_sum);
|
| - }
|
| -
|
| - // Split along the axis perpendicular to the axis with the overall smallest
|
| - // margin sum. Meaning the axis sort resulting in two boxes with the smallest
|
| - // combined margin will become the axis along which the sorted rectangles are
|
| - // distributed to the two Nodes.
|
| - bool is_vertical_split =
|
| - smallest_vertical_margin_sum < smallest_horizontal_margin_sum;
|
| - return is_vertical_split;
|
| -}
|
| -
|
| -RTree::Node* RTree::Node::DivideChildren(
|
| - const std::vector<Rect>& low_bounds,
|
| - const std::vector<Rect>& high_bounds,
|
| - const std::vector<Node*>& sorted_children,
|
| - size_t split_index) {
|
| - Node* sibling = new Node(level_);
|
| - sibling->parent_ = parent_;
|
| - rect_ = low_bounds[split_index - 1];
|
| - sibling->rect_ = high_bounds[split_index];
|
| - // Our own children_ vector is unsorted, so we wipe it out and divide the
|
| - // sorted bounds rects between ourselves and our sibling.
|
| - children_.weak_clear();
|
| - children_.insert(children_.end(),
|
| - sorted_children.begin(),
|
| - sorted_children.begin() + split_index);
|
| - sibling->children_.insert(sibling->children_.end(),
|
| - sorted_children.begin() + split_index,
|
| - sorted_children.end());
|
| -
|
| - // Fix up sibling parentage or it's gonna be an awkward Thanksgiving.
|
| - for (size_t i = 0; i < sibling->children_.size(); ++i) {
|
| - sibling->children_[i]->parent_ = sibling;
|
| - }
|
| -
|
| - return sibling;
|
| -}
|
| -
|
| -void RTree::Node::SetRect(const Rect& rect) {
|
| - // Record nodes only, please.
|
| - DCHECK(key_);
|
| - rect_ = rect;
|
| -}
|
| -
|
| -// Returns all contained record_node values for this node and all children.
|
| -void RTree::Node::GetAllValues(base::hash_set<intptr_t>* matches_out) const {
|
| - if (key_) {
|
| - DCHECK_EQ(level_, -1);
|
| - matches_out->insert(key_);
|
| - } else {
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - Node* node = children_[i];
|
| - // Sanity-check our children.
|
| - DCHECK_EQ(node->parent_, this);
|
| - DCHECK_EQ(level_ - 1, node->level_);
|
| - DCHECK(rect_.Contains(node->rect_));
|
| - node->GetAllValues(matches_out);
|
| - }
|
| - }
|
| -}
|
| -
|
| -// static
|
| -bool RTree::Node::CompareVertical(Node* a, Node* b) {
|
| - // Sort nodes by top coordinate first.
|
| - if (a->rect_.y() < b->rect_.y()) {
|
| - return true;
|
| - } else if (a->rect_.y() == b->rect_.y()) {
|
| - // If top coordinate is equal, sort by lowest bottom coordinate.
|
| - return a->rect_.height() < b->rect_.height();
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// static
|
| -bool RTree::Node::CompareHorizontal(Node* a, Node* b) {
|
| - // Sort nodes by left coordinate first.
|
| - if (a->rect_.x() < b->rect_.x()) {
|
| - return true;
|
| - } else if (a->rect_.x() == b->rect_.x()) {
|
| - // If left coordinate is equal, sort by lowest right coordinate.
|
| - return a->rect_.width() < b->rect_.width();
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// Sort these two nodes by the distance of the center of their rects from the
|
| -// center of their parent's rect. We don't bother with square roots because we
|
| -// are only comparing the two values for sorting purposes.
|
| -// static
|
| -bool RTree::Node::CompareCenterDistanceFromParent(Node* a, Node* b) {
|
| - // This comparison assumes the nodes have the same parent.
|
| - DCHECK(a->parent_ == b->parent_);
|
| - // This comparison requires that each node have a parent.
|
| - DCHECK(a->parent_);
|
| - // Sanity-check level_ of these nodes is equal.
|
| - DCHECK_EQ(a->level_, b->level_);
|
| - // Also the parent of the nodes should have level one higher.
|
| - DCHECK_EQ(a->level_, a->parent_->level_ - 1);
|
| -
|
| - // Find the parent.
|
| - Node* p = a->parent();
|
| -
|
| - Vector2d p_center = CenterOfRect(p->rect_);
|
| - Vector2d a_center = CenterOfRect(a->rect_);
|
| - Vector2d b_center = CenterOfRect(b->rect_);
|
| -
|
| - return (a_center - p_center).LengthSquared() <
|
| - (b_center - p_center).LengthSquared();
|
| -}
|
| -
|
| -size_t RTree::Node::ChooseSplitIndex(size_t min_children,
|
| - size_t max_children,
|
| - const std::vector<Rect>& low_bounds,
|
| - const std::vector<Rect>& high_bounds) {
|
| - int smallest_overlap_area = std::numeric_limits<int>::max();
|
| - int smallest_combined_area = std::numeric_limits<int>::max();
|
| - size_t optimal_split_index = 0;
|
| - for (size_t p = min_children; p < max_children - min_children; ++p) {
|
| - Rect overlap_bounds = low_bounds[p];
|
| - overlap_bounds.Union(high_bounds[p]);
|
| - int overlap_area = overlap_bounds.size().GetArea();
|
| - if (overlap_area < smallest_overlap_area) {
|
| - smallest_overlap_area = overlap_area;
|
| - smallest_combined_area =
|
| - low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea();
|
| - optimal_split_index = p;
|
| - } else if (overlap_area == smallest_overlap_area) {
|
| - // Break ties with smallest combined area of the two bounding boxes.
|
| - int combined_area =
|
| - low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea();
|
| - if (combined_area < smallest_combined_area) {
|
| - smallest_combined_area = combined_area;
|
| - optimal_split_index = p;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // optimal_split_index currently points at the last element in the first set,
|
| - // so advance it by 1 to point at the first element in the second set.
|
| - return optimal_split_index + 1;
|
| -}
|
| -
|
| -void RTree::Node::RecomputeBoundsNoParents() {
|
| - // Clear our rectangle, then reset it to union of our children.
|
| - rect_.SetRect(0, 0, 0, 0);
|
| - for (size_t i = 0; i < children_.size(); ++i) {
|
| - rect_.Union(children_[i]->rect_);
|
| - }
|
| -}
|
| -
|
| -RTree::RTree(size_t min_children, size_t max_children)
|
| - : root_(new Node(0)),
|
| - min_children_(min_children),
|
| - max_children_(max_children) {
|
| - // R-Trees require min_children >= 2
|
| - DCHECK_GE(min_children_, 2U);
|
| - // R-Trees also require min_children <= max_children / 2
|
| - DCHECK_LE(min_children_, max_children_ / 2U);
|
| - root_.reset(new Node(0));
|
| -}
|
| -
|
| -RTree::~RTree() {
|
| - Clear();
|
| -}
|
| -
|
| -void RTree::Insert(const Rect& rect, intptr_t key) {
|
| - // Non-NULL keys, please.
|
| - DCHECK(key);
|
| -
|
| - Node* record_node = NULL;
|
| - // Check if this key is already present in the tree.
|
| - base::hash_map<intptr_t, Node*>::iterator it = record_map_.find(key);
|
| - if (it != record_map_.end()) {
|
| - // We will re-use this node structure, regardless of re-insert or return.
|
| - record_node = it->second;
|
| - // If the new rect and the current rect are identical we can skip rest of
|
| - // Insert() as nothing has changed.
|
| - if (record_node->rect() == rect)
|
| - return;
|
| -
|
| - // Remove the node from the tree in its current position.
|
| - RemoveNode(record_node);
|
| -
|
| - // If we are replacing this key with an empty rectangle we just remove the
|
| - // old node from the list and return, thus preventing insertion of empty
|
| - // rectangles into our spatial database.
|
| - if (rect.IsEmpty()) {
|
| - record_map_.erase(it);
|
| - delete record_node;
|
| - return;
|
| - }
|
| -
|
| - // Reset the rectangle to the new value.
|
| - record_node->SetRect(rect);
|
| - } else {
|
| - if (rect.IsEmpty())
|
| - return;
|
| - // Build a new record Node for insertion in to tree.
|
| - record_node = new Node(rect, key);
|
| - // Add this new node to our map, for easy retrieval later.
|
| - record_map_.insert(std::make_pair(key, record_node));
|
| - }
|
| -
|
| - // Call internal Insert with this new node and allowing all re-inserts.
|
| - int starting_level = -1;
|
| - InsertNode(record_node, &starting_level);
|
| -}
|
| -
|
| -void RTree::Remove(intptr_t key) {
|
| - // Search the map for the leaf parent that has the provided record.
|
| - base::hash_map<intptr_t, Node*>::iterator it = record_map_.find(key);
|
| - // If not in the map it's not in the tree, we're done.
|
| - if (it == record_map_.end())
|
| - return;
|
| -
|
| - Node* node = it->second;
|
| - // Remove this node from the map.
|
| - record_map_.erase(it);
|
| - // Now remove it from the RTree.
|
| - RemoveNode(node);
|
| - delete node;
|
| -
|
| - // Lastly check the root. If it has only one non-leaf child, delete it and
|
| - // replace it with its child.
|
| - if (root_->count() == 1 && root_->level() > 0) {
|
| - root_ = root_->RemoveAndReturnLastChild();
|
| - }
|
| -}
|
| -
|
| -void RTree::Query(const Rect& query_rect,
|
| - base::hash_set<intptr_t>* matches_out) const {
|
| - root_->Query(query_rect, matches_out);
|
| -}
|
| -
|
| -void RTree::Clear() {
|
| - record_map_.clear();
|
| - root_.reset(new Node(0));
|
| -}
|
| -
|
| -void RTree::InsertNode(Node* node, int* highest_reinsert_level) {
|
| - // Find the most appropriate parent to insert node into.
|
| - Node* parent = root_->ChooseSubtree(node);
|
| - DCHECK(parent);
|
| - // Verify ChooseSubtree returned a Node at the correct level.
|
| - DCHECK_EQ(parent->level(), node->level() + 1);
|
| - Node* insert_node = node;
|
| - Node* insert_parent = parent;
|
| - Node* needs_bounds_recomputed = insert_parent->parent();
|
| - ScopedVector<Node> reinserts;
|
| - // Attempt to insert the Node, if this overflows the Node we must handle it.
|
| - while (insert_parent &&
|
| - insert_parent->AddChild(insert_node) > max_children_) {
|
| - // If we have yet to re-insert nodes at this level during this data insert,
|
| - // and we're not at the root, R*-Tree calls for re-insertion of some of the
|
| - // nodes, resulting in a better balance on the tree.
|
| - if (insert_parent->parent() &&
|
| - insert_parent->level() > *highest_reinsert_level) {
|
| - insert_parent->RemoveNodesForReinsert(max_children_ / 3, &reinserts);
|
| - // Adjust highest_reinsert_level to this level.
|
| - *highest_reinsert_level = insert_parent->level();
|
| - // We didn't create any new nodes so we have nothing new to insert.
|
| - insert_node = NULL;
|
| - // RemoveNodesForReinsert() does not recompute bounds, so mark it.
|
| - needs_bounds_recomputed = insert_parent;
|
| - break;
|
| - }
|
| -
|
| - // Split() will create a sibling to insert_parent both of which will have
|
| - // valid bounds, but this invalidates their parent's bounds.
|
| - insert_node = insert_parent->Split(min_children_, max_children_);
|
| - insert_parent = insert_parent->parent();
|
| - needs_bounds_recomputed = insert_parent;
|
| - }
|
| -
|
| - // If we have a Node to insert, and we hit the root of the current tree,
|
| - // we create a new root which is the parent of the current root and the
|
| - // insert_node
|
| - if (!insert_parent && insert_node) {
|
| - Node* old_root = root_.release();
|
| - root_.reset(new Node(old_root->level() + 1));
|
| - root_->AddChild(old_root);
|
| - root_->AddChild(insert_node);
|
| - }
|
| -
|
| - // Recompute bounds along insertion path.
|
| - if (needs_bounds_recomputed) {
|
| - needs_bounds_recomputed->RecomputeBounds();
|
| - }
|
| -
|
| - // Complete re-inserts, if any.
|
| - for (size_t i = 0; i < reinserts.size(); ++i) {
|
| - InsertNode(reinserts[i], highest_reinsert_level);
|
| - }
|
| -
|
| - // Clear out reinserts without deleting any of the children, as they have been
|
| - // re-inserted into the tree.
|
| - reinserts.weak_clear();
|
| -}
|
| -
|
| -void RTree::RemoveNode(Node* node) {
|
| - // We need to remove this node from its parent.
|
| - Node* parent = node->parent();
|
| - // Record nodes are never allowed as the root, so we should always have a
|
| - // parent.
|
| - DCHECK(parent);
|
| - // Should always be a leaf that had the record.
|
| - DCHECK_EQ(parent->level(), 0);
|
| - ScopedVector<Node> orphans;
|
| - Node* child = node;
|
| -
|
| - // Traverse up the tree, removing the child from each parent and deleting
|
| - // parent nodes, until we either encounter the root of the tree or a parent
|
| - // that still has sufficient children.
|
| - while (parent) {
|
| - size_t children_remaining = parent->RemoveChild(child, &orphans);
|
| - if (child != node)
|
| - delete child;
|
| -
|
| - if (children_remaining >= min_children_)
|
| - break;
|
| -
|
| - child = parent;
|
| - parent = parent->parent();
|
| - }
|
| -
|
| - // If we stopped deleting nodes up the tree before encountering the root,
|
| - // we'll need to fix up the bounds from the first parent we didn't delete
|
| - // up to the root.
|
| - if (parent) {
|
| - parent->RecomputeBounds();
|
| - } else {
|
| - root_->RecomputeBounds();
|
| - }
|
| -
|
| - // Now re-insert each of the orphaned nodes back into the tree.
|
| - for (size_t i = 0; i < orphans.size(); ++i) {
|
| - int starting_level = -1;
|
| - InsertNode(orphans[i], &starting_level);
|
| - }
|
| -
|
| - // Clear out the orphans list without deleting any of the children, as they
|
| - // have been re-inserted into the tree.
|
| - orphans.weak_clear();
|
| -}
|
| -
|
| -} // namespace gfx
|
|
|