From bfd0052905a6773207691b2e32b6420b036dcff0 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 10 Jun 2013 15:55:45 +0000 Subject: [PATCH] geometry.index: packer replaced by pack, various tweaks added. [SVN r84730] --- .../index/detail/rtree/pack_create.hpp | 124 +++++++++++------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/include/boost/geometry/index/detail/rtree/pack_create.hpp b/include/boost/geometry/index/detail/rtree/pack_create.hpp index 2c75fca64..3273a6ccc 100644 --- a/include/boost/geometry/index/detail/rtree/pack_create.hpp +++ b/include/boost/geometry/index/detail/rtree/pack_create.hpp @@ -105,9 +105,17 @@ struct partial_sort_and_half_boxes // it is more similar to the top-down recursive kd-tree creation algorithm // using object median split and split axis of greatest BB edge // BB is only used as a hint (assuming objects are distributed uniformly) +// +// Implemented algorithm guarantees that the number of elements in nodes will be between Min and Max +// and that nodes are packed as tightly as possible +// e.g. for 177 values Max = 5 and Min = 2 it will construct the following tree: +// ROOT 177 +// L1 125 52 +// L2 25 25 25 25 25 25 17 10 +// L3 5x5 5x5 5x5 5x5 5x5 5x5 3x5+2 2x5 template -class packer +class pack { typedef typename rtree::node::type node; typedef typename rtree::internal_node::type internal_node; @@ -130,34 +138,37 @@ class packer typedef typename internal_elements::value_type internal_element; public: - packer(parameters_type const& p, Translator const& tr, Allocators & al) : m_parameters(p), m_translator(tr), m_allocators(al) {} - // Arbitrary iterators - template - node_pointer pack(InIt first, InIt last) + template inline static + node_pointer apply(InIt first, InIt last, + parameters_type const& parameters, Translator const& translator, Allocators & allocators) { + typedef typename std::iterator_traits::difference_type diff_type; + + diff_type diff = std::distance(first, last); + if ( diff <= 0 ) + return node_pointer(0); + typedef std::pair entry_type; std::vector entries; - // TODO if RandomAccess - // count = distance(first, last); - // reserve(count); - + std::size_t values_count = static_cast(diff); + entries.reserve(values_count); + Box hint_box; geometry::assign_inverse(hint_box); - - std::size_t count = 0; - for ( ; first != last ; ++first, ++count ) + for ( ; first != last ; ++first ) { - geometry::expand(hint_box, m_translator(*first)); + geometry::expand(hint_box, translator(*first)); point_type pt; - geometry::centroid(m_translator(*first), pt); + geometry::centroid(translator(*first), pt); entries.push_back(std::make_pair(pt, first)); } - subtree_elements_counts subtree_counts = calculate_subtree_elements_counts(count); - internal_element el = per_level(entries.begin(), entries.end(), hint_box, count, subtree_counts); + subtree_elements_counts subtree_counts = calculate_subtree_elements_counts(values_count, parameters); + internal_element el = per_level(entries.begin(), entries.end(), hint_box, values_count, subtree_counts, + parameters, translator, allocators); return el.second; } @@ -169,80 +180,84 @@ private: std::size_t minc; }; - template - internal_element per_level(EIt first, EIt last, Box const& hint_box, std::size_t count, subtree_elements_counts const& subtree_counts) + template inline static + internal_element per_level(EIt first, EIt last, Box const& hint_box, std::size_t values_count, subtree_elements_counts const& subtree_counts, + parameters_type const& parameters, Translator const& translator, Allocators & allocators) { - // remove it later - BOOST_ASSERT(first <= last); BOOST_ASSERT(last - first == typename std::iterator_traits::difference_type(count)); + BOOST_ASSERT(first < last); + BOOST_ASSERT(last - first == values_count); if ( subtree_counts.maxc <= 1 ) { // ROOT or LEAF - BOOST_ASSERT(count <= m_parameters.get_max_elements()); + BOOST_ASSERT(values_count <= parameters.get_max_elements()); // if !root check m_parameters.get_min_elements() <= count // create new leaf node - node_pointer n = rtree::create_node::apply(m_allocators); // MAY THROW (A) + node_pointer n = rtree::create_node::apply(allocators); // MAY THROW (A) leaf & l = rtree::get(*n); // reserve space for values - rtree::elements(l).reserve(count); // MAY THROW (A) + rtree::elements(l).reserve(values_count); // MAY THROW (A) // calculate values box and copy values Box elements_box; geometry::assign_inverse(elements_box); for ( ; first != last ; ++first ) { rtree::elements(l).push_back(*(first->second)); // MAY THROW (C) - geometry::expand(elements_box, m_translator(*(first->second))); + geometry::expand(elements_box, translator(*(first->second))); } return internal_element(elements_box, n); } // calculate next max and min subtree counts subtree_elements_counts next_subtree_counts = subtree_counts; - next_subtree_counts.maxc /= m_parameters.get_max_elements(); - next_subtree_counts.minc /= m_parameters.get_max_elements(); + next_subtree_counts.maxc /= parameters.get_max_elements(); + next_subtree_counts.minc /= parameters.get_max_elements(); // create new internal node - node_pointer n = rtree::create_node::apply(m_allocators); // MAY THROW (A) + node_pointer n = rtree::create_node::apply(allocators); // MAY THROW (A) internal_node & in = rtree::get(*n); // reserve space for values - rtree::elements(in).reserve(calculate_nodes_count(count, subtree_counts)); // MAY THROW (A) + std::size_t nodes_count = calculate_nodes_count(values_count, subtree_counts); + rtree::elements(in).reserve(nodes_count); // MAY THROW (A) // calculate values box and copy values Box elements_box; geometry::assign_inverse(elements_box); - per_level_packets(first, last, - hint_box, - subtree_counts, - next_subtree_counts, - rtree::elements(in), elements_box); + per_level_packets(first, last, hint_box, values_count, subtree_counts, next_subtree_counts, + rtree::elements(in), elements_box, + parameters, translator, allocators); return internal_element(elements_box, n); } - template - void per_level_packets(EIt first, EIt last, - Box const& hint_box, + template inline static + void per_level_packets(EIt first, EIt last, Box const& hint_box, + std::size_t values_count, subtree_elements_counts const& subtree_counts, subtree_elements_counts const& next_subtree_counts, - internal_elements & elements, Box & elements_box) + internal_elements & elements, Box & elements_box, + parameters_type const& parameters, Translator const& translator, Allocators & allocators) { - std::size_t values_count = last - first; + BOOST_ASSERT(first < last); + BOOST_ASSERT(last - first == values_count); - BOOST_ASSERT_MSG( subtree_counts.minc <= values_count, "invalid min counter" ); + BOOST_ASSERT_MSG( subtree_counts.minc <= values_count, "too small number of elements"); // only one packet if ( values_count <= subtree_counts.maxc ) { // the end, move to the next level - internal_element el = per_level(first, last, hint_box, values_count, next_subtree_counts); + internal_element el = per_level(first, last, hint_box, values_count, next_subtree_counts, + parameters, translator, allocators); // this container should have memory allocated, reserve() called outside elements.push_back(el); // SHOULDN'T THROW (C) geometry::expand(elements_box, el.first); return; } - EIt median = first + calculate_median_count(values_count, subtree_counts); + std::size_t median_count = calculate_median_count(values_count, subtree_counts); + EIt median = first + median_count; coordinate_type greatest_length; std::size_t greatest_dim_index = 0; @@ -251,23 +266,33 @@ private: pack_utils::partial_sort_and_half_boxes<0, dimension> ::apply(first, median, last, hint_box, left, right, greatest_dim_index); - per_level_packets(first, median, left, subtree_counts, next_subtree_counts, elements, elements_box); - per_level_packets(median, last, right, subtree_counts, next_subtree_counts, elements, elements_box); + per_level_packets(first, median, left, + median_count, subtree_counts, next_subtree_counts, + elements, elements_box, + parameters, translator, allocators); + per_level_packets(median, last, right, + values_count - median_count, subtree_counts, next_subtree_counts, + elements, elements_box, + parameters, translator, allocators); } - subtree_elements_counts calculate_subtree_elements_counts(std::size_t elements_count) + inline static + subtree_elements_counts calculate_subtree_elements_counts(std::size_t elements_count, parameters_type const& parameters) { + (void)parameters; + subtree_elements_counts res(1, 1); - std::size_t smax = m_parameters.get_max_elements(); - for ( ; smax < elements_count ; smax *= m_parameters.get_max_elements() ) + std::size_t smax = parameters.get_max_elements(); + for ( ; smax < elements_count ; smax *= parameters.get_max_elements() ) res.maxc = smax; - res.minc = m_parameters.get_min_elements() * (res.maxc / m_parameters.get_max_elements()); + res.minc = parameters.get_min_elements() * (res.maxc / parameters.get_max_elements()); return res; } + inline static std::size_t calculate_nodes_count(std::size_t count, subtree_elements_counts const& subtree_counts) { @@ -288,6 +313,7 @@ private: return n; } + inline static std::size_t calculate_median_count(std::size_t count, subtree_elements_counts const& subtree_counts) { @@ -327,10 +353,6 @@ private: return median_count; } - - parameters_type const& m_parameters; - Translator const& m_translator; - Allocators & m_allocators; }; }}}}} // namespace boost::geometry::index::detail::rtree