choose_next_node.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // Boost.Geometry Index
  2. //
  3. // R-tree R*-tree next node choosing algorithm implementation
  4. //
  5. // Copyright (c) 2011-2019 Adam Wulkiewicz, Lodz, Poland.
  6. //
  7. // This file was modified by Oracle on 2019-2021.
  8. // Modifications copyright (c) 2019-2021 Oracle and/or its affiliates.
  9. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  10. //
  11. // Use, modification and distribution is subject to the Boost Software License,
  12. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  13. // http://www.boost.org/LICENSE_1_0.txt)
  14. #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
  15. #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
  16. #include <algorithm>
  17. #include <boost/core/ignore_unused.hpp>
  18. #include <boost/geometry/algorithms/expand.hpp>
  19. #include <boost/geometry/index/detail/algorithms/content.hpp>
  20. #include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
  21. #include <boost/geometry/index/detail/algorithms/nth_element.hpp>
  22. #include <boost/geometry/index/detail/algorithms/union_content.hpp>
  23. #include <boost/geometry/index/detail/rtree/node/node.hpp>
  24. #include <boost/geometry/index/detail/rtree/options.hpp>
  25. #include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
  26. #include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
  27. namespace boost { namespace geometry { namespace index {
  28. namespace detail { namespace rtree {
  29. template <typename MembersHolder>
  30. class choose_next_node<MembersHolder, choose_by_overlap_diff_tag>
  31. {
  32. typedef typename MembersHolder::box_type box_type;
  33. typedef typename MembersHolder::parameters_type parameters_type;
  34. typedef typename MembersHolder::node node;
  35. typedef typename MembersHolder::internal_node internal_node;
  36. typedef typename MembersHolder::leaf leaf;
  37. typedef typename rtree::elements_type<internal_node>::type children_type;
  38. typedef typename children_type::value_type child_type;
  39. typedef typename index::detail::default_content_result<box_type>::type content_type;
  40. public:
  41. template <typename Indexable>
  42. static inline size_t apply(internal_node & n,
  43. Indexable const& indexable,
  44. parameters_type const& parameters,
  45. size_t node_relative_level)
  46. {
  47. ::boost::ignore_unused(parameters);
  48. children_type & children = rtree::elements(n);
  49. // children are leafs
  50. if ( node_relative_level <= 1 )
  51. {
  52. return choose_by_minimum_overlap_cost(children, indexable,
  53. parameters.get_overlap_cost_threshold(),
  54. index::detail::get_strategy(parameters));
  55. }
  56. // children are internal nodes
  57. else
  58. {
  59. return choose_by_minimum_content_cost(children, indexable,
  60. index::detail::get_strategy(parameters));
  61. }
  62. }
  63. private:
  64. struct child_contents
  65. {
  66. content_type content_diff;
  67. content_type content;
  68. size_t i;
  69. void set(size_t i_, content_type const& content_, content_type const& content_diff_)
  70. {
  71. i = i_;
  72. content = content_;
  73. content_diff = content_diff_;
  74. }
  75. };
  76. template <typename Indexable, typename Strategy>
  77. static inline size_t choose_by_minimum_overlap_cost(children_type const& children,
  78. Indexable const& indexable,
  79. size_t overlap_cost_threshold,
  80. Strategy const& strategy)
  81. {
  82. const size_t children_count = children.size();
  83. content_type min_content_diff = (std::numeric_limits<content_type>::max)();
  84. content_type min_content = (std::numeric_limits<content_type>::max)();
  85. size_t choosen_index = 0;
  86. // create container of children sorted by content enlargement needed to include the new value
  87. typename rtree::container_from_elements_type<children_type, child_contents>::type
  88. children_contents(children_count);
  89. for ( size_t i = 0 ; i < children_count ; ++i )
  90. {
  91. child_type const& ch_i = children[i];
  92. // expanded child node's box
  93. box_type box_exp(ch_i.first);
  94. index::detail::expand(box_exp, indexable, strategy);
  95. // areas difference
  96. content_type content = index::detail::content(box_exp);
  97. content_type content_diff = content - index::detail::content(ch_i.first);
  98. children_contents[i].set(i, content, content_diff);
  99. if ( content_diff < min_content_diff ||
  100. (content_diff == min_content_diff && content < min_content) )
  101. {
  102. min_content_diff = content_diff;
  103. min_content = content;
  104. choosen_index = i;
  105. }
  106. }
  107. // is this assumption ok? if min_content_diff == 0 there is no overlap increase?
  108. if ( min_content_diff < -std::numeric_limits<double>::epsilon() || std::numeric_limits<double>::epsilon() < min_content_diff )
  109. {
  110. size_t first_n_children_count = children_count;
  111. if ( 0 < overlap_cost_threshold && overlap_cost_threshold < children.size() )
  112. {
  113. first_n_children_count = overlap_cost_threshold;
  114. // rearrange by content_diff
  115. // in order to calculate nearly minimum overlap cost
  116. index::detail::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less);
  117. }
  118. // calculate minimum or nearly minimum overlap cost
  119. choosen_index = choose_by_minimum_overlap_cost_first_n(children, indexable,
  120. first_n_children_count,
  121. children_count,
  122. children_contents,
  123. strategy);
  124. }
  125. return choosen_index;
  126. }
  127. static inline bool content_diff_less(child_contents const& p1, child_contents const& p2)
  128. {
  129. return p1.content_diff < p2.content_diff
  130. || (p1.content_diff == p2.content_diff && (p1.content) < (p2.content));
  131. }
  132. template <typename Indexable, typename ChildrenContents, typename Strategy>
  133. static inline size_t choose_by_minimum_overlap_cost_first_n(children_type const& children,
  134. Indexable const& indexable,
  135. size_t const first_n_children_count,
  136. size_t const children_count,
  137. ChildrenContents const& children_contents,
  138. Strategy const& strategy)
  139. {
  140. BOOST_GEOMETRY_INDEX_ASSERT(first_n_children_count <= children_count, "unexpected value");
  141. BOOST_GEOMETRY_INDEX_ASSERT(children_contents.size() == children_count, "unexpected number of elements");
  142. // choose index with smallest overlap change value, or content change or smallest content
  143. size_t choosen_index = 0;
  144. content_type smallest_overlap_diff = (std::numeric_limits<content_type>::max)();
  145. content_type smallest_content_diff = (std::numeric_limits<content_type>::max)();
  146. content_type smallest_content = (std::numeric_limits<content_type>::max)();
  147. // for each child node
  148. for (size_t first_i = 0 ; first_i < first_n_children_count ; ++first_i)
  149. {
  150. size_t i = children_contents[first_i].i;
  151. content_type const& content = children_contents[first_i].content;
  152. content_type const& content_diff = children_contents[first_i].content_diff;
  153. child_type const& ch_i = children[i];
  154. box_type box_exp(ch_i.first);
  155. // calculate expanded box of child node ch_i
  156. index::detail::expand(box_exp, indexable, strategy);
  157. content_type overlap_diff = 0;
  158. // calculate overlap
  159. for ( size_t j = 0 ; j < children_count ; ++j )
  160. {
  161. if ( i != j )
  162. {
  163. child_type const& ch_j = children[j];
  164. content_type overlap_exp = index::detail::intersection_content(box_exp, ch_j.first, strategy);
  165. if ( overlap_exp < -std::numeric_limits<content_type>::epsilon() || std::numeric_limits<content_type>::epsilon() < overlap_exp )
  166. {
  167. overlap_diff += overlap_exp - index::detail::intersection_content(ch_i.first, ch_j.first, strategy);
  168. }
  169. }
  170. }
  171. // update result
  172. if ( overlap_diff < smallest_overlap_diff ||
  173. ( overlap_diff == smallest_overlap_diff && ( content_diff < smallest_content_diff ||
  174. ( content_diff == smallest_content_diff && content < smallest_content ) )
  175. ) )
  176. {
  177. smallest_overlap_diff = overlap_diff;
  178. smallest_content_diff = content_diff;
  179. smallest_content = content;
  180. choosen_index = i;
  181. }
  182. }
  183. return choosen_index;
  184. }
  185. template <typename Indexable, typename Strategy>
  186. static inline size_t choose_by_minimum_content_cost(children_type const& children,
  187. Indexable const& indexable,
  188. Strategy const& strategy)
  189. {
  190. size_t children_count = children.size();
  191. // choose index with smallest content change or smallest content
  192. size_t choosen_index = 0;
  193. content_type smallest_content_diff = (std::numeric_limits<content_type>::max)();
  194. content_type smallest_content = (std::numeric_limits<content_type>::max)();
  195. // choose the child which requires smallest box expansion to store the indexable
  196. for ( size_t i = 0 ; i < children_count ; ++i )
  197. {
  198. child_type const& ch_i = children[i];
  199. // expanded child node's box
  200. box_type box_exp(ch_i.first);
  201. index::detail::expand(box_exp, indexable, strategy);
  202. // areas difference
  203. content_type content = index::detail::content(box_exp);
  204. content_type content_diff = content - index::detail::content(ch_i.first);
  205. // update the result
  206. if ( content_diff < smallest_content_diff ||
  207. ( content_diff == smallest_content_diff && content < smallest_content ) )
  208. {
  209. smallest_content_diff = content_diff;
  210. smallest_content = content;
  211. choosen_index = i;
  212. }
  213. }
  214. return choosen_index;
  215. }
  216. };
  217. }} // namespace detail::rtree
  218. }}} // namespace boost::geometry::index
  219. #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP