// Boost.Geometry (aka GGL, Generic Geometry Library) // Boost.SpatialIndex - rtree node implementation // // Copyright 2008 Federico J. Fernandez. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_NODE_HPP #define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_NODE_HPP #include #include // TODO: Remove if print() is removed #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { namespace index { /// forward declaration template class rtree_leaf; template class rtree_node { public: typedef std::shared_ptr > node_pointer; typedef std::shared_ptr > leaf_pointer; /// type for the node map typedef std::vector > node_map; /** * \brief Creates a default node (needed for the containers) */ rtree_node() { } /** * \brief Creates a node with 'parent' as parent and 'level' as its level */ rtree_node(node_pointer const& parent, unsigned int const& level) : m_parent(parent), m_level(level) { } /** * \brief destructor (virtual because we have virtual functions) */ virtual ~rtree_node() { } /** * \brief Level projector */ virtual unsigned int get_level() const { return m_level; } /** * \brief Number of elements in the subtree */ virtual unsigned int elements() const { return m_nodes.size(); } /** * \brief Project first element, to replace root in case of condensing */ inline node_pointer first_element() const { if (0 == m_nodes.size()) { // TODO: mloskot - define & use GGL exception throw std::logic_error("first_element in empty node"); } return m_nodes.begin()->second; } /** * \brief True if it is a leaf node */ virtual bool is_leaf() const { return false; } /** * \brief Proyector for the 'i' node */ node_pointer get_node(unsigned int index) { return m_nodes[index].second; } /** * \brief Search for elements in 'box' in the Rtree. Add them to 'result'. * If exact_match is true only return the elements having as * key the box 'box'. Otherwise return everything inside 'box'. */ virtual void find(Box const& box, std::deque& result, bool const exact_match) { for (typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { if (is_overlapping(it->first, box)) { it->second->find(box, result, exact_match); } } } /** * \brief Return in 'result' all the leaves inside 'box' */ void find_leaves(Box const& box, typename std::vector& result) const { for (typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { if (is_overlapping(it->first, box)) { if (it->second->is_leaf()) { result.push_back(it->second); } else { it->second->find_leaves(box, result); } } } } /** * \brief Compute bounding box for this node */ virtual Box compute_box() const { if (m_nodes.empty()) { return Box(); } Box result; geometry::assign_inverse(result); for(typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { geometry::expand(result, it->first); } return result; } /** * \brief Insert a value (not allowed for a node, only on leaves) */ virtual void insert(Box const&, Value const&) { // TODO: mloskot - define & use GGL exception throw std::logic_error("Insert in node!"); } /** * \brief Get the envelopes of a node */ virtual std::vector get_boxes() const { std::vector result; for(typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { result.push_back(it->first); } return result; } /** * \brief Recompute the bounding box */ void adjust_box(node_pointer const& node) { unsigned int index = 0; for (typename node_map::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it, index++) { if (it->second.get() == node.get()) { m_nodes[index] = std::make_pair(node->compute_box(), node); return; } } } /** * \brief Remove elements inside the 'box' */ virtual void remove(Box const& box) { for (typename node_map::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { if (geometry::equals(it->first, box)) { m_nodes.erase(it); return; } } } /** * \brief Remove value in this leaf */ virtual void remove(Value const&) { // TODO: mloskot - define & use GGL exception throw std::logic_error("Can't remove a non-leaf node by value."); } /** * \brief Replace the node in the m_nodes vector and recompute the box */ void replace_node(node_pointer const& leaf, node_pointer& new_leaf) { unsigned int index = 0; for(typename node_map::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it, index++) { if (it->second.get() == leaf.get()) { m_nodes[index] = std::make_pair(new_leaf->compute_box(), new_leaf); new_leaf->update_parent(new_leaf); return; } } // TODO: mloskot - define & use GGL exception throw std::logic_error("Node not found."); } /** * \brief Add a child to this node */ virtual void add_node(Box const& box, node_pointer const& node) { m_nodes.push_back(std::make_pair(box, node)); node->update_parent(node); } /** * \brief add a value (not allowed in nodes, only on leaves) */ virtual void add_value(Box const&, Value const&) { // TODO: mloskot - define & use GGL exception throw std::logic_error("Can't add value to non-leaf node."); } /** * \brief Add a child leaf to this node */ inline void add_leaf_node(Box const& box, leaf_pointer const& leaf) { m_nodes.push_back(std::make_pair(box, leaf)); } /** * \brief Choose a node suitable for adding 'box' */ node_pointer choose_node(Box const& box) { if (m_nodes.size() == 0) { // TODO: mloskot - define & use GGL exception throw std::logic_error("Empty node trying to choose the least enlargement node."); } typedef typename coordinate_type::type coordinate_type; bool first = true; coordinate_type min_area = 0; coordinate_type min_diff_area = 0; node_pointer chosen_node; // check for the least enlargement for (typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { coordinate_type const diff_area = coordinate_type(compute_union_area(box, it->first)) - geometry::area(it->first); if (first) { // it's the first time, we keep the first min_diff_area = diff_area; min_area = geometry::area(it->first); chosen_node = it->second; first = false; } else { if (diff_area < min_diff_area) { min_diff_area = diff_area; min_area = geometry::area(it->first); chosen_node = it->second; } else { if (diff_area == min_diff_area) { if (geometry::area(it->first) < min_area) { min_diff_area = diff_area; min_area = geometry::area(it->first); chosen_node = it->second; } } } } } return chosen_node; } /** * \brief Empty the node */ virtual void empty_nodes() { m_nodes.clear(); } /** * \brief Projector for parent */ inline node_pointer get_parent() const { return m_parent; } /** * \brief Update the parent of all the childs */ void update_parent(node_pointer const& node) { for (typename node_map::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { it->second->set_parent(node); } } /** * \brief Set parent */ void set_parent(node_pointer const& node) { m_parent = node; } /** * \brief Value projector for leaf_node (not allowed for non-leaf nodes) */ virtual Value get_value(unsigned int) const { // TODO: mloskot - define & use GGL exception throw std::logic_error("No values in a non-leaf node."); } /** * \brief Box projector for node 'index' */ virtual Box get_box(unsigned int index) const { return m_nodes[index].first; } /** * \brief Box projector for node pointed by 'leaf' */ virtual Box get_box(node_pointer const& leaf) const { for (typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { if (it->second.get() == leaf.get()) { return it->first; } } // TODO: mloskot - define & use GGL exception throw std::logic_error("Node not found"); } /** * \brief Children projector */ node_map get_nodes() const { return m_nodes; } /** * \brief Get leaves for a node */ virtual std::vector > get_leaves() const { typedef std::vector > leaf_type; leaf_type leaf; for (typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { leaf_type this_leaves = it->second->get_leaves(); for (typename leaf_type::iterator it_leaf = this_leaves.begin(); it_leaf != this_leaves.end(); ++it_leaf) { leaf.push_back(*it_leaf); } } return leaf; } /** * \brief Print Rtree subtree (mainly for debug) */ virtual void print() const { std::cerr << " --> Node --------" << std::endl; std::cerr << " Address: " << this << std::endl; std::cerr << " Level: " << m_level << std::endl; std::cerr << " Size: " << m_nodes.size() << std::endl; std::cerr << " | "; for(typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { if (this != it->second->get_parent().get()) { std::cerr << "ERROR - " << this << " is not " << it->second->get_parent().get() << " "; } std::cerr << "( " << geometry::get(it->first) << " , " << geometry::get(it->first) << " ) x "; std::cerr << "( " << geometry::get(it->first) << " , " << geometry::get(it->first) << " )"; std::cerr << " | "; } std::cerr << std::endl; std::cerr << " --< Node --------" << std::endl; // print child nodes std::cerr << " Children: " << std::endl; for (typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) { it->second->print(); } } private: /// parent node node_pointer m_parent; /// level of this node // TODO: mloskot - Why not std::size_t or node_map::size_type, same with member functions? unsigned int m_level; /// child nodes node_map m_nodes; }; }}} // namespace boost::geometry::index #endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_NODE_HPP