File indexing completed on 2025-01-18 09:35:32
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP
0018 #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP
0019
0020 #include <boost/core/ignore_unused.hpp>
0021
0022 #include <boost/geometry/algorithms/centroid.hpp>
0023 #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
0024 #include <boost/geometry/algorithms/expand.hpp>
0025
0026 #include <boost/geometry/index/detail/algorithms/bounds.hpp>
0027 #include <boost/geometry/index/detail/algorithms/content.hpp>
0028 #include <boost/geometry/index/detail/algorithms/is_valid.hpp>
0029 #include <boost/geometry/index/detail/algorithms/nth_element.hpp>
0030 #include <boost/geometry/index/detail/rtree/node/node_elements.hpp>
0031 #include <boost/geometry/index/detail/rtree/node/subtree_destroyer.hpp>
0032 #include <boost/geometry/index/parameters.hpp>
0033
0034 namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
0035
0036 namespace pack_utils {
0037
0038 template <std::size_t Dimension>
0039 struct biggest_edge
0040 {
0041 BOOST_STATIC_ASSERT(0 < Dimension);
0042 template <typename Box>
0043 static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index)
0044 {
0045 biggest_edge<Dimension-1>::apply(box, length, dim_index);
0046 typename coordinate_type<Box>::type curr
0047 = geometry::get<max_corner, Dimension-1>(box) - geometry::get<min_corner, Dimension-1>(box);
0048 if ( length < curr )
0049 {
0050 dim_index = Dimension - 1;
0051 length = curr;
0052 }
0053 }
0054 };
0055
0056 template <>
0057 struct biggest_edge<1>
0058 {
0059 template <typename Box>
0060 static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index)
0061 {
0062 dim_index = 0;
0063 length = geometry::get<max_corner, 0>(box) - geometry::get<min_corner, 0>(box);
0064 }
0065 };
0066
0067 template <std::size_t I>
0068 struct point_entries_comparer
0069 {
0070 template <typename PointEntry>
0071 bool operator()(PointEntry const& e1, PointEntry const& e2) const
0072 {
0073 return geometry::get<I>(e1.first) < geometry::get<I>(e2.first);
0074 }
0075 };
0076
0077 template <std::size_t I, std::size_t Dimension>
0078 struct nth_element_and_half_boxes
0079 {
0080 template <typename EIt, typename Box>
0081 static inline void apply(EIt first, EIt median, EIt last, Box const& box,
0082 Box & left, Box & right, std::size_t dim_index)
0083 {
0084 if (I == dim_index)
0085 {
0086 index::detail::nth_element(first, median, last, point_entries_comparer<I>());
0087
0088 geometry::convert(box, left);
0089 geometry::convert(box, right);
0090 auto const mi = geometry::get<min_corner, I>(box);
0091 auto const ma = geometry::get<max_corner, I>(box);
0092 auto const center = mi + (ma - mi) / 2;
0093 geometry::set<max_corner, I>(left, center);
0094 geometry::set<min_corner, I>(right, center);
0095 }
0096 else
0097 {
0098 nth_element_and_half_boxes
0099 <
0100 I + 1, Dimension
0101 >::apply(first, median, last, box, left, right, dim_index);
0102 }
0103 }
0104 };
0105
0106 template <std::size_t Dimension>
0107 struct nth_element_and_half_boxes<Dimension, Dimension>
0108 {
0109 template <typename EIt, typename Box>
0110 static inline void apply(EIt , EIt , EIt , Box const& , Box & , Box & , std::size_t ) {}
0111 };
0112
0113 }
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142 template <typename MembersHolder>
0143 class pack
0144 {
0145 typedef typename MembersHolder::node node;
0146 typedef typename MembersHolder::internal_node internal_node;
0147 typedef typename MembersHolder::leaf leaf;
0148
0149 typedef typename MembersHolder::node_pointer node_pointer;
0150 typedef typename MembersHolder::size_type size_type;
0151 typedef typename MembersHolder::parameters_type parameters_type;
0152 typedef typename MembersHolder::translator_type translator_type;
0153 typedef typename MembersHolder::allocators_type allocators_type;
0154
0155 typedef typename MembersHolder::box_type box_type;
0156 typedef typename geometry::point_type<box_type>::type point_type;
0157 typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
0158 typedef typename detail::default_content_result<box_type>::type content_type;
0159 typedef typename detail::strategy_type<parameters_type>::type strategy_type;
0160 static const std::size_t dimension = geometry::dimension<point_type>::value;
0161
0162 typedef typename rtree::container_from_elements_type<
0163 typename rtree::elements_type<leaf>::type,
0164 size_type
0165 >::type values_counts_container;
0166
0167 typedef typename rtree::elements_type<internal_node>::type internal_elements;
0168 typedef typename internal_elements::value_type internal_element;
0169
0170 typedef rtree::subtree_destroyer<MembersHolder> subtree_destroyer;
0171
0172 public:
0173
0174 template <typename InIt> inline static
0175 node_pointer apply(InIt first, InIt last,
0176 size_type & values_count,
0177 size_type & leafs_level,
0178 parameters_type const& parameters,
0179 translator_type const& translator,
0180 allocators_type & allocators)
0181 {
0182 return apply(first, last, values_count, leafs_level, parameters, translator,
0183 allocators, boost::container::new_allocator<void>());
0184 }
0185
0186 template <typename InIt, typename TmpAlloc> inline static
0187 node_pointer apply(InIt first, InIt last,
0188 size_type & values_count,
0189 size_type & leafs_level,
0190 parameters_type const& parameters,
0191 translator_type const& translator,
0192 allocators_type & allocators,
0193 TmpAlloc const& temp_allocator)
0194 {
0195 typedef typename std::iterator_traits<InIt>::difference_type diff_type;
0196
0197 diff_type diff = std::distance(first, last);
0198 if ( diff <= 0 )
0199 return node_pointer(0);
0200
0201 typedef std::pair<point_type, InIt> entry_type;
0202 typedef typename boost::container::allocator_traits<TmpAlloc>::
0203 template rebind_alloc<entry_type> temp_entry_allocator_type;
0204
0205 temp_entry_allocator_type temp_entry_allocator(temp_allocator);
0206 boost::container::vector<entry_type, temp_entry_allocator_type> entries(temp_entry_allocator);
0207
0208 values_count = static_cast<size_type>(diff);
0209 entries.reserve(values_count);
0210
0211 auto const& strategy = index::detail::get_strategy(parameters);
0212
0213 expandable_box<box_type, strategy_type> hint_box(strategy);
0214 for ( ; first != last ; ++first )
0215 {
0216
0217
0218
0219
0220 typename std::iterator_traits<InIt>::reference in_ref = *first;
0221 typename translator_type::result_type indexable = translator(in_ref);
0222
0223
0224
0225 BOOST_GEOMETRY_INDEX_ASSERT(detail::is_valid(indexable), "Indexable is invalid");
0226
0227 hint_box.expand(indexable);
0228
0229 point_type pt;
0230 geometry::centroid(indexable, pt, strategy);
0231 entries.push_back(std::make_pair(pt, first));
0232 }
0233
0234 subtree_elements_counts subtree_counts = calculate_subtree_elements_counts(values_count, parameters, leafs_level);
0235 internal_element el = per_level(entries.begin(), entries.end(), hint_box.get(), values_count, subtree_counts,
0236 parameters, translator, allocators);
0237
0238 return el.second;
0239 }
0240
0241 private:
0242 template <typename BoxType, typename Strategy>
0243 class expandable_box
0244 {
0245 public:
0246 explicit expandable_box(Strategy const& strategy)
0247 : m_strategy(strategy), m_initialized(false)
0248 {}
0249
0250 template <typename Indexable>
0251 explicit expandable_box(Indexable const& indexable, Strategy const& strategy)
0252 : m_strategy(strategy), m_initialized(true)
0253 {
0254 detail::bounds(indexable, m_box, m_strategy);
0255 }
0256
0257 template <typename Indexable>
0258 void expand(Indexable const& indexable)
0259 {
0260 if ( !m_initialized )
0261 {
0262
0263
0264
0265 detail::bounds(indexable, m_box, m_strategy);
0266 m_initialized = true;
0267 }
0268 else
0269 {
0270 detail::expand(m_box, indexable, m_strategy);
0271 }
0272 }
0273
0274 void expand_by_epsilon()
0275 {
0276 geometry::detail::expand_by_epsilon(m_box);
0277 }
0278
0279 BoxType const& get() const
0280 {
0281 BOOST_GEOMETRY_INDEX_ASSERT(m_initialized, "uninitialized envelope accessed");
0282 return m_box;
0283 }
0284
0285 private:
0286 BoxType m_box;
0287 Strategy m_strategy;
0288 bool m_initialized;
0289 };
0290
0291 struct subtree_elements_counts
0292 {
0293 subtree_elements_counts(size_type ma, size_type mi) : maxc(ma), minc(mi) {}
0294 size_type maxc;
0295 size_type minc;
0296 };
0297
0298 template <typename EIt> inline static
0299 internal_element per_level(EIt first, EIt last,
0300 box_type const& hint_box,
0301 size_type values_count,
0302 subtree_elements_counts const& subtree_counts,
0303 parameters_type const& parameters,
0304 translator_type const& translator,
0305 allocators_type & allocators)
0306 {
0307 BOOST_GEOMETRY_INDEX_ASSERT(0 < std::distance(first, last) && static_cast<size_type>(std::distance(first, last)) == values_count,
0308 "unexpected parameters");
0309
0310 if ( subtree_counts.maxc <= 1 )
0311 {
0312
0313 BOOST_GEOMETRY_INDEX_ASSERT(values_count <= parameters.get_max_elements(),
0314 "too big number of elements");
0315
0316
0317
0318 node_pointer n = rtree::create_node<allocators_type, leaf>::apply(allocators);
0319 subtree_destroyer auto_remover(n, allocators);
0320 leaf & l = rtree::get<leaf>(*n);
0321
0322
0323 rtree::elements(l).reserve(values_count);
0324
0325
0326
0327 expandable_box<box_type, strategy_type> elements_box(translator(*(first->second)),
0328 detail::get_strategy(parameters));
0329 rtree::elements(l).push_back(*(first->second));
0330 for ( ++first ; first != last ; ++first )
0331 {
0332
0333
0334
0335 elements_box.expand(translator(*(first->second)));
0336 rtree::elements(l).push_back(*(first->second));
0337 }
0338
0339 #ifdef BOOST_GEOMETRY_INDEX_EXPERIMENTAL_ENLARGE_BY_EPSILON
0340
0341
0342
0343
0344
0345
0346 if ( BOOST_GEOMETRY_CONDITION((
0347 ! index::detail::is_bounding_geometry
0348 <
0349 typename indexable_type<translator_type>::type
0350 >::value )) )
0351 {
0352 elements_box.expand_by_epsilon();
0353 }
0354 #endif
0355
0356 auto_remover.release();
0357 return internal_element(elements_box.get(), n);
0358 }
0359
0360
0361 subtree_elements_counts next_subtree_counts = subtree_counts;
0362 next_subtree_counts.maxc /= parameters.get_max_elements();
0363 next_subtree_counts.minc /= parameters.get_max_elements();
0364
0365
0366 node_pointer n = rtree::create_node<allocators_type, internal_node>::apply(allocators);
0367 subtree_destroyer auto_remover(n, allocators);
0368 internal_node & in = rtree::get<internal_node>(*n);
0369
0370
0371 size_type nodes_count = calculate_nodes_count(values_count, subtree_counts);
0372 rtree::elements(in).reserve(nodes_count);
0373
0374 expandable_box<box_type, strategy_type> elements_box(detail::get_strategy(parameters));
0375
0376 per_level_packets(first, last, hint_box, values_count, subtree_counts, next_subtree_counts,
0377 rtree::elements(in), elements_box,
0378 parameters, translator, allocators);
0379
0380 auto_remover.release();
0381 return internal_element(elements_box.get(), n);
0382 }
0383
0384 template <typename EIt, typename ExpandableBox> inline static
0385 void per_level_packets(EIt first, EIt last,
0386 box_type const& hint_box,
0387 size_type values_count,
0388 subtree_elements_counts const& subtree_counts,
0389 subtree_elements_counts const& next_subtree_counts,
0390 internal_elements & elements,
0391 ExpandableBox & elements_box,
0392 parameters_type const& parameters,
0393 translator_type const& translator,
0394 allocators_type & allocators)
0395 {
0396 BOOST_GEOMETRY_INDEX_ASSERT(0 < std::distance(first, last) && static_cast<size_type>(std::distance(first, last)) == values_count,
0397 "unexpected parameters");
0398
0399 BOOST_GEOMETRY_INDEX_ASSERT(subtree_counts.minc <= values_count,
0400 "too small number of elements");
0401
0402
0403 if ( values_count <= subtree_counts.maxc )
0404 {
0405
0406 internal_element el = per_level(first, last, hint_box, values_count, next_subtree_counts,
0407 parameters, translator, allocators);
0408
0409
0410
0411
0412 subtree_destroyer auto_remover(el.second, allocators);
0413
0414 elements.push_back(el);
0415 auto_remover.release();
0416
0417 elements_box.expand(el.first);
0418 return;
0419 }
0420
0421 size_type median_count = calculate_median_count(values_count, subtree_counts);
0422 EIt median = first + median_count;
0423
0424 coordinate_type greatest_length;
0425 std::size_t greatest_dim_index = 0;
0426 pack_utils::biggest_edge<dimension>::apply(hint_box, greatest_length, greatest_dim_index);
0427 box_type left, right;
0428 pack_utils::nth_element_and_half_boxes<0, dimension>
0429 ::apply(first, median, last, hint_box, left, right, greatest_dim_index);
0430
0431 per_level_packets(first, median, left,
0432 median_count, subtree_counts, next_subtree_counts,
0433 elements, elements_box,
0434 parameters, translator, allocators);
0435 per_level_packets(median, last, right,
0436 values_count - median_count, subtree_counts, next_subtree_counts,
0437 elements, elements_box,
0438 parameters, translator, allocators);
0439 }
0440
0441 inline static
0442 subtree_elements_counts calculate_subtree_elements_counts(size_type elements_count, parameters_type const& parameters, size_type & leafs_level)
0443 {
0444 boost::ignore_unused(parameters);
0445
0446 subtree_elements_counts res(1, 1);
0447 leafs_level = 0;
0448
0449 size_type smax = parameters.get_max_elements();
0450 for ( ; smax < elements_count ; smax *= parameters.get_max_elements(), ++leafs_level )
0451 res.maxc = smax;
0452
0453 res.minc = parameters.get_min_elements() * (res.maxc / parameters.get_max_elements());
0454
0455 return res;
0456 }
0457
0458 inline static
0459 size_type calculate_nodes_count(size_type count,
0460 subtree_elements_counts const& subtree_counts)
0461 {
0462 size_type n = count / subtree_counts.maxc;
0463 size_type r = count % subtree_counts.maxc;
0464
0465 if ( 0 < r && r < subtree_counts.minc )
0466 {
0467 size_type count_minus_min = count - subtree_counts.minc;
0468 n = count_minus_min / subtree_counts.maxc;
0469 r = count_minus_min % subtree_counts.maxc;
0470 ++n;
0471 }
0472
0473 if ( 0 < r )
0474 ++n;
0475
0476 return n;
0477 }
0478
0479 inline static
0480 size_type calculate_median_count(size_type count,
0481 subtree_elements_counts const& subtree_counts)
0482 {
0483
0484
0485 size_type n = count / subtree_counts.maxc;
0486 size_type r = count % subtree_counts.maxc;
0487 size_type median_count = (n / 2) * subtree_counts.maxc;
0488
0489 if ( 0 != r )
0490 {
0491 if ( subtree_counts.minc <= r )
0492 {
0493
0494 median_count = ((n+1)/2) * subtree_counts.maxc;
0495 }
0496 else
0497 {
0498 size_type count_minus_min = count - subtree_counts.minc;
0499 n = count_minus_min / subtree_counts.maxc;
0500 r = count_minus_min % subtree_counts.maxc;
0501 if ( r == 0 )
0502 {
0503
0504
0505 median_count = ((n+1)/2) * subtree_counts.maxc;
0506 }
0507 else
0508 {
0509 if ( n == 0 )
0510 median_count = r;
0511 else
0512 median_count = ((n+2)/2) * subtree_counts.maxc;
0513 }
0514 }
0515 }
0516
0517 return median_count;
0518 }
0519 };
0520
0521 }}}}}
0522
0523 #endif