distance_query.hpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. // Boost.Geometry Index
  2. //
  3. // R-tree distance (knn, path, etc. ) query visitor implementation
  4. //
  5. // Copyright (c) 2011-2014 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_VISITORS_DISTANCE_QUERY_HPP
  15. #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
  16. namespace boost { namespace geometry { namespace index {
  17. namespace detail { namespace rtree { namespace visitors {
  18. template <typename Value, typename Translator, typename DistanceType, typename OutIt>
  19. class distance_query_result
  20. {
  21. public:
  22. typedef DistanceType distance_type;
  23. inline explicit distance_query_result(size_t k, OutIt out_it)
  24. : m_count(k), m_out_it(out_it)
  25. {
  26. BOOST_GEOMETRY_INDEX_ASSERT(0 < m_count, "Number of neighbors should be greater than 0");
  27. m_neighbors.reserve(m_count);
  28. }
  29. inline void store(Value const& val, distance_type const& curr_comp_dist)
  30. {
  31. if ( m_neighbors.size() < m_count )
  32. {
  33. m_neighbors.push_back(std::make_pair(curr_comp_dist, val));
  34. if ( m_neighbors.size() == m_count )
  35. std::make_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
  36. }
  37. else
  38. {
  39. if ( curr_comp_dist < m_neighbors.front().first )
  40. {
  41. std::pop_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
  42. m_neighbors.back().first = curr_comp_dist;
  43. m_neighbors.back().second = val;
  44. std::push_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
  45. }
  46. }
  47. }
  48. inline bool has_enough_neighbors() const
  49. {
  50. return m_count <= m_neighbors.size();
  51. }
  52. inline distance_type greatest_comparable_distance() const
  53. {
  54. // greatest distance is in the first neighbor only
  55. // if there is at least m_count values found
  56. // this is just for safety reasons since is_comparable_distance_valid() is checked earlier
  57. // TODO - may be replaced by ASSERT
  58. return m_neighbors.size() < m_count
  59. ? (std::numeric_limits<distance_type>::max)()
  60. : m_neighbors.front().first;
  61. }
  62. inline size_t finish()
  63. {
  64. typedef typename std::vector< std::pair<distance_type, Value> >::const_iterator neighbors_iterator;
  65. for ( neighbors_iterator it = m_neighbors.begin() ; it != m_neighbors.end() ; ++it, ++m_out_it )
  66. *m_out_it = it->second;
  67. return m_neighbors.size();
  68. }
  69. private:
  70. inline static bool neighbors_less(
  71. std::pair<distance_type, Value> const& p1,
  72. std::pair<distance_type, Value> const& p2)
  73. {
  74. return p1.first < p2.first;
  75. }
  76. size_t m_count;
  77. OutIt m_out_it;
  78. std::vector< std::pair<distance_type, Value> > m_neighbors;
  79. };
  80. template <
  81. typename Value,
  82. typename Options,
  83. typename Translator,
  84. typename Box,
  85. typename Allocators,
  86. typename Predicates,
  87. unsigned DistancePredicateIndex,
  88. typename OutIter
  89. >
  90. class distance_query
  91. : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
  92. {
  93. public:
  94. typedef typename Options::parameters_type parameters_type;
  95. typedef typename index::detail::strategy_type<parameters_type>::type strategy_type;
  96. typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
  97. typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
  98. typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
  99. typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
  100. typedef typename nearest_predicate_access::type nearest_predicate_type;
  101. typedef typename indexable_type<Translator>::type indexable_type;
  102. typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, strategy_type, value_tag> calculate_value_distance;
  103. typedef index::detail::calculate_distance<nearest_predicate_type, Box, strategy_type, bounds_tag> calculate_node_distance;
  104. typedef typename calculate_value_distance::result_type value_distance_type;
  105. typedef typename calculate_node_distance::result_type node_distance_type;
  106. static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
  107. inline distance_query(parameters_type const& parameters, Translator const& translator, Predicates const& pred, OutIter out_it)
  108. : m_parameters(parameters), m_translator(translator)
  109. , m_pred(pred)
  110. , m_result(nearest_predicate_access::get(m_pred).count, out_it)
  111. , m_strategy(index::detail::get_strategy(parameters))
  112. {}
  113. inline void operator()(internal_node const& n)
  114. {
  115. typedef typename rtree::elements_type<internal_node>::type elements_type;
  116. // array of active nodes
  117. typedef typename index::detail::rtree::container_from_elements_type<
  118. elements_type,
  119. std::pair<node_distance_type, typename Allocators::node_pointer>
  120. >::type active_branch_list_type;
  121. active_branch_list_type active_branch_list;
  122. active_branch_list.reserve(m_parameters.get_max_elements());
  123. elements_type const& elements = rtree::elements(n);
  124. // fill array of nodes meeting predicates
  125. for (typename elements_type::const_iterator it = elements.begin();
  126. it != elements.end(); ++it)
  127. {
  128. // if current node meets predicates
  129. // 0 - dummy value
  130. if ( index::detail::predicates_check
  131. <
  132. index::detail::bounds_tag, 0, predicates_len
  133. >(m_pred, 0, it->first, m_strategy) )
  134. {
  135. // calculate node's distance(s) for distance predicate
  136. node_distance_type node_distance;
  137. // if distance isn't ok - move to the next node
  138. if ( !calculate_node_distance::apply(predicate(), it->first,
  139. m_strategy, node_distance) )
  140. {
  141. continue;
  142. }
  143. // if current node is further than found neighbors - don't analyze it
  144. if ( m_result.has_enough_neighbors() &&
  145. is_node_prunable(m_result.greatest_comparable_distance(), node_distance) )
  146. {
  147. continue;
  148. }
  149. // add current node's data into the list
  150. active_branch_list.push_back( std::make_pair(node_distance, it->second) );
  151. }
  152. }
  153. // if there aren't any nodes in ABL - return
  154. if ( active_branch_list.empty() )
  155. return;
  156. // sort array
  157. std::sort(active_branch_list.begin(), active_branch_list.end(), abl_less);
  158. // recursively visit nodes
  159. for ( typename active_branch_list_type::const_iterator it = active_branch_list.begin();
  160. it != active_branch_list.end() ; ++it )
  161. {
  162. // if current node is further than furthest neighbor, the rest of nodes also will be further
  163. if ( m_result.has_enough_neighbors() &&
  164. is_node_prunable(m_result.greatest_comparable_distance(), it->first) )
  165. break;
  166. rtree::apply_visitor(*this, *(it->second));
  167. }
  168. // ALTERNATIVE VERSION - use heap instead of sorted container
  169. // It seems to be faster for greater MaxElements and slower otherwise
  170. // CONSIDER: using one global container/heap for active branches
  171. // instead of a sorted container per level
  172. // This would also change the way how branches are traversed!
  173. // The same may be applied to the iterative version which btw suffers
  174. // from the copying of the whole containers on resize of the ABLs container
  175. //// make a heap
  176. //std::make_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater);
  177. //// recursively visit nodes
  178. //while ( !active_branch_list.empty() )
  179. //{
  180. // //if current node is further than furthest neighbor, the rest of nodes also will be further
  181. // if ( m_result.has_enough_neighbors()
  182. // && is_node_prunable(m_result.greatest_comparable_distance(), active_branch_list.front().first) )
  183. // {
  184. // break;
  185. // }
  186. // rtree::apply_visitor(*this, *(active_branch_list.front().second));
  187. // std::pop_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater);
  188. // active_branch_list.pop_back();
  189. //}
  190. }
  191. inline void operator()(leaf const& n)
  192. {
  193. typedef typename rtree::elements_type<leaf>::type elements_type;
  194. elements_type const& elements = rtree::elements(n);
  195. // search leaf for closest value meeting predicates
  196. for (typename elements_type::const_iterator it = elements.begin();
  197. it != elements.end(); ++it)
  198. {
  199. // if value meets predicates
  200. if ( index::detail::predicates_check
  201. <
  202. index::detail::value_tag, 0, predicates_len
  203. >(m_pred, *it, m_translator(*it), m_strategy) )
  204. {
  205. // calculate values distance for distance predicate
  206. value_distance_type value_distance;
  207. // if distance is ok
  208. if ( calculate_value_distance::apply(predicate(), m_translator(*it),
  209. m_strategy, value_distance) )
  210. {
  211. // store value
  212. m_result.store(*it, value_distance);
  213. }
  214. }
  215. }
  216. }
  217. inline size_t finish()
  218. {
  219. return m_result.finish();
  220. }
  221. private:
  222. static inline bool abl_less(
  223. std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
  224. std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
  225. {
  226. return p1.first < p2.first;
  227. }
  228. //static inline bool abl_greater(
  229. // std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
  230. // std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
  231. //{
  232. // return p1.first > p2.first;
  233. //}
  234. template <typename Distance>
  235. static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d)
  236. {
  237. return greatest_dist <= d;
  238. }
  239. nearest_predicate_type const& predicate() const
  240. {
  241. return nearest_predicate_access::get(m_pred);
  242. }
  243. parameters_type const& m_parameters;
  244. Translator const& m_translator;
  245. Predicates m_pred;
  246. distance_query_result<Value, Translator, value_distance_type, OutIter> m_result;
  247. strategy_type m_strategy;
  248. };
  249. template <
  250. typename Value,
  251. typename Options,
  252. typename Translator,
  253. typename Box,
  254. typename Allocators,
  255. typename Predicates,
  256. unsigned DistancePredicateIndex
  257. >
  258. class distance_query_incremental
  259. : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
  260. {
  261. public:
  262. typedef typename Options::parameters_type parameters_type;
  263. typedef typename index::detail::strategy_type<parameters_type>::type strategy_type;
  264. typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
  265. typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
  266. typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
  267. typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
  268. typedef typename nearest_predicate_access::type nearest_predicate_type;
  269. typedef typename indexable_type<Translator>::type indexable_type;
  270. typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, strategy_type, value_tag> calculate_value_distance;
  271. typedef index::detail::calculate_distance<nearest_predicate_type, Box, strategy_type, bounds_tag> calculate_node_distance;
  272. typedef typename calculate_value_distance::result_type value_distance_type;
  273. typedef typename calculate_node_distance::result_type node_distance_type;
  274. typedef typename Allocators::size_type size_type;
  275. typedef typename Allocators::const_reference const_reference;
  276. typedef typename Allocators::node_pointer node_pointer;
  277. static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
  278. typedef typename rtree::elements_type<internal_node>::type internal_elements;
  279. typedef typename internal_elements::const_iterator internal_iterator;
  280. typedef typename rtree::elements_type<leaf>::type leaf_elements;
  281. typedef std::pair<node_distance_type, node_pointer> branch_data;
  282. typedef typename index::detail::rtree::container_from_elements_type<
  283. internal_elements, branch_data
  284. >::type active_branch_list_type;
  285. struct internal_stack_element
  286. {
  287. internal_stack_element() : current_branch(0) {}
  288. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  289. // Required in c++03 for containers using Boost.Move
  290. internal_stack_element & operator=(internal_stack_element const& o)
  291. {
  292. branches = o.branches;
  293. current_branch = o.current_branch;
  294. return *this;
  295. }
  296. #endif
  297. active_branch_list_type branches;
  298. typename active_branch_list_type::size_type current_branch;
  299. };
  300. typedef std::vector<internal_stack_element> internal_stack_type;
  301. inline distance_query_incremental()
  302. : m_translator(NULL)
  303. // , m_pred()
  304. , current_neighbor((std::numeric_limits<size_type>::max)())
  305. // , next_closest_node_distance((std::numeric_limits<node_distance_type>::max)())
  306. // , m_strategy_type()
  307. {}
  308. inline distance_query_incremental(parameters_type const& params, Translator const& translator, Predicates const& pred)
  309. : m_translator(::boost::addressof(translator))
  310. , m_pred(pred)
  311. , current_neighbor((std::numeric_limits<size_type>::max)())
  312. , next_closest_node_distance((std::numeric_limits<node_distance_type>::max)())
  313. , m_strategy(index::detail::get_strategy(params))
  314. {
  315. BOOST_GEOMETRY_INDEX_ASSERT(0 < max_count(), "k must be greather than 0");
  316. }
  317. const_reference dereference() const
  318. {
  319. return *(neighbors[current_neighbor].second);
  320. }
  321. void initialize(node_pointer root)
  322. {
  323. rtree::apply_visitor(*this, *root);
  324. increment();
  325. }
  326. void increment()
  327. {
  328. for (;;)
  329. {
  330. size_type new_neighbor = current_neighbor == (std::numeric_limits<size_type>::max)() ? 0 : current_neighbor + 1;
  331. if ( internal_stack.empty() )
  332. {
  333. if ( new_neighbor < neighbors.size() )
  334. current_neighbor = new_neighbor;
  335. else
  336. {
  337. current_neighbor = (std::numeric_limits<size_type>::max)();
  338. // clear() is used to disable the condition above
  339. neighbors.clear();
  340. }
  341. return;
  342. }
  343. else
  344. {
  345. active_branch_list_type & branches = internal_stack.back().branches;
  346. typename active_branch_list_type::size_type & current_branch = internal_stack.back().current_branch;
  347. if ( branches.size() <= current_branch )
  348. {
  349. internal_stack.pop_back();
  350. continue;
  351. }
  352. // if there are no nodes which can have closer values, set new value
  353. if ( new_neighbor < neighbors.size() &&
  354. // here must be < because otherwise neighbours may be sorted in different order
  355. // if there is another value with equal distance
  356. neighbors[new_neighbor].first < next_closest_node_distance )
  357. {
  358. current_neighbor = new_neighbor;
  359. return;
  360. }
  361. // if node is further than the furthest neighbour, following nodes also will be further
  362. BOOST_GEOMETRY_INDEX_ASSERT(neighbors.size() <= max_count(), "unexpected neighbours count");
  363. if ( max_count() <= neighbors.size() &&
  364. is_node_prunable(neighbors.back().first, branches[current_branch].first) )
  365. {
  366. // stop traversing current level
  367. internal_stack.pop_back();
  368. continue;
  369. }
  370. else
  371. {
  372. // new level - must increment current_branch before traversing of another level (mem reallocation)
  373. ++current_branch;
  374. rtree::apply_visitor(*this, *(branches[current_branch - 1].second));
  375. next_closest_node_distance = calc_closest_node_distance(internal_stack.begin(), internal_stack.end());
  376. }
  377. }
  378. }
  379. }
  380. bool is_end() const
  381. {
  382. return (std::numeric_limits<size_type>::max)() == current_neighbor;
  383. }
  384. friend bool operator==(distance_query_incremental const& l, distance_query_incremental const& r)
  385. {
  386. BOOST_GEOMETRY_INDEX_ASSERT(l.current_neighbor != r.current_neighbor ||
  387. (std::numeric_limits<size_type>::max)() == l.current_neighbor ||
  388. (std::numeric_limits<size_type>::max)() == r.current_neighbor ||
  389. l.neighbors[l.current_neighbor].second == r.neighbors[r.current_neighbor].second,
  390. "not corresponding iterators");
  391. return l.current_neighbor == r.current_neighbor;
  392. }
  393. // Put node's elements into the list of active branches if those elements meets predicates
  394. // and distance predicates(currently not used)
  395. // and aren't further than found neighbours (if there is enough neighbours)
  396. inline void operator()(internal_node const& n)
  397. {
  398. typedef typename rtree::elements_type<internal_node>::type elements_type;
  399. elements_type const& elements = rtree::elements(n);
  400. // add new element
  401. internal_stack.resize(internal_stack.size()+1);
  402. // fill active branch list array of nodes meeting predicates
  403. for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it )
  404. {
  405. // if current node meets predicates
  406. // 0 - dummy value
  407. if ( index::detail::predicates_check
  408. <
  409. index::detail::bounds_tag, 0, predicates_len
  410. >(m_pred, 0, it->first, m_strategy) )
  411. {
  412. // calculate node's distance(s) for distance predicate
  413. node_distance_type node_distance;
  414. // if distance isn't ok - move to the next node
  415. if ( !calculate_node_distance::apply(predicate(), it->first,
  416. m_strategy, node_distance) )
  417. {
  418. continue;
  419. }
  420. // if current node is further than found neighbors - don't analyze it
  421. if ( max_count() <= neighbors.size() &&
  422. is_node_prunable(neighbors.back().first, node_distance) )
  423. {
  424. continue;
  425. }
  426. // add current node's data into the list
  427. internal_stack.back().branches.push_back( std::make_pair(node_distance, it->second) );
  428. }
  429. }
  430. if ( internal_stack.back().branches.empty() )
  431. internal_stack.pop_back();
  432. else
  433. // sort array
  434. std::sort(internal_stack.back().branches.begin(), internal_stack.back().branches.end(), abl_less);
  435. }
  436. // Put values into the list of neighbours if those values meets predicates
  437. // and distance predicates(currently not used)
  438. // and aren't further than already found neighbours (if there is enough neighbours)
  439. inline void operator()(leaf const& n)
  440. {
  441. typedef typename rtree::elements_type<leaf>::type elements_type;
  442. elements_type const& elements = rtree::elements(n);
  443. // store distance to the furthest neighbour
  444. bool not_enough_neighbors = neighbors.size() < max_count();
  445. value_distance_type greatest_distance = !not_enough_neighbors ? neighbors.back().first : (std::numeric_limits<value_distance_type>::max)();
  446. // search leaf for closest value meeting predicates
  447. for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
  448. {
  449. // if value meets predicates
  450. if ( index::detail::predicates_check
  451. <
  452. index::detail::value_tag, 0, predicates_len
  453. >(m_pred, *it, (*m_translator)(*it), m_strategy) )
  454. {
  455. // calculate values distance for distance predicate
  456. value_distance_type value_distance;
  457. // if distance is ok
  458. if ( calculate_value_distance::apply(predicate(), (*m_translator)(*it),
  459. m_strategy, value_distance) )
  460. {
  461. // if there is not enough values or current value is closer than furthest neighbour
  462. if ( not_enough_neighbors || value_distance < greatest_distance )
  463. {
  464. neighbors.push_back(std::make_pair(value_distance, boost::addressof(*it)));
  465. }
  466. }
  467. }
  468. }
  469. // sort array
  470. std::sort(neighbors.begin(), neighbors.end(), neighbors_less);
  471. // remove furthest values
  472. if ( max_count() < neighbors.size() )
  473. neighbors.resize(max_count());
  474. }
  475. private:
  476. static inline bool abl_less(std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
  477. std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
  478. {
  479. return p1.first < p2.first;
  480. }
  481. static inline bool neighbors_less(std::pair<value_distance_type, const Value *> const& p1,
  482. std::pair<value_distance_type, const Value *> const& p2)
  483. {
  484. return p1.first < p2.first;
  485. }
  486. node_distance_type
  487. calc_closest_node_distance(typename internal_stack_type::const_iterator first,
  488. typename internal_stack_type::const_iterator last)
  489. {
  490. node_distance_type result = (std::numeric_limits<node_distance_type>::max)();
  491. for ( ; first != last ; ++first )
  492. {
  493. if ( first->branches.size() <= first->current_branch )
  494. continue;
  495. node_distance_type curr_dist = first->branches[first->current_branch].first;
  496. if ( curr_dist < result )
  497. result = curr_dist;
  498. }
  499. return result;
  500. }
  501. template <typename Distance>
  502. static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d)
  503. {
  504. return greatest_dist <= d;
  505. }
  506. inline unsigned max_count() const
  507. {
  508. return nearest_predicate_access::get(m_pred).count;
  509. }
  510. nearest_predicate_type const& predicate() const
  511. {
  512. return nearest_predicate_access::get(m_pred);
  513. }
  514. const Translator * m_translator;
  515. Predicates m_pred;
  516. internal_stack_type internal_stack;
  517. std::vector< std::pair<value_distance_type, const Value *> > neighbors;
  518. size_type current_neighbor;
  519. node_distance_type next_closest_node_distance;
  520. strategy_type m_strategy;
  521. };
  522. }}} // namespace detail::rtree::visitors
  523. }}} // namespace boost::geometry::index
  524. #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP