redistribute_elements.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. // Boost.Geometry Index
  2. //
  3. // R-tree R*-tree split algorithm implementation
  4. //
  5. // Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
  6. //
  7. // This file was modified by Oracle on 2019.
  8. // Modifications copyright (c) 2019 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_REDISTRIBUTE_ELEMENTS_HPP
  15. #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
  16. #include <boost/core/ignore_unused.hpp>
  17. #include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
  18. #include <boost/geometry/index/detail/algorithms/margin.hpp>
  19. #include <boost/geometry/index/detail/algorithms/nth_element.hpp>
  20. #include <boost/geometry/index/detail/algorithms/union_content.hpp>
  21. #include <boost/geometry/index/detail/bounded_view.hpp>
  22. #include <boost/geometry/index/detail/rtree/node/node.hpp>
  23. #include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
  24. #include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
  25. namespace boost { namespace geometry { namespace index {
  26. namespace detail { namespace rtree {
  27. namespace rstar {
  28. template <typename Element, typename Parameters, typename Translator, typename Tag, size_t Corner, size_t AxisIndex>
  29. class element_axis_corner_less
  30. {
  31. typedef typename rtree::element_indexable_type<Element, Translator>::type indexable_type;
  32. typedef typename geometry::point_type<indexable_type>::type point_type;
  33. typedef geometry::model::box<point_type> bounds_type;
  34. typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
  35. typedef index::detail::bounded_view
  36. <
  37. indexable_type, bounds_type, strategy_type
  38. > bounded_view_type;
  39. public:
  40. element_axis_corner_less(Translator const& tr, strategy_type const& strategy)
  41. : m_tr(tr), m_strategy(strategy)
  42. {}
  43. bool operator()(Element const& e1, Element const& e2) const
  44. {
  45. bounded_view_type bounded_ind1(rtree::element_indexable(e1, m_tr), m_strategy);
  46. bounded_view_type bounded_ind2(rtree::element_indexable(e2, m_tr), m_strategy);
  47. return geometry::get<Corner, AxisIndex>(bounded_ind1)
  48. < geometry::get<Corner, AxisIndex>(bounded_ind2);
  49. }
  50. private:
  51. Translator const& m_tr;
  52. strategy_type const& m_strategy;
  53. };
  54. template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
  55. class element_axis_corner_less<Element, Parameters, Translator, box_tag, Corner, AxisIndex>
  56. {
  57. typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
  58. public:
  59. element_axis_corner_less(Translator const& tr, strategy_type const&)
  60. : m_tr(tr)
  61. {}
  62. bool operator()(Element const& e1, Element const& e2) const
  63. {
  64. return geometry::get<Corner, AxisIndex>(rtree::element_indexable(e1, m_tr))
  65. < geometry::get<Corner, AxisIndex>(rtree::element_indexable(e2, m_tr));
  66. }
  67. private:
  68. Translator const& m_tr;
  69. };
  70. template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
  71. class element_axis_corner_less<Element, Parameters, Translator, point_tag, Corner, AxisIndex>
  72. {
  73. typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
  74. public:
  75. element_axis_corner_less(Translator const& tr, strategy_type const& )
  76. : m_tr(tr)
  77. {}
  78. bool operator()(Element const& e1, Element const& e2) const
  79. {
  80. return geometry::get<AxisIndex>(rtree::element_indexable(e1, m_tr))
  81. < geometry::get<AxisIndex>(rtree::element_indexable(e2, m_tr));
  82. }
  83. private:
  84. Translator const& m_tr;
  85. };
  86. template <typename Box, size_t Corner, size_t AxisIndex>
  87. struct choose_split_axis_and_index_for_corner
  88. {
  89. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  90. typedef typename index::detail::default_content_result<Box>::type content_type;
  91. template <typename Elements, typename Parameters, typename Translator>
  92. static inline void apply(Elements const& elements,
  93. size_t & choosen_index,
  94. margin_type & sum_of_margins,
  95. content_type & smallest_overlap,
  96. content_type & smallest_content,
  97. Parameters const& parameters,
  98. Translator const& translator)
  99. {
  100. typedef typename Elements::value_type element_type;
  101. typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
  102. typedef typename tag<indexable_type>::type indexable_tag;
  103. BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements");
  104. typename index::detail::strategy_type<Parameters>::type const&
  105. strategy = index::detail::get_strategy(parameters);
  106. // copy elements
  107. Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy)
  108. size_t const index_first = parameters.get_min_elements();
  109. size_t const index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2;
  110. // sort elements
  111. element_axis_corner_less
  112. <
  113. element_type, Parameters, Translator, indexable_tag, Corner, AxisIndex
  114. > elements_less(translator, strategy);
  115. std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
  116. // {
  117. // typename Elements::iterator f = elements_copy.begin() + index_first;
  118. // typename Elements::iterator l = elements_copy.begin() + index_last;
  119. // // NOTE: for stdlibc++ shipped with gcc 4.8.2 std::nth_element is replaced with std::sort anyway
  120. // index::detail::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
  121. // index::detail::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
  122. // std::sort(f, l, elements_less); // MAY THROW, BASIC (copy)
  123. // }
  124. // init outputs
  125. choosen_index = index_first;
  126. sum_of_margins = 0;
  127. smallest_overlap = (std::numeric_limits<content_type>::max)();
  128. smallest_content = (std::numeric_limits<content_type>::max)();
  129. // calculate sum of margins for all distributions
  130. for ( size_t i = index_first ; i < index_last ; ++i )
  131. {
  132. // TODO - awulkiew: may be optimized - box of group 1 may be initialized with
  133. // box of min_elems number of elements and expanded for each iteration by another element
  134. Box box1 = rtree::elements_box<Box>(elements_copy.begin(), elements_copy.begin() + i,
  135. translator, strategy);
  136. Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(),
  137. translator, strategy);
  138. sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2);
  139. content_type ovl = index::detail::intersection_content(box1, box2, strategy);
  140. content_type con = index::detail::content(box1) + index::detail::content(box2);
  141. // TODO - shouldn't here be < instead of <= ?
  142. if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) )
  143. {
  144. choosen_index = i;
  145. smallest_overlap = ovl;
  146. smallest_content = con;
  147. }
  148. }
  149. ::boost::ignore_unused(parameters);
  150. }
  151. };
  152. //template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
  153. //struct choose_split_axis_and_index_for_axis
  154. //{
  155. // BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (ElementIndexableTag));
  156. //};
  157. template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
  158. struct choose_split_axis_and_index_for_axis
  159. {
  160. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  161. typedef typename index::detail::default_content_result<Box>::type content_type;
  162. template <typename Elements, typename Parameters, typename Translator>
  163. static inline void apply(Elements const& elements,
  164. size_t & choosen_corner,
  165. size_t & choosen_index,
  166. margin_type & sum_of_margins,
  167. content_type & smallest_overlap,
  168. content_type & smallest_content,
  169. Parameters const& parameters,
  170. Translator const& translator)
  171. {
  172. size_t index1 = 0;
  173. margin_type som1 = 0;
  174. content_type ovl1 = (std::numeric_limits<content_type>::max)();
  175. content_type con1 = (std::numeric_limits<content_type>::max)();
  176. choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
  177. ::apply(elements, index1,
  178. som1, ovl1, con1,
  179. parameters, translator); // MAY THROW, STRONG
  180. size_t index2 = 0;
  181. margin_type som2 = 0;
  182. content_type ovl2 = (std::numeric_limits<content_type>::max)();
  183. content_type con2 = (std::numeric_limits<content_type>::max)();
  184. choose_split_axis_and_index_for_corner<Box, max_corner, AxisIndex>
  185. ::apply(elements, index2,
  186. som2, ovl2, con2,
  187. parameters, translator); // MAY THROW, STRONG
  188. sum_of_margins = som1 + som2;
  189. if ( ovl1 < ovl2 || (ovl1 == ovl2 && con1 <= con2) )
  190. {
  191. choosen_corner = min_corner;
  192. choosen_index = index1;
  193. smallest_overlap = ovl1;
  194. smallest_content = con1;
  195. }
  196. else
  197. {
  198. choosen_corner = max_corner;
  199. choosen_index = index2;
  200. smallest_overlap = ovl2;
  201. smallest_content = con2;
  202. }
  203. }
  204. };
  205. template <typename Box, size_t AxisIndex>
  206. struct choose_split_axis_and_index_for_axis<Box, AxisIndex, point_tag>
  207. {
  208. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  209. typedef typename index::detail::default_content_result<Box>::type content_type;
  210. template <typename Elements, typename Parameters, typename Translator>
  211. static inline void apply(Elements const& elements,
  212. size_t & choosen_corner,
  213. size_t & choosen_index,
  214. margin_type & sum_of_margins,
  215. content_type & smallest_overlap,
  216. content_type & smallest_content,
  217. Parameters const& parameters,
  218. Translator const& translator)
  219. {
  220. choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
  221. ::apply(elements, choosen_index,
  222. sum_of_margins, smallest_overlap, smallest_content,
  223. parameters, translator); // MAY THROW, STRONG
  224. choosen_corner = min_corner;
  225. }
  226. };
  227. template <typename Box, size_t Dimension>
  228. struct choose_split_axis_and_index
  229. {
  230. BOOST_STATIC_ASSERT(0 < Dimension);
  231. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  232. typedef typename index::detail::default_content_result<Box>::type content_type;
  233. template <typename Elements, typename Parameters, typename Translator>
  234. static inline void apply(Elements const& elements,
  235. size_t & choosen_axis,
  236. size_t & choosen_corner,
  237. size_t & choosen_index,
  238. margin_type & smallest_sum_of_margins,
  239. content_type & smallest_overlap,
  240. content_type & smallest_content,
  241. Parameters const& parameters,
  242. Translator const& translator)
  243. {
  244. typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
  245. choose_split_axis_and_index<Box, Dimension - 1>
  246. ::apply(elements, choosen_axis, choosen_corner, choosen_index,
  247. smallest_sum_of_margins, smallest_overlap, smallest_content,
  248. parameters, translator); // MAY THROW, STRONG
  249. margin_type sum_of_margins = 0;
  250. size_t corner = min_corner;
  251. size_t index = 0;
  252. content_type overlap_val = (std::numeric_limits<content_type>::max)();
  253. content_type content_val = (std::numeric_limits<content_type>::max)();
  254. choose_split_axis_and_index_for_axis<
  255. Box,
  256. Dimension - 1,
  257. typename tag<element_indexable_type>::type
  258. >::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW, STRONG
  259. if ( sum_of_margins < smallest_sum_of_margins )
  260. {
  261. choosen_axis = Dimension - 1;
  262. choosen_corner = corner;
  263. choosen_index = index;
  264. smallest_sum_of_margins = sum_of_margins;
  265. smallest_overlap = overlap_val;
  266. smallest_content = content_val;
  267. }
  268. }
  269. };
  270. template <typename Box>
  271. struct choose_split_axis_and_index<Box, 1>
  272. {
  273. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  274. typedef typename index::detail::default_content_result<Box>::type content_type;
  275. template <typename Elements, typename Parameters, typename Translator>
  276. static inline void apply(Elements const& elements,
  277. size_t & choosen_axis,
  278. size_t & choosen_corner,
  279. size_t & choosen_index,
  280. margin_type & smallest_sum_of_margins,
  281. content_type & smallest_overlap,
  282. content_type & smallest_content,
  283. Parameters const& parameters,
  284. Translator const& translator)
  285. {
  286. typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
  287. choosen_axis = 0;
  288. choose_split_axis_and_index_for_axis<
  289. Box,
  290. 0,
  291. typename tag<element_indexable_type>::type
  292. >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW
  293. }
  294. };
  295. template <size_t Corner, size_t Dimension, size_t I = 0>
  296. struct nth_element
  297. {
  298. BOOST_STATIC_ASSERT(0 < Dimension);
  299. BOOST_STATIC_ASSERT(I < Dimension);
  300. template <typename Elements, typename Parameters, typename Translator>
  301. static inline void apply(Elements & elements, Parameters const& parameters,
  302. const size_t axis, const size_t index, Translator const& tr)
  303. {
  304. //BOOST_GEOMETRY_INDEX_ASSERT(axis < Dimension, "unexpected axis value");
  305. if ( axis != I )
  306. {
  307. nth_element<Corner, Dimension, I + 1>::apply(elements, parameters, axis, index, tr); // MAY THROW, BASIC (copy)
  308. }
  309. else
  310. {
  311. typedef typename Elements::value_type element_type;
  312. typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
  313. typedef typename tag<indexable_type>::type indexable_tag;
  314. typename index::detail::strategy_type<Parameters>::type
  315. strategy = index::detail::get_strategy(parameters);
  316. element_axis_corner_less
  317. <
  318. element_type, Parameters, Translator, indexable_tag, Corner, I
  319. > less(tr, strategy);
  320. index::detail::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
  321. }
  322. }
  323. };
  324. template <size_t Corner, size_t Dimension>
  325. struct nth_element<Corner, Dimension, Dimension>
  326. {
  327. template <typename Elements, typename Parameters, typename Translator>
  328. static inline void apply(Elements & /*elements*/, Parameters const& /*parameters*/,
  329. const size_t /*axis*/, const size_t /*index*/, Translator const& /*tr*/)
  330. {}
  331. };
  332. } // namespace rstar
  333. template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
  334. struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_tag>
  335. {
  336. typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
  337. typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
  338. typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
  339. typedef typename Options::parameters_type parameters_type;
  340. static const size_t dimension = geometry::dimension<Box>::value;
  341. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  342. typedef typename index::detail::default_content_result<Box>::type content_type;
  343. template <typename Node>
  344. static inline void apply(
  345. Node & n,
  346. Node & second_node,
  347. Box & box1,
  348. Box & box2,
  349. parameters_type const& parameters,
  350. Translator const& translator,
  351. Allocators & allocators)
  352. {
  353. typedef typename rtree::elements_type<Node>::type elements_type;
  354. typedef typename elements_type::value_type element_type;
  355. elements_type & elements1 = rtree::elements(n);
  356. elements_type & elements2 = rtree::elements(second_node);
  357. // copy original elements - use in-memory storage (std::allocator)
  358. // TODO: move if noexcept
  359. typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
  360. container_type;
  361. container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG
  362. container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG
  363. size_t split_axis = 0;
  364. size_t split_corner = 0;
  365. size_t split_index = parameters.get_min_elements();
  366. margin_type smallest_sum_of_margins = (std::numeric_limits<margin_type>::max)();
  367. content_type smallest_overlap = (std::numeric_limits<content_type>::max)();
  368. content_type smallest_content = (std::numeric_limits<content_type>::max)();
  369. // NOTE: this function internally copies passed elements
  370. // why not pass mutable elements and use the same container for all axes/corners
  371. // and again, the same below calling partial_sort/nth_element
  372. // It would be even possible to not re-sort/find nth_element if the axis/corner
  373. // was found for the last sorting - last combination of axis/corner
  374. rstar::choose_split_axis_and_index<Box, dimension>
  375. ::apply(elements_copy,
  376. split_axis, split_corner, split_index,
  377. smallest_sum_of_margins, smallest_overlap, smallest_content,
  378. parameters, translator); // MAY THROW, STRONG
  379. // TODO: awulkiew - get rid of following static_casts?
  380. BOOST_GEOMETRY_INDEX_ASSERT(split_axis < dimension, "unexpected value");
  381. BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast<size_t>(min_corner) || split_corner == static_cast<size_t>(max_corner), "unexpected value");
  382. BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value");
  383. // TODO: consider using nth_element
  384. if ( split_corner == static_cast<size_t>(min_corner) )
  385. {
  386. rstar::nth_element<min_corner, dimension>
  387. ::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
  388. }
  389. else
  390. {
  391. rstar::nth_element<max_corner, dimension>
  392. ::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
  393. }
  394. BOOST_TRY
  395. {
  396. typename index::detail::strategy_type<parameters_type>::type const&
  397. strategy = index::detail::get_strategy(parameters);
  398. // copy elements to nodes
  399. elements1.assign(elements_copy.begin(), elements_copy.begin() + split_index); // MAY THROW, BASIC
  400. elements2.assign(elements_copy.begin() + split_index, elements_copy.end()); // MAY THROW, BASIC
  401. // calculate boxes
  402. box1 = rtree::elements_box<Box>(elements1.begin(), elements1.end(),
  403. translator, strategy);
  404. box2 = rtree::elements_box<Box>(elements2.begin(), elements2.end(),
  405. translator, strategy);
  406. }
  407. BOOST_CATCH(...)
  408. {
  409. //elements_copy.clear();
  410. elements1.clear();
  411. elements2.clear();
  412. rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
  413. //elements_backup.clear();
  414. BOOST_RETHROW // RETHROW, BASIC
  415. }
  416. BOOST_CATCH_END
  417. }
  418. };
  419. }} // namespace detail::rtree
  420. }}} // namespace boost::geometry::index
  421. #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP