GEOS  3.13.0dev
TemplateSTRtree.h
1 /**********************************************************************
2  *
3  * GEOS - Geometry Engine Open Source
4  * http://geos.osgeo.org
5  *
6  * Copyright (C) 2020-2021 Daniel Baston
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU Lesser General Public Licence as published
10  * by the Free Software Foundation.
11  * See the COPYING file for more information.
12  *
13  **********************************************************************/
14 
15 #pragma once
16 
17 #include <geos/geom/Geometry.h>
18 #include <geos/index/SpatialIndex.h> // for inheritance
19 #include <geos/index/chain/MonotoneChain.h>
20 #include <geos/index/ItemVisitor.h>
21 #include <geos/util.h>
22 
23 #include <geos/index/strtree/TemplateSTRNode.h>
24 #include <geos/index/strtree/TemplateSTRNodePair.h>
25 #include <geos/index/strtree/TemplateSTRtreeDistance.h>
26 #include <geos/index/strtree/Interval.h>
27 
28 #include <vector>
29 #include <queue>
30 #include <mutex>
31 
32 namespace geos {
33 namespace index {
34 namespace strtree {
35 
56 template<typename ItemType, typename BoundsTraits>
58 public:
59  using Node = TemplateSTRNode<ItemType, BoundsTraits>;
60  using NodeList = std::vector<Node>;
61  using NodeListIterator = typename NodeList::iterator;
62  using BoundsType = typename BoundsTraits::BoundsType;
63 
64  class Iterator {
65  public:
66  using iterator_category = std::forward_iterator_tag;
67  using value_type = ItemType;
68  using difference_type = typename NodeList::const_iterator::difference_type;
69  using pointer = ItemType*;
70  using reference = ItemType&;
71 
72  Iterator(typename NodeList::const_iterator&& iter,
73  typename NodeList::const_iterator&& end) : m_iter(iter), m_end(end) {
74  skipDeleted();
75  }
76 
77  const ItemType& operator*() const {
78  return m_iter->getItem();
79  }
80 
81  Iterator& operator++() {
82  m_iter++;
83  skipDeleted();
84  return *this;
85  }
86 
87  friend bool operator==(const Iterator& a, const Iterator& b) {
88  return a.m_iter == b.m_iter;
89  }
90 
91  friend bool operator!=(const Iterator& a, const Iterator& b) {
92  return a.m_iter != b.m_iter;
93  }
94 
95  private:
96  void skipDeleted() {
97  while(m_iter != m_end && m_iter->isDeleted()) {
98  m_iter++;
99  }
100  }
101 
102  typename NodeList::const_iterator m_iter;
103  typename NodeList::const_iterator m_end;
104  };
105 
106  class Items {
107  public:
108  explicit Items(TemplateSTRtreeImpl& tree) : m_tree(tree) {}
109 
110  Iterator begin() {
111  return Iterator(m_tree.nodes.cbegin(),
112  std::next(m_tree.nodes.cbegin(), static_cast<long>(m_tree.numItems)));
113  }
114 
115  Iterator end() {
116  return Iterator(std::next(m_tree.nodes.cbegin(), static_cast<long>(m_tree.numItems)),
117  std::next(m_tree.nodes.cbegin(), static_cast<long>(m_tree.numItems)));
118  }
119  private:
120  TemplateSTRtreeImpl& m_tree;
121  };
122 
125 
130  explicit TemplateSTRtreeImpl(size_t p_nodeCapacity = 10) :
131  root(nullptr),
132  nodeCapacity(p_nodeCapacity),
133  numItems(0)
134  {}
135 
141  TemplateSTRtreeImpl(size_t p_nodeCapacity, size_t itemCapacity) :
142  root(nullptr),
143  nodeCapacity(p_nodeCapacity),
144  numItems(0) {
145  auto finalSize = treeSize(itemCapacity);
146  nodes.reserve(finalSize);
147  }
148 
153  root(other.root),
154  nodeCapacity(other.nodeCapacity),
155  numItems(other.numItems) {
156  nodes = other.nodes;
157  }
158 
159  TemplateSTRtreeImpl& operator=(TemplateSTRtreeImpl other)
160  {
161  root = other.root;
162  nodeCapacity = other.nodeCapacity;
163  numItems = other.numItems;
164  nodes = other.nodes;
165  return *this;
166  }
167 
171 
173  void insert(ItemType&& item) {
174  insert(BoundsTraits::fromItem(item), std::forward<ItemType>(item));
175  }
176 
178  void insert(const ItemType& item) {
179  insert(BoundsTraits::fromItem(item), item);
180  }
181 
183  void insert(const BoundsType& itemEnv, ItemType&& item) {
184  if (!BoundsTraits::isNull(itemEnv)) {
185  createLeafNode(std::forward<ItemType>(item), itemEnv);
186  }
187  }
188 
190  void insert(const BoundsType& itemEnv, const ItemType& item) {
191  if (!BoundsTraits::isNull(itemEnv)) {
192  createLeafNode(item, itemEnv);
193  }
194  }
195 
199 
201  template<typename ItemDistance>
202  std::pair<ItemType, ItemType> nearestNeighbour(ItemDistance& distance) {
203  return nearestNeighbour(*this, distance);
204  }
205 
207  template<typename ItemDistance>
208  std::pair<ItemType, ItemType> nearestNeighbour() {
209  return nearestNeighbour(*this);
210  }
211 
213  template<typename ItemDistance>
214  std::pair<ItemType, ItemType> nearestNeighbour(TemplateSTRtreeImpl<ItemType, BoundsTraits> & other,
215  ItemDistance & distance) {
216  if (!getRoot() || !other.getRoot()) {
217  return { nullptr, nullptr };
218  }
219 
220  TemplateSTRtreeDistance<ItemType, BoundsTraits, ItemDistance> td(distance);
221  return td.nearestNeighbour(*root, *other.root);
222  }
223 
225  template<typename ItemDistance>
226  std::pair<ItemType, ItemType> nearestNeighbour(TemplateSTRtreeImpl<ItemType, BoundsTraits>& other) {
227  ItemDistance id;
228  return nearestNeighbour(other, id);
229  }
230 
231  template<typename ItemDistance>
232  ItemType nearestNeighbour(const BoundsType& env, const ItemType& item, ItemDistance& itemDist) {
233  build();
234 
235  if (getRoot() == nullptr) {
236  return nullptr;
237  }
238 
239  TemplateSTRNode<ItemType, BoundsTraits> bnd(item, env);
240  TemplateSTRNodePair<ItemType, BoundsTraits, ItemDistance> pair(*getRoot(), bnd, itemDist);
241 
242  TemplateSTRtreeDistance<ItemType, BoundsTraits, ItemDistance> td(itemDist);
243  return td.nearestNeighbour(pair).first;
244  }
245 
246  template<typename ItemDistance>
247  ItemType nearestNeighbour(const BoundsType& env, const ItemType& item) {
248  ItemDistance id;
249  return nearestNeighbour(env, item, id);
250  }
251 
252  template<typename ItemDistance>
253  bool isWithinDistance(TemplateSTRtreeImpl<ItemType, BoundsTraits>& other, double maxDistance) {
254  ItemDistance itemDist;
255 
256  if (!getRoot() || !other.getRoot()) {
257  return false;
258  }
259 
260  TemplateSTRtreeDistance<ItemType, BoundsTraits, ItemDistance> td(itemDist);
261  return td.isWithinDistance(*root, *other.root, maxDistance);
262  }
263 
267 
268  // Query the tree using the specified visitor. The visitor must be callable
269  // either with a single argument of `const ItemType&` or with the
270  // arguments `(const BoundsType&, const ItemType&).
271  // The visitor need not return a value, but if it does return a value,
272  // false values will be taken as a signal to stop the query.
273  template<typename Visitor>
274  void query(const BoundsType& queryEnv, Visitor &&visitor) {
275  if (!built()) {
276  build();
277  }
278 
279  if (root && root->boundsIntersect(queryEnv)) {
280  if (root->isLeaf()) {
281  visitLeaf(visitor, *root);
282  } else {
283  query(queryEnv, *root, visitor);
284  }
285  }
286  }
287 
288  // Query the tree for all pairs whose bounds intersect. The visitor must
289  // be callable with arguments (const ItemType&, const ItemType&).
290  // The visitor will be called for each pair once, with first-inserted
291  // item used for the first argument.
292  // The visitor need not return a value, but if it does return a value,
293  // false values will be taken as a signal to stop the query.
294  template<typename Visitor>
295  void queryPairs(Visitor&& visitor) {
296  if (!built()) {
297  build();
298  }
299 
300  if (numItems < 2) {
301  return;
302  }
303 
304  for (std::size_t i = 0; i < numItems; i++) {
305  queryPairs(nodes[i], *root, visitor);
306  }
307  }
308 
309  // Query the tree and collect items in the provided vector.
310  void query(const BoundsType& queryEnv, std::vector<ItemType>& results) {
311  query(queryEnv, [&results](const ItemType& x) {
312  results.push_back(x);
313  });
314  }
315 
319  Items items() {
320  build();
321  return Items(*this);
322  }
323 
328  template<typename F>
329  void iterate(F&& func) {
330  auto n = built() ? numItems : nodes.size();
331  for (size_t i = 0; i < n; i++) {
332  if (!nodes[i].isDeleted()) {
333  func(nodes[i].getItem());
334  }
335  }
336  }
337 
341 
342  bool remove(const BoundsType& itemEnv, const ItemType& item) {
343  build();
344 
345  if (root == nullptr) {
346  return false;
347  }
348 
349  if (root->isLeaf()) {
350  if (!root->isDeleted() && root->getItem() == item) {
351  root->removeItem();
352  return true;
353  }
354  return false;
355  }
356 
357  return remove(itemEnv, *root, item);
358  }
359 
363 
365  bool built() const {
366  return root != nullptr;
367  }
368 
370  const Node* getRoot() {
371  build();
372  return root;
373  }
374 
376 
378  void build() {
379  std::lock_guard<std::mutex> lock(lock_);
380 
381  if (built()) {
382  return;
383  }
384 
385  if (nodes.empty()) {
386  return;
387  }
388 
389  numItems = nodes.size();
390 
391  // compute final size of tree and set it aside in a single
392  // block of memory
393  auto finalSize = treeSize(numItems);
394  nodes.reserve(finalSize);
395 
396  // begin and end define a range of nodes needing parents
397  auto begin = nodes.begin();
398  auto number = static_cast<size_t>(std::distance(begin, nodes.end()));
399 
400  while (number > 1) {
401  createParentNodes(begin, number);
402  std::advance(begin, static_cast<long>(number)); // parents just added become children in the next round
403  number = static_cast<size_t>(std::distance(begin, nodes.end()));
404  }
405 
406  assert(finalSize == nodes.size());
407 
408  root = &nodes.back();
409  }
410 
411 protected:
412  std::mutex lock_;
413  NodeList nodes; //**< a list of all leaf and branch nodes in the tree. */
414  Node* root; //**< a pointer to the root node, if the tree has been built. */
415  size_t nodeCapacity; //*< maximum number of children of each node */
416  size_t numItems; //*< total number of items in the tree, if it has been built. */
417 
418  // Prevent instantiation of base class.
419  // ~TemplateSTRtreeImpl() = default;
420 
421  void createLeafNode(ItemType&& item, const BoundsType& env) {
422  nodes.emplace_back(std::forward<ItemType>(item), env);
423  }
424 
425  void createLeafNode(const ItemType& item, const BoundsType& env) {
426  nodes.emplace_back(item, env);
427  }
428 
429  void createBranchNode(const Node *begin, const Node *end) {
430  assert(nodes.size() < nodes.capacity());
431  nodes.emplace_back(begin, end);
432  }
433 
434  // calculate what the tree size will be when it is build. This is simply
435  // a version of createParentNodes that doesn't actually create anything.
436  size_t treeSize(size_t numLeafNodes) {
437  size_t nodesInTree = numLeafNodes;
438 
439  size_t nodesWithoutParents = numLeafNodes;
440  while (nodesWithoutParents > 1) {
441  auto numSlices = sliceCount(nodesWithoutParents);
442  auto nodesPerSlice = sliceCapacity(nodesWithoutParents, numSlices);
443 
444  size_t parentNodesAdded = 0;
445  for (size_t j = 0; j < numSlices; j++) {
446  auto nodesInSlice = std::min(nodesWithoutParents, nodesPerSlice);
447  nodesWithoutParents -= nodesInSlice;
448 
449  parentNodesAdded += static_cast<size_t>(std::ceil(
450  static_cast<double>(nodesInSlice) / static_cast<double>(nodeCapacity)));
451  }
452 
453  nodesInTree += parentNodesAdded;
454  nodesWithoutParents = parentNodesAdded;
455  }
456 
457  return nodesInTree;
458  }
459 
460  void createParentNodes(const NodeListIterator& begin, size_t number) {
461  // Arrange child nodes in two dimensions.
462  // First, divide them into vertical slices of a given size (left-to-right)
463  // Then create nodes within those slices (bottom-to-top)
464  auto numSlices = sliceCount(number);
465  std::size_t nodesPerSlice = sliceCapacity(number, numSlices);
466 
467  // We could sort all of the nodes here, but we don't actually need them to be
468  // completely sorted. They need to be sorted enough for each node to end up
469  // in the right vertical slice, but their relative position within the slice
470  // doesn't matter. So we do a partial sort for each slice below instead.
471  auto end = begin + static_cast<long>(number);
472  sortNodesX(begin, end);
473 
474  auto startOfSlice = begin;
475  for (decltype(numSlices) j = 0; j < numSlices; j++) {
476  // end iterator is being invalidated at each iteration
477  end = begin + static_cast<long>(number);
478  auto nodesRemaining = static_cast<size_t>(std::distance(startOfSlice, end));
479  auto nodesInSlice = std::min(nodesRemaining, nodesPerSlice);
480  auto endOfSlice = std::next(startOfSlice, static_cast<long>(nodesInSlice));
481 
482  // Make sure that every node that should be in this slice ends up somewhere
483  // between startOfSlice and endOfSlice. We don't require any ordering among
484  // nodes between startOfSlice and endOfSlice.
485  //partialSortNodes(startOfSlice, endOfSlice, end);
486 
487  addParentNodesFromVerticalSlice(startOfSlice, endOfSlice);
488 
489  startOfSlice = endOfSlice;
490  }
491  }
492 
493  void addParentNodesFromVerticalSlice(const NodeListIterator& begin, const NodeListIterator& end) {
494  if (BoundsTraits::TwoDimensional::value) {
495  sortNodesY(begin, end);
496  }
497 
498  // Arrange the nodes vertically and full up parent nodes sequentially until they're full.
499  // A possible improvement would be to rework this such so that if we have 81 nodes we
500  // put 9 into each parent instead of 10 or 1.
501  auto firstChild = begin;
502  while (firstChild != end) {
503  auto childrenRemaining = static_cast<size_t>(std::distance(firstChild, end));
504  auto childrenForNode = std::min(nodeCapacity, childrenRemaining);
505  auto lastChild = std::next(firstChild, static_cast<long>(childrenForNode));
506 
507  //partialSortNodes(firstChild, lastChild, end);
508 
509  // Ideally we would be able to store firstChild and lastChild instead of
510  // having to convert them to pointers, but I wasn't sure how to access
511  // the NodeListIterator type from within Node without creating some weird
512  // circular dependency.
513  const Node *ptr_first = &*firstChild;
514  const Node *ptr_end = ptr_first + childrenForNode;
515 
516  createBranchNode(ptr_first, ptr_end);
517  firstChild = lastChild;
518  }
519  }
520 
521  void sortNodesX(const NodeListIterator& begin, const NodeListIterator& end) {
522  std::sort(begin, end, [](const Node &a, const Node &b) {
523  return BoundsTraits::getX(a.getBounds()) < BoundsTraits::getX(b.getBounds());
524  });
525  }
526 
527  void sortNodesY(const NodeListIterator& begin, const NodeListIterator& end) {
528  std::sort(begin, end, [](const Node &a, const Node &b) {
529  return BoundsTraits::getY(a.getBounds()) < BoundsTraits::getY(b.getBounds());
530  });
531  }
532 
533  // Helper function to visit an item using a visitor that has no return value.
534  // In this case, we will always return true, indicating that querying should
535  // continue.
536  template<typename Visitor,
537  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
538  bool visitLeaf(Visitor&& visitor, const Node& node)
539  {
540  visitor(node.getItem());
541  return true;
542  }
543 
544  template<typename Visitor,
545  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
546  bool visitLeaves(Visitor&& visitor, const Node& node1, const Node& node2)
547  {
548  visitor(node1.getItem(), node2.getItem());
549  return true;
550  }
551 
552  // MSVC 2015 does not implement C++11 expression SFINAE and considers this a
553  // redefinition of a previous method
554 #if !defined(_MSC_VER) || _MSC_VER >= 1910
555  template<typename Visitor,
556  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<BoundsType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
557  bool visitLeaf(Visitor&& visitor, const Node& node)
558  {
559  visitor(node.getBounds(), node.getItem());
560  return true;
561  }
562 #endif
563 
564  // If the visitor function does return a value, we will use this to indicate
565  // that querying should continue.
566  template<typename Visitor,
567  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr>
568  bool visitLeaf(Visitor&& visitor, const Node& node)
569  {
570  return visitor(node.getItem());
571  }
572 
573  template<typename Visitor,
574  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
575  bool visitLeaves(Visitor&& visitor, const Node& node1, const Node& node2)
576  {
577  return visitor(node1.getItem(), node2.getItem());
578  }
579 
580  // MSVC 2015 does not implement C++11 expression SFINAE and considers this a
581  // redefinition of a previous method
582 #if !defined(_MSC_VER) || _MSC_VER >= 1910
583  template<typename Visitor,
584  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<BoundsType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr>
585  bool visitLeaf(Visitor&& visitor, const Node& node)
586  {
587  return visitor(node.getBounds(), node.getItem());
588  }
589 #endif
590 
591  template<typename Visitor>
592  bool query(const BoundsType& queryEnv,
593  const Node& node,
594  Visitor&& visitor) {
595 
596  assert(!node.isLeaf());
597 
598  for (auto *child = node.beginChildren(); child < node.endChildren(); ++child) {
599  if (child->boundsIntersect(queryEnv)) {
600  if (child->isLeaf()) {
601  if (!child->isDeleted()) {
602  if (!visitLeaf(visitor, *child)) {
603  return false; // abort query
604  }
605  }
606  } else {
607  if (!query(queryEnv, *child, visitor)) {
608  return false; // abort query
609  }
610  }
611  }
612  }
613  return true; // continue searching
614  }
615 
616  template<typename Visitor>
617  bool queryPairs(const Node& queryNode,
618  const Node& searchNode,
619  Visitor&& visitor) {
620 
621  assert(!searchNode.isLeaf());
622 
623  for (auto* child = searchNode.beginChildren(); child < searchNode.endChildren(); ++child) {
624  if (child->isLeaf()) {
625  // Only visit leaf nodes if they have a higher address than the query node,
626  // to avoid processing the same pairs twice.
627  if (child > &queryNode && !child->isDeleted() && child->boundsIntersect(queryNode.getBounds())) {
628  if (!visitLeaves(visitor, queryNode, *child)) {
629  return false; // abort query
630  }
631  }
632  } else {
633  if (child->boundsIntersect(queryNode.getBounds())) {
634  if (!queryPairs(queryNode, *child, visitor)) {
635  return false; // abort query
636  }
637  }
638  }
639  }
640 
641  return true; // continue searching
642  }
643 
644  bool remove(const BoundsType& queryEnv,
645  const Node& node,
646  const ItemType& item) {
647 
648  assert(!node.isLeaf());
649 
650  for (auto *child = node.beginChildren(); child < node.endChildren(); ++child) {
651  if (child->boundsIntersect(queryEnv)) {
652  if (child->isLeaf()) {
653  if (!child->isDeleted() && child->getItem() == item) {
654  // const cast is ugly, but alternative seems to be to remove all
655  // const qualifiers in Node and open up mutability everywhere?
656  auto mutableChild = const_cast<Node*>(child);
657  mutableChild->removeItem();
658  return true;
659  }
660  } else {
661  bool removed = remove(queryEnv, *child, item);
662  if (removed) {
663  return true;
664  }
665  }
666  }
667  }
668 
669  return false;
670  }
671 
672  size_t sliceCount(size_t numNodes) const {
673  double minLeafCount = std::ceil(static_cast<double>(numNodes) / static_cast<double>(nodeCapacity));
674 
675  return static_cast<size_t>(std::ceil(std::sqrt(minLeafCount)));
676  }
677 
678  static size_t sliceCapacity(size_t numNodes, size_t numSlices) {
679  return static_cast<size_t>(std::ceil(static_cast<double>(numNodes) / static_cast<double>(numSlices)));
680  }
681 };
682 
683 struct EnvelopeTraits {
684  using BoundsType = geom::Envelope;
685  using TwoDimensional = std::true_type;
686 
687  static bool intersects(const BoundsType& a, const BoundsType& b) {
688  return a.intersects(b);
689  }
690 
691  static double size(const BoundsType& a) {
692  return a.getArea();
693  }
694 
695  static double distance(const BoundsType& a, const BoundsType& b) {
696  return a.distance(b);
697  }
698 
699  static double maxDistance(const BoundsType& a, const BoundsType& b) {
700  return a.maxDistance(b);
701  }
702 
703  static BoundsType empty() {
704  return {};
705  }
706 
707  template<typename ItemType>
708  static const BoundsType& fromItem(const ItemType& i) {
709  return *(i->getEnvelopeInternal());
710  }
711 
712  template<typename ItemType>
713  static const BoundsType& fromItem(ItemType&& i) {
714  return *(i->getEnvelopeInternal());
715  }
716 
717  static double getX(const BoundsType& a) {
718  return a.getMinX() + a.getMaxX();
719  }
720 
721  static double getY(const BoundsType& a) {
722  return a.getMinY() + a.getMaxY();
723  }
724 
725  static void expandToInclude(BoundsType& a, const BoundsType& b) {
726  a.expandToInclude(b);
727  }
728 
729  static bool isNull(const BoundsType& a) {
730  return a.isNull();
731  }
732 };
733 
734 struct IntervalTraits {
735  using BoundsType = Interval;
736  using TwoDimensional = std::false_type;
737 
738  static bool intersects(const BoundsType& a, const BoundsType& b) {
739  return a.intersects(&b);
740  }
741 
742  static double size(const BoundsType& a) {
743  return a.getWidth();
744  }
745 
746  static double getX(const BoundsType& a) {
747  return a.getMin() + a.getMax();
748  }
749 
750  static double getY(const BoundsType& a) {
751  return a.getMin() + a.getMax();
752  }
753 
754  static void expandToInclude(BoundsType& a, const BoundsType& b) {
755  a.expandToInclude(&b);
756  }
757 
758  static bool isNull(const BoundsType& a) {
759  (void) a;
760  return false;
761  }
762 };
763 
764 
765 template<typename ItemType, typename BoundsTraits = EnvelopeTraits>
766 class TemplateSTRtree : public TemplateSTRtreeImpl<ItemType, BoundsTraits> {
767 public:
769 };
770 
771 // When ItemType is a pointer and our bounds are geom::Envelope, adopt
772 // the SpatialIndex interface which requires queries via an envelope
773 // and items to be representable as void*.
774 template<typename ItemType>
775 class TemplateSTRtree<ItemType*, EnvelopeTraits> : public TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>, public SpatialIndex {
776 public:
779  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::query;
780  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::remove;
781 
782  // The SpatialIndex methods only work when we are storing a pointer type.
783  void query(const geom::Envelope* queryEnv, std::vector<void*>& results) override {
784  query(*queryEnv, [&results](const ItemType* x) {
785  results.push_back(const_cast<void*>(static_cast<const void*>(x)));
786  });
787  }
788 
789  void query(const geom::Envelope* queryEnv, ItemVisitor& visitor) override {
790  query(*queryEnv, [&visitor](const ItemType* x) {
791  visitor.visitItem(const_cast<void*>(static_cast<const void*>(x)));
792  });
793  }
794 
795  bool remove(const geom::Envelope* itemEnv, void* item) override {
796  return remove(*itemEnv, static_cast<ItemType*>(item));
797  }
798 
799  void insert(const geom::Envelope* itemEnv, void* item) override {
800  insert(*itemEnv, std::move(static_cast<ItemType*>(item)));
801  }
802 };
803 
804 
805 }
806 }
807 }
A function method which computes the distance between two ItemBoundables in an STRtree....
Definition: ItemDistance.h:33
A query-only R-tree created using the Sort-Tile-Recursive (STR) algorithm. For one- or two-dimensiona...
Definition: TemplateSTRtree.h:57
void build()
Definition: TemplateSTRtree.h:378
std::pair< ItemType, ItemType > nearestNeighbour(TemplateSTRtreeImpl< ItemType, BoundsTraits > &other)
Definition: TemplateSTRtree.h:226
std::pair< ItemType, ItemType > nearestNeighbour(ItemDistance &distance)
Definition: TemplateSTRtree.h:202
std::pair< ItemType, ItemType > nearestNeighbour(TemplateSTRtreeImpl< ItemType, BoundsTraits > &other, ItemDistance &distance)
Definition: TemplateSTRtree.h:214
std::pair< ItemType, ItemType > nearestNeighbour()
Definition: TemplateSTRtree.h:208
TemplateSTRtreeImpl(size_t p_nodeCapacity=10)
Definition: TemplateSTRtree.h:130
TemplateSTRtreeImpl(size_t p_nodeCapacity, size_t itemCapacity)
Definition: TemplateSTRtree.h:141
TemplateSTRtreeImpl(const TemplateSTRtreeImpl &other)
Definition: TemplateSTRtree.h:152
void insert(const BoundsType &itemEnv, const ItemType &item)
Definition: TemplateSTRtree.h:190
void insert(const ItemType &item)
Definition: TemplateSTRtree.h:178
void insert(ItemType &&item)
Definition: TemplateSTRtree.h:173
void insert(const BoundsType &itemEnv, ItemType &&item)
Definition: TemplateSTRtree.h:183
const Node * getRoot()
Definition: TemplateSTRtree.h:370
bool built() const
Definition: TemplateSTRtree.h:365
void iterate(F &&func)
Definition: TemplateSTRtree.h:329
Items items()
Definition: TemplateSTRtree.h:319
Basic namespace for all GEOS functionalities.
Definition: Angle.h:25