diff --git a/include/boost/geometry/extensions/index/rtree/rtree.hpp b/include/boost/geometry/extensions/index/rtree/rtree.hpp index f82f0e56d..2d582811e 100644 --- a/include/boost/geometry/extensions/index/rtree/rtree.hpp +++ b/include/boost/geometry/extensions/index/rtree/rtree.hpp @@ -147,7 +147,9 @@ public: , m_values_count(0) , m_leafs_level(0) , m_root(0) - {} + { + geometry::assign_inverse(m_box); + } /*! \brief The constructor. @@ -168,7 +170,9 @@ public: , m_values_count(0) , m_leafs_level(0) , m_root(0) - {} + { + geometry::assign_inverse(m_box); + } /*! \brief The constructor. @@ -197,6 +201,8 @@ public: , m_leafs_level(0) , m_root(0) { + geometry::assign_inverse(m_box); + try { this->insert(first, last); @@ -234,6 +240,8 @@ public: , m_leafs_level(0) , m_root(0) { + geometry::assign_inverse(m_box); + try { this->insert(rng); @@ -276,9 +284,9 @@ public: , m_values_count(0) , m_leafs_level(0) , m_root(0) + , m_box(src.m_box) { //TODO use Boost.Container allocator_traits_type::select_on_container_copy_construction() - this->raw_copy(src, *this, false); } @@ -303,6 +311,7 @@ public: , m_values_count(0) , m_leafs_level(0) , m_root(0) + , m_box(src.m_box) { this->raw_copy(src, *this, false); } @@ -325,6 +334,7 @@ public: , m_values_count(src.m_values_count) , m_leafs_level(src.m_leafs_level) , m_root(src.m_root) + , m_box(src.m_box) { src.m_values_count = 0; src.m_leafs_level = 0; @@ -353,6 +363,7 @@ public: , m_values_count(0) , m_leafs_level(0) , m_root(0) + , m_box(src.m_box) { if ( src.m_allocators.allocator == allocator ) { @@ -388,6 +399,8 @@ public: // It uses m_allocators this->raw_copy(src, *this, true); + m_box = src.m_box; + return *this; } @@ -432,6 +445,8 @@ public: this->raw_copy(src, *this, true); } + m_box = src.m_box; + return *this; } @@ -454,6 +469,7 @@ public: boost::swap(m_values_count, other.m_values_count); boost::swap(m_leafs_level, other.m_leafs_level); boost::swap(m_root, other.m_root); + boost::swap(m_box, other.m_box); } /*! @@ -888,6 +904,7 @@ public: inline void clear() { this->raw_destroy(*this); + geometry::assign_inverse(m_box); } /*! @@ -902,21 +919,9 @@ public: \par Throws Nothing. */ - inline box_type box() const + inline box_type const& box() const { - if ( this->empty() ) - { - box_type result; - geometry::assign_inverse(result); - return result; - } - - detail::rtree::visitors::children_box - children_box_v(m_translator); - - detail::rtree::apply_visitor(children_box_v, *m_root); - - return children_box_v.result; + return m_box; } /*! @@ -967,7 +972,7 @@ public: \par Throws Nothing. */ - inline const translator_type & translator() const + inline translator_type const& translator() const { return m_translator; } @@ -1067,6 +1072,8 @@ private: // TODO // If exception is thrown, m_values_count may be invalid ++m_values_count; + + geometry::expand(m_box, m_translator(value)); } /*! @@ -1081,7 +1088,6 @@ private: { // TODO: awulkiew - assert for correct value (indexable) ? BOOST_GEOMETRY_INDEX_ASSERT(m_root, "The root must exist"); - BOOST_GEOMETRY_INDEX_ASSERT(0 < m_values_count, "can't remove, there are no elements in the rtree"); detail::rtree::visitors::remove< value_type, options_type, translator_type, box_type, allocators_type @@ -1089,15 +1095,31 @@ private: detail::rtree::apply_visitor(remove_v, *m_root); -// TODO -// Think about this: If exception is thrown, may the root be removed? -// Or it is just cleared? + // If exception is thrown, m_values_count may be invalid -// TODO -// If exception is thrown, m_values_count may be invalid - --m_values_count; + if ( remove_v.is_value_removed() ) + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_values_count, "unexpected state"); - return remove_v.is_value_removed() ? 1 : 0; + --m_values_count; + + // Calculate new box + if ( m_values_count == 0 ) + { + geometry::assign_inverse(m_box); + } + else + { + detail::rtree::visitors::children_box + children_box_v(m_box, m_translator); + + detail::rtree::apply_visitor(children_box_v, *m_root); + } + + return 1; + } + + return 0; } /*! @@ -1259,6 +1281,8 @@ private: size_type m_values_count; size_type m_leafs_level; node * m_root; + + box_type m_box; }; /*! @@ -1540,7 +1564,7 @@ It calls \c rtree::box(). \return The box containing all stored values or an invalid box. */ template -inline typename rtree::box_type +inline typename rtree::box_type const& box(rtree const& tree) { return tree.box(); @@ -1548,44 +1572,73 @@ box(rtree const& tree) }}} // namespace boost::geometry::index -#include +// Rtree adaptation to Box concept namespace boost { namespace geometry { -/*! -\brief Get the box containing all stored values or an invalid box if the index has no values. - -It calls \c rtree::box(). - -\ingroup rtree_functions - -\param tree The spatial index. -\param box The object to which box containing all stored values or an invalid box will be assigned. -*/ -template -void envelope(index::rtree const& tree, Box & box) +// Traits specializations for box above +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits { - envelope(tree.box(), box); -} -/*! -\brief Get the box containing all stored values or an invalid box if the index has no values. - -It calls \c rtree::box(). - -\ingroup rtree_functions - -\tparam Box The type of returned Box. - -\param tree The spatial index. - -\return The box containing all stored values or an invalid box. -*/ -template -Box return_envelope(index::rtree const& tree) +template +struct tag< index::rtree > { - return return_envelope(tree.box()); -} + typedef box_tag type; +}; + +template +struct point_type< index::rtree > +{ + typedef typename geometry::point_type< + typename index::rtree::box_type + >::type type; +}; + +template +struct indexed_access, min_corner, Dimension> +{ + typedef typename geometry::coordinate_type< + typename geometry::point_type< + index::rtree + >::type + >::type coordinate_type; + + static inline coordinate_type get(index::rtree const& tree) + { + return geometry::get(tree.box()); + } + + static inline void set(index::rtree & tree, + coordinate_type const& value) + { + return geometry::set(tree.box(), value); + } +}; + +template +struct indexed_access, max_corner, Dimension> +{ + typedef typename geometry::coordinate_type< + typename geometry::point_type< + index::rtree + >::type + >::type coordinate_type; + + static inline coordinate_type get(index::rtree const& tree) + { + return geometry::get(tree.box()); + } + + static inline void set(index::rtree & tree, + coordinate_type const& value) + { + return geometry::set(tree.box(), value); + } +}; + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS }} //namespace boost::geometry diff --git a/include/boost/geometry/extensions/index/rtree/visitors/children_box.hpp b/include/boost/geometry/extensions/index/rtree/visitors/children_box.hpp index 860d5e9cc..5f83cf909 100644 --- a/include/boost/geometry/extensions/index/rtree/visitors/children_box.hpp +++ b/include/boost/geometry/extensions/index/rtree/visitors/children_box.hpp @@ -26,8 +26,8 @@ class children_box typedef typename rtree::leaf::type leaf; public: - inline children_box(Translator const& tr) - : m_tr(tr) + inline children_box(Box & result, Translator const& tr) + : m_result(result), m_tr(tr) {} inline void operator()(internal_node const& n) @@ -35,7 +35,7 @@ public: typedef typename rtree::elements_type::type elements_type; elements_type const& elements = rtree::elements(n); - result = rtree::elements_box(elements.begin(), elements.end(), m_tr); + m_result = rtree::elements_box(elements.begin(), elements.end(), m_tr); } inline void operator()(leaf const& n) @@ -43,12 +43,11 @@ public: typedef typename rtree::elements_type::type elements_type; elements_type const& elements = rtree::elements(n); - result = rtree::elements_box(elements.begin(), elements.end(), m_tr); + m_result = rtree::elements_box(elements.begin(), elements.end(), m_tr); } - Box result; - private: + Box & m_result; Translator const& m_tr; }; diff --git a/test/rtree/test_rtree.hpp b/test/rtree/test_rtree.hpp index 9c32a4711..04071b432 100644 --- a/test/rtree/test_rtree.hpp +++ b/test/rtree/test_rtree.hpp @@ -1049,6 +1049,7 @@ void test_remove(bgi::rtree & tree, Box const& qbox) std::vector expected_output; tree.spatial_query(bgi::disjoint(qbox), std::back_inserter(expected_output)); size_t expected_removed_count = values_to_remove.size(); + size_t expected_size_after_remove = tree.size() - values_to_remove.size(); // Add value which is not stored in the Rtree Value outsider = generate_value_outside(); @@ -1062,6 +1063,7 @@ void test_remove(bgi::rtree & tree, Box const& qbox) BOOST_CHECK( r == expected_removed_count ); std::vector output; t.spatial_query(bgi::disjoint(qbox), std::back_inserter(output)); + BOOST_CHECK( t.size() == expected_size_after_remove ); BOOST_CHECK( output.size() == tree.size() - expected_removed_count ); test_compare_outputs(t, output, expected_output); } @@ -1071,6 +1073,7 @@ void test_remove(bgi::rtree & tree, Box const& qbox) BOOST_CHECK( r == expected_removed_count ); std::vector output; t.spatial_query(bgi::disjoint(qbox), std::back_inserter(output)); + BOOST_CHECK( t.size() == expected_size_after_remove ); BOOST_CHECK( output.size() == tree.size() - expected_removed_count ); test_compare_outputs(t, output, expected_output); } @@ -1080,6 +1083,7 @@ void test_remove(bgi::rtree & tree, Box const& qbox) BOOST_CHECK( r == expected_removed_count ); std::vector output; t.spatial_query(bgi::disjoint(qbox), std::back_inserter(output)); + BOOST_CHECK( t.size() == expected_size_after_remove ); BOOST_CHECK( output.size() == tree.size() - expected_removed_count ); test_compare_outputs(t, output, expected_output); } @@ -1092,6 +1096,7 @@ void test_remove(bgi::rtree & tree, Box const& qbox) BOOST_CHECK( r == expected_removed_count ); std::vector output; bgi::spatial_query(t, bgi::disjoint(qbox), std::back_inserter(output)); + BOOST_CHECK( t.size() == expected_size_after_remove ); BOOST_CHECK( output.size() == tree.size() - expected_removed_count ); test_compare_outputs(t, output, expected_output); } @@ -1101,6 +1106,7 @@ void test_remove(bgi::rtree & tree, Box const& qbox) BOOST_CHECK( r == expected_removed_count ); std::vector output; bgi::spatial_query(t, bgi::disjoint(qbox), std::back_inserter(output)); + BOOST_CHECK( t.size() == expected_size_after_remove ); BOOST_CHECK( output.size() == tree.size() - expected_removed_count ); test_compare_outputs(t, output, expected_output); } @@ -1110,6 +1116,7 @@ void test_remove(bgi::rtree & tree, Box const& qbox) BOOST_CHECK( r == expected_removed_count ); std::vector output; bgi::spatial_query(t, bgi::disjoint(qbox), std::back_inserter(output)); + BOOST_CHECK( t.size() == expected_size_after_remove ); BOOST_CHECK( output.size() == tree.size() - expected_removed_count ); test_compare_outputs(t, output, expected_output); } @@ -1265,6 +1272,64 @@ void test_rtree_count(Parameters const& parameters) BOOST_CHECK(t.count(input[0].first) == 3); } +// test rtree box + +template +void test_rtree_box(Parameters const& parameters) +{ + typedef bgi::rtree Tree; + typedef typename Tree::box_type B; + typedef typename bg::traits::point_type::type P; + + B b; + bg::assign_inverse(b); + + Tree t(parameters); + std::vector input; + B qbox; + + BOOST_CHECK(bg::equals(t.box(), b)); + + generate_rtree(t, input, qbox); + + BOOST_FOREACH(Value const& v, input) + bg::expand(b, t.translator()(v)); + + BOOST_CHECK(bg::equals(t.box(), b)); + + //BOOST_CHECK(bg::equals(bg::return_envelope(t), b)); + //BOOST_CHECK(bg::area(t) == bg::area(b)); + //BOOST_CHECK(bg::perimeter(t) == bg::perimeter(b)); + //BOOST_CHECK(bg::equals(bg::return_centroid

(t), bg::return_centroid

(b))); + + size_t s = input.size(); + while ( s/2 < input.size() && !input.empty() ) + { + t.remove(input.back()); + input.pop_back(); + } + + bg::assign_inverse(b); + BOOST_FOREACH(Value const& v, input) + bg::expand(b, t.translator()(v)); + + BOOST_CHECK(bg::equals(t.box(), b)); + + Tree t2(t); + BOOST_CHECK(bg::equals(t2.box(), b)); + t2.clear(); + t2 = t; + BOOST_CHECK(bg::equals(t2.box(), b)); + t2.clear(); + t2 = boost::move(t); + BOOST_CHECK(bg::equals(t2.box(), b)); + + t.clear(); + + bg::assign_inverse(b); + BOOST_CHECK(bg::equals(t.box(), b)); +} + // run all tests for one Algorithm for some number of rtrees // defined by some number of Values constructed from given Point @@ -1286,6 +1351,7 @@ void test_rtree_for_point(Parameters const& parameters = Parameters()) test_count_rtree_values(parameters); test_rtree_count(parameters); + test_rtree_box(parameters); } template @@ -1305,6 +1371,7 @@ void test_rtree_for_box(Parameters const& parameters = Parameters()) test_count_rtree_values(parameters); test_rtree_count(parameters); + test_rtree_box(parameters); } #endif