]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/geometry/include/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / geometry / include / boost / geometry / index / detail / rtree / quadratic / redistribute_elements.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry Index
2//
3// R-tree quadratic split algorithm implementation
4//
5// Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
6//
7// Use, modification and distribution is subject to the Boost Software License,
8// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10
11#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
12#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
13
14#include <algorithm>
15
16#include <boost/geometry/index/detail/algorithms/content.hpp>
17#include <boost/geometry/index/detail/algorithms/union_content.hpp>
18
19#include <boost/geometry/index/detail/bounded_view.hpp>
20
21#include <boost/geometry/index/detail/rtree/node/node.hpp>
22#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
23#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
24
25namespace boost { namespace geometry { namespace index {
26
27namespace detail { namespace rtree {
28
29namespace quadratic {
30
31template <typename Box, typename Elements, typename Parameters, typename Translator>
32inline void pick_seeds(Elements const& elements,
33 Parameters const& parameters,
34 Translator const& tr,
35 size_t & seed1,
36 size_t & seed2)
37{
38 typedef typename Elements::value_type element_type;
39 typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
40 typedef Box box_type;
41 typedef typename index::detail::default_content_result<box_type>::type content_type;
42 typedef index::detail::bounded_view<indexable_type, box_type> bounded_indexable_view;
43
44 const size_t elements_count = parameters.get_max_elements() + 1;
45 BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "wrong number of elements");
46 BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
47
48 content_type greatest_free_content = 0;
49 seed1 = 0;
50 seed2 = 1;
51
52 for ( size_t i = 0 ; i < elements_count - 1 ; ++i )
53 {
54 for ( size_t j = i + 1 ; j < elements_count ; ++j )
55 {
56 indexable_type const& ind1 = rtree::element_indexable(elements[i], tr);
57 indexable_type const& ind2 = rtree::element_indexable(elements[j], tr);
58
59 box_type enlarged_box;
60 detail::bounds(ind1, enlarged_box);
61 geometry::expand(enlarged_box, ind2);
62
63 bounded_indexable_view bounded_ind1(ind1);
64 bounded_indexable_view bounded_ind2(ind2);
65 content_type free_content = ( index::detail::content(enlarged_box)
66 - index::detail::content(bounded_ind1) )
67 - index::detail::content(bounded_ind2);
68
69 if ( greatest_free_content < free_content )
70 {
71 greatest_free_content = free_content;
72 seed1 = i;
73 seed2 = j;
74 }
75 }
76 }
77
78 ::boost::ignore_unused_variable_warning(parameters);
79}
80
81} // namespace quadratic
82
83template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
84struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadratic_tag>
85{
86 typedef typename Options::parameters_type parameters_type;
87
88 typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
89 typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
90 typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
91
92 typedef typename index::detail::default_content_result<Box>::type content_type;
93
94 template <typename Node>
95 static inline void apply(Node & n,
96 Node & second_node,
97 Box & box1,
98 Box & box2,
99 parameters_type const& parameters,
100 Translator const& translator,
101 Allocators & allocators)
102 {
103 typedef typename rtree::elements_type<Node>::type elements_type;
104 typedef typename elements_type::value_type element_type;
105 typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
106
107 elements_type & elements1 = rtree::elements(n);
108 elements_type & elements2 = rtree::elements(second_node);
109
110 BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == parameters.get_max_elements() + 1, "unexpected elements number");
111
112 // copy original elements - use in-memory storage (std::allocator)
113 // TODO: move if noexcept
114 typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
115 container_type;
116 container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
117 container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
118
119 // calculate initial seeds
120 size_t seed1 = 0;
121 size_t seed2 = 0;
122 quadratic::pick_seeds<Box>(elements_copy, parameters, translator, seed1, seed2);
123
124 // prepare nodes' elements containers
125 elements1.clear();
126 BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "second node's elements container should be empty");
127
128 BOOST_TRY
129 {
130 // add seeds
131 elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
132 elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
133
134 // calculate boxes
135 detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1);
136 detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2);
137
138 // remove seeds
139 if (seed1 < seed2)
140 {
141 rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
142 elements_copy.pop_back();
143 rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
144 elements_copy.pop_back();
145 }
146 else
147 {
148 rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
149 elements_copy.pop_back();
150 rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
151 elements_copy.pop_back();
152 }
153
154 // initialize areas
155 content_type content1 = index::detail::content(box1);
156 content_type content2 = index::detail::content(box2);
157
158 size_t remaining = elements_copy.size();
159
160 // redistribute the rest of the elements
161 while ( !elements_copy.empty() )
162 {
163 typename container_type::reverse_iterator el_it = elements_copy.rbegin();
164 bool insert_into_group1 = false;
165
166 size_t elements1_count = elements1.size();
167 size_t elements2_count = elements2.size();
168
169 // if there is small number of elements left and the number of elements in node is lesser than min_elems
170 // just insert them to this node
171 if ( elements1_count + remaining <= parameters.get_min_elements() )
172 {
173 insert_into_group1 = true;
174 }
175 else if ( elements2_count + remaining <= parameters.get_min_elements() )
176 {
177 insert_into_group1 = false;
178 }
179 // insert the best element
180 else
181 {
182 // find element with minimum groups areas increses differences
183 content_type content_increase1 = 0;
184 content_type content_increase2 = 0;
185 el_it = pick_next(elements_copy.rbegin(), elements_copy.rend(),
186 box1, box2, content1, content2, translator,
187 content_increase1, content_increase2);
188
189 if ( content_increase1 < content_increase2 ||
190 ( content_increase1 == content_increase2 && ( content1 < content2 ||
191 ( content1 == content2 && elements1_count <= elements2_count ) )
192 ) )
193 {
194 insert_into_group1 = true;
195 }
196 else
197 {
198 insert_into_group1 = false;
199 }
200 }
201
202 // move element to the choosen group
203 element_type const& elem = *el_it;
204 indexable_type const& indexable = rtree::element_indexable(elem, translator);
205
206 if ( insert_into_group1 )
207 {
208 elements1.push_back(elem); // MAY THROW, STRONG (copy)
209 geometry::expand(box1, indexable);
210 content1 = index::detail::content(box1);
211 }
212 else
213 {
214 elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
215 geometry::expand(box2, indexable);
216 content2 = index::detail::content(box2);
217 }
218
219 BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements");
220 typename container_type::iterator el_it_base = el_it.base();
221 rtree::move_from_back(elements_copy, --el_it_base); // MAY THROW, STRONG (copy)
222 elements_copy.pop_back();
223
224 BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
225 --remaining;
226 }
227 }
228 BOOST_CATCH(...)
229 {
230 //elements_copy.clear();
231 elements1.clear();
232 elements2.clear();
233
234 rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
235 //elements_backup.clear();
236
237 BOOST_RETHROW // RETHROW, BASIC
238 }
239 BOOST_CATCH_END
240 }
241
242 // TODO: awulkiew - change following function to static member of the pick_next class?
243
244 template <typename It>
245 static inline It pick_next(It first, It last,
246 Box const& box1, Box const& box2,
247 content_type const& content1, content_type const& content2,
248 Translator const& translator,
249 content_type & out_content_increase1, content_type & out_content_increase2)
250 {
251 typedef typename boost::iterator_value<It>::type element_type;
252 typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
253
254 content_type greatest_content_incrase_diff = 0;
255 It out_it = first;
256 out_content_increase1 = 0;
257 out_content_increase2 = 0;
258
259 // find element with greatest difference between increased group's boxes areas
260 for ( It el_it = first ; el_it != last ; ++el_it )
261 {
262 indexable_type const& indexable = rtree::element_indexable(*el_it, translator);
263
264 // calculate enlarged boxes and areas
265 Box enlarged_box1(box1);
266 Box enlarged_box2(box2);
267 geometry::expand(enlarged_box1, indexable);
268 geometry::expand(enlarged_box2, indexable);
269 content_type enlarged_content1 = index::detail::content(enlarged_box1);
270 content_type enlarged_content2 = index::detail::content(enlarged_box2);
271
272 content_type content_incrase1 = (enlarged_content1 - content1);
273 content_type content_incrase2 = (enlarged_content2 - content2);
274
275 content_type content_incrase_diff = content_incrase1 < content_incrase2 ?
276 content_incrase2 - content_incrase1 : content_incrase1 - content_incrase2;
277
278 if ( greatest_content_incrase_diff < content_incrase_diff )
279 {
280 greatest_content_incrase_diff = content_incrase_diff;
281 out_it = el_it;
282 out_content_increase1 = content_incrase1;
283 out_content_increase2 = content_incrase2;
284 }
285 }
286
287 return out_it;
288 }
289};
290
291}} // namespace detail::rtree
292
293}}} // namespace boost::geometry::index
294
295#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP