1 // Boost.Geometry Index
3 // R-tree R*-tree split algorithm implementation
5 // Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
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
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)
15 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
16 #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
18 #include <boost/core/ignore_unused.hpp>
20 #include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
21 #include <boost/geometry/index/detail/algorithms/margin.hpp>
22 #include <boost/geometry/index/detail/algorithms/nth_element.hpp>
23 #include <boost/geometry/index/detail/algorithms/union_content.hpp>
25 #include <boost/geometry/index/detail/bounded_view.hpp>
27 #include <boost/geometry/index/detail/rtree/node/node.hpp>
28 #include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
29 #include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
31 namespace boost { namespace geometry { namespace index {
33 namespace detail { namespace rtree {
37 template <typename Element, typename Parameters, typename Translator, typename Tag, size_t Corner, size_t AxisIndex>
38 class element_axis_corner_less
40 typedef typename rtree::element_indexable_type<Element, Translator>::type indexable_type;
41 typedef typename geometry::point_type<indexable_type>::type point_type;
42 typedef geometry::model::box<point_type> bounds_type;
43 typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
44 typedef index::detail::bounded_view
46 indexable_type, bounds_type, strategy_type
50 element_axis_corner_less(Translator const& tr, strategy_type const& strategy)
51 : m_tr(tr), m_strategy(strategy)
54 bool operator()(Element const& e1, Element const& e2) const
56 bounded_view_type bounded_ind1(rtree::element_indexable(e1, m_tr), m_strategy);
57 bounded_view_type bounded_ind2(rtree::element_indexable(e2, m_tr), m_strategy);
59 return geometry::get<Corner, AxisIndex>(bounded_ind1)
60 < geometry::get<Corner, AxisIndex>(bounded_ind2);
64 Translator const& m_tr;
65 strategy_type const& m_strategy;
68 template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
69 class element_axis_corner_less<Element, Parameters, Translator, box_tag, Corner, AxisIndex>
71 typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
74 element_axis_corner_less(Translator const& tr, strategy_type const&)
78 bool operator()(Element const& e1, Element const& e2) const
80 return geometry::get<Corner, AxisIndex>(rtree::element_indexable(e1, m_tr))
81 < geometry::get<Corner, AxisIndex>(rtree::element_indexable(e2, m_tr));
85 Translator const& m_tr;
88 template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
89 class element_axis_corner_less<Element, Parameters, Translator, point_tag, Corner, AxisIndex>
91 typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
94 element_axis_corner_less(Translator const& tr, strategy_type const& )
98 bool operator()(Element const& e1, Element const& e2) const
100 return geometry::get<AxisIndex>(rtree::element_indexable(e1, m_tr))
101 < geometry::get<AxisIndex>(rtree::element_indexable(e2, m_tr));
105 Translator const& m_tr;
108 template <typename Box, size_t Corner, size_t AxisIndex>
109 struct choose_split_axis_and_index_for_corner
111 typedef typename index::detail::default_margin_result<Box>::type margin_type;
112 typedef typename index::detail::default_content_result<Box>::type content_type;
114 template <typename Elements, typename Parameters, typename Translator>
115 static inline void apply(Elements const& elements,
116 size_t & choosen_index,
117 margin_type & sum_of_margins,
118 content_type & smallest_overlap,
119 content_type & smallest_content,
120 Parameters const& parameters,
121 Translator const& translator)
123 typedef typename Elements::value_type element_type;
124 typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
125 typedef typename tag<indexable_type>::type indexable_tag;
127 BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements");
129 typename index::detail::strategy_type<Parameters>::type const&
130 strategy = index::detail::get_strategy(parameters);
133 Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy)
135 size_t const index_first = parameters.get_min_elements();
136 size_t const index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2;
139 element_axis_corner_less
141 element_type, Parameters, Translator, indexable_tag, Corner, AxisIndex
142 > elements_less(translator, strategy);
143 std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
145 // typename Elements::iterator f = elements_copy.begin() + index_first;
146 // typename Elements::iterator l = elements_copy.begin() + index_last;
147 // // NOTE: for stdlibc++ shipped with gcc 4.8.2 std::nth_element is replaced with std::sort anyway
148 // index::detail::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
149 // index::detail::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
150 // std::sort(f, l, elements_less); // MAY THROW, BASIC (copy)
154 choosen_index = index_first;
156 smallest_overlap = (std::numeric_limits<content_type>::max)();
157 smallest_content = (std::numeric_limits<content_type>::max)();
159 // calculate sum of margins for all distributions
160 for ( size_t i = index_first ; i < index_last ; ++i )
162 // TODO - awulkiew: may be optimized - box of group 1 may be initialized with
163 // box of min_elems number of elements and expanded for each iteration by another element
165 Box box1 = rtree::elements_box<Box>(elements_copy.begin(), elements_copy.begin() + i,
166 translator, strategy);
167 Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(),
168 translator, strategy);
170 sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2);
172 content_type ovl = index::detail::intersection_content(box1, box2, strategy);
173 content_type con = index::detail::content(box1) + index::detail::content(box2);
175 // TODO - shouldn't here be < instead of <= ?
176 if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) )
179 smallest_overlap = ovl;
180 smallest_content = con;
184 ::boost::ignore_unused(parameters);
188 //template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
189 //struct choose_split_axis_and_index_for_axis
191 // BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (ElementIndexableTag));
194 template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
195 struct choose_split_axis_and_index_for_axis
197 typedef typename index::detail::default_margin_result<Box>::type margin_type;
198 typedef typename index::detail::default_content_result<Box>::type content_type;
200 template <typename Elements, typename Parameters, typename Translator>
201 static inline void apply(Elements const& elements,
202 size_t & choosen_corner,
203 size_t & choosen_index,
204 margin_type & sum_of_margins,
205 content_type & smallest_overlap,
206 content_type & smallest_content,
207 Parameters const& parameters,
208 Translator const& translator)
211 margin_type som1 = 0;
212 content_type ovl1 = (std::numeric_limits<content_type>::max)();
213 content_type con1 = (std::numeric_limits<content_type>::max)();
215 choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
216 ::apply(elements, index1,
218 parameters, translator); // MAY THROW, STRONG
221 margin_type som2 = 0;
222 content_type ovl2 = (std::numeric_limits<content_type>::max)();
223 content_type con2 = (std::numeric_limits<content_type>::max)();
225 choose_split_axis_and_index_for_corner<Box, max_corner, AxisIndex>
226 ::apply(elements, index2,
228 parameters, translator); // MAY THROW, STRONG
230 sum_of_margins = som1 + som2;
232 if ( ovl1 < ovl2 || (ovl1 == ovl2 && con1 <= con2) )
234 choosen_corner = min_corner;
235 choosen_index = index1;
236 smallest_overlap = ovl1;
237 smallest_content = con1;
241 choosen_corner = max_corner;
242 choosen_index = index2;
243 smallest_overlap = ovl2;
244 smallest_content = con2;
249 template <typename Box, size_t AxisIndex>
250 struct choose_split_axis_and_index_for_axis<Box, AxisIndex, point_tag>
252 typedef typename index::detail::default_margin_result<Box>::type margin_type;
253 typedef typename index::detail::default_content_result<Box>::type content_type;
255 template <typename Elements, typename Parameters, typename Translator>
256 static inline void apply(Elements const& elements,
257 size_t & choosen_corner,
258 size_t & choosen_index,
259 margin_type & sum_of_margins,
260 content_type & smallest_overlap,
261 content_type & smallest_content,
262 Parameters const& parameters,
263 Translator const& translator)
265 choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
266 ::apply(elements, choosen_index,
267 sum_of_margins, smallest_overlap, smallest_content,
268 parameters, translator); // MAY THROW, STRONG
270 choosen_corner = min_corner;
274 template <typename Box, size_t Dimension>
275 struct choose_split_axis_and_index
277 BOOST_STATIC_ASSERT(0 < Dimension);
279 typedef typename index::detail::default_margin_result<Box>::type margin_type;
280 typedef typename index::detail::default_content_result<Box>::type content_type;
282 template <typename Elements, typename Parameters, typename Translator>
283 static inline void apply(Elements const& elements,
284 size_t & choosen_axis,
285 size_t & choosen_corner,
286 size_t & choosen_index,
287 margin_type & smallest_sum_of_margins,
288 content_type & smallest_overlap,
289 content_type & smallest_content,
290 Parameters const& parameters,
291 Translator const& translator)
293 typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
295 choose_split_axis_and_index<Box, Dimension - 1>
296 ::apply(elements, choosen_axis, choosen_corner, choosen_index,
297 smallest_sum_of_margins, smallest_overlap, smallest_content,
298 parameters, translator); // MAY THROW, STRONG
300 margin_type sum_of_margins = 0;
302 size_t corner = min_corner;
305 content_type overlap_val = (std::numeric_limits<content_type>::max)();
306 content_type content_val = (std::numeric_limits<content_type>::max)();
308 choose_split_axis_and_index_for_axis<
311 typename tag<element_indexable_type>::type
312 >::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW, STRONG
314 if ( sum_of_margins < smallest_sum_of_margins )
316 choosen_axis = Dimension - 1;
317 choosen_corner = corner;
318 choosen_index = index;
319 smallest_sum_of_margins = sum_of_margins;
320 smallest_overlap = overlap_val;
321 smallest_content = content_val;
326 template <typename Box>
327 struct choose_split_axis_and_index<Box, 1>
329 typedef typename index::detail::default_margin_result<Box>::type margin_type;
330 typedef typename index::detail::default_content_result<Box>::type content_type;
332 template <typename Elements, typename Parameters, typename Translator>
333 static inline void apply(Elements const& elements,
334 size_t & choosen_axis,
335 size_t & choosen_corner,
336 size_t & choosen_index,
337 margin_type & smallest_sum_of_margins,
338 content_type & smallest_overlap,
339 content_type & smallest_content,
340 Parameters const& parameters,
341 Translator const& translator)
343 typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
347 choose_split_axis_and_index_for_axis<
350 typename tag<element_indexable_type>::type
351 >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW
355 template <size_t Corner, size_t Dimension, size_t I = 0>
358 BOOST_STATIC_ASSERT(0 < Dimension);
359 BOOST_STATIC_ASSERT(I < Dimension);
361 template <typename Elements, typename Parameters, typename Translator>
362 static inline void apply(Elements & elements, Parameters const& parameters,
363 const size_t axis, const size_t index, Translator const& tr)
365 //BOOST_GEOMETRY_INDEX_ASSERT(axis < Dimension, "unexpected axis value");
369 nth_element<Corner, Dimension, I + 1>::apply(elements, parameters, axis, index, tr); // MAY THROW, BASIC (copy)
373 typedef typename Elements::value_type element_type;
374 typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
375 typedef typename tag<indexable_type>::type indexable_tag;
377 typename index::detail::strategy_type<Parameters>::type
378 strategy = index::detail::get_strategy(parameters);
380 element_axis_corner_less
382 element_type, Parameters, Translator, indexable_tag, Corner, I
383 > less(tr, strategy);
384 index::detail::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
389 template <size_t Corner, size_t Dimension>
390 struct nth_element<Corner, Dimension, Dimension>
392 template <typename Elements, typename Parameters, typename Translator>
393 static inline void apply(Elements & /*elements*/, Parameters const& /*parameters*/,
394 const size_t /*axis*/, const size_t /*index*/, Translator const& /*tr*/)
400 template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
401 struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_tag>
403 typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
404 typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
405 typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
407 typedef typename Options::parameters_type parameters_type;
409 static const size_t dimension = geometry::dimension<Box>::value;
411 typedef typename index::detail::default_margin_result<Box>::type margin_type;
412 typedef typename index::detail::default_content_result<Box>::type content_type;
414 template <typename Node>
415 static inline void apply(
420 parameters_type const& parameters,
421 Translator const& translator,
422 Allocators & allocators)
424 typedef typename rtree::elements_type<Node>::type elements_type;
425 typedef typename elements_type::value_type element_type;
427 elements_type & elements1 = rtree::elements(n);
428 elements_type & elements2 = rtree::elements(second_node);
430 // copy original elements - use in-memory storage (std::allocator)
431 // TODO: move if noexcept
432 typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
434 container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG
435 container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG
437 size_t split_axis = 0;
438 size_t split_corner = 0;
439 size_t split_index = parameters.get_min_elements();
440 margin_type smallest_sum_of_margins = (std::numeric_limits<margin_type>::max)();
441 content_type smallest_overlap = (std::numeric_limits<content_type>::max)();
442 content_type smallest_content = (std::numeric_limits<content_type>::max)();
444 // NOTE: this function internally copies passed elements
445 // why not pass mutable elements and use the same container for all axes/corners
446 // and again, the same below calling partial_sort/nth_element
447 // It would be even possible to not re-sort/find nth_element if the axis/corner
448 // was found for the last sorting - last combination of axis/corner
449 rstar::choose_split_axis_and_index<Box, dimension>
450 ::apply(elements_copy,
451 split_axis, split_corner, split_index,
452 smallest_sum_of_margins, smallest_overlap, smallest_content,
453 parameters, translator); // MAY THROW, STRONG
455 // TODO: awulkiew - get rid of following static_casts?
456 BOOST_GEOMETRY_INDEX_ASSERT(split_axis < dimension, "unexpected value");
457 BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast<size_t>(min_corner) || split_corner == static_cast<size_t>(max_corner), "unexpected value");
458 BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value");
460 // TODO: consider using nth_element
461 if ( split_corner == static_cast<size_t>(min_corner) )
463 rstar::nth_element<min_corner, dimension>
464 ::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
468 rstar::nth_element<max_corner, dimension>
469 ::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
474 typename index::detail::strategy_type<parameters_type>::type const&
475 strategy = index::detail::get_strategy(parameters);
477 // copy elements to nodes
478 elements1.assign(elements_copy.begin(), elements_copy.begin() + split_index); // MAY THROW, BASIC
479 elements2.assign(elements_copy.begin() + split_index, elements_copy.end()); // MAY THROW, BASIC
482 box1 = rtree::elements_box<Box>(elements1.begin(), elements1.end(),
483 translator, strategy);
484 box2 = rtree::elements_box<Box>(elements2.begin(), elements2.end(),
485 translator, strategy);
489 //elements_copy.clear();
493 rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
494 //elements_backup.clear();
496 BOOST_RETHROW // RETHROW, BASIC
502 }} // namespace detail::rtree
504 }}} // namespace boost::geometry::index
506 #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP