GEOS  3.10.0
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  ItemDistance id;
210  return nearestNeighbour(*this);
211  }
212 
214  template<typename ItemDistance>
215  std::pair<ItemType, ItemType> nearestNeighbour(TemplateSTRtreeImpl<ItemType, BoundsTraits> & other,
216  ItemDistance & distance) {
217  if (!getRoot() || !other.getRoot()) {
218  return { nullptr, nullptr };
219  }
220 
221  TemplateSTRtreeDistance<ItemType, BoundsTraits, ItemDistance> td(distance);
222  return td.nearestNeighbour(*root, *other.root);
223  }
224 
226  template<typename ItemDistance>
227  std::pair<ItemType, ItemType> nearestNeighbour(TemplateSTRtreeImpl<ItemType, BoundsTraits>& other) {
228  ItemDistance id;
229  return nearestNeighbour(other, id);
230  }
231 
232  template<typename ItemDistance>
233  ItemType nearestNeighbour(const BoundsType& env, const ItemType& item, ItemDistance& itemDist) {
234  build();
235 
236  if (getRoot() == nullptr) {
237  return nullptr;
238  }
239 
240  TemplateSTRNode<ItemType, BoundsTraits> bnd(item, env);
241  TemplateSTRNodePair<ItemType, BoundsTraits, ItemDistance> pair(*getRoot(), bnd, itemDist);
242 
243  TemplateSTRtreeDistance<ItemType, BoundsTraits, ItemDistance> td(itemDist);
244  return td.nearestNeighbour(pair).first;
245  }
246 
247  template<typename ItemDistance>
248  ItemType nearestNeighbour(const BoundsType& env, const ItemType& item) {
249  ItemDistance id;
250  return nearestNeighbour(env, item, id);
251  }
252 
256 
257  // Query the tree using the specified visitor. The visitor must be callable
258  // either with a single argument of `const ItemType&` or with the
259  // arguments `(const BoundsType&, const ItemType&).
260  // The visitor need not return a value, but if it does return a value,
261  // false values will be taken as a signal to stop the query.
262  template<typename Visitor>
263  void query(const BoundsType& queryEnv, Visitor &&visitor) {
264  if (!built()) {
265  build();
266  }
267 
268  if (root && root->boundsIntersect(queryEnv)) {
269  if (root->isLeaf()) {
270  visitLeaf(visitor, *root);
271  } else {
272  query(queryEnv, *root, visitor);
273  }
274  }
275  }
276 
277  // Query the tree and collect items in the provided vector.
278  void query(const BoundsType& queryEnv, std::vector<ItemType>& results) {
279  query(queryEnv, [&results](const ItemType& x) {
280  results.push_back(x);
281  });
282  }
283 
287  Items items() {
288  build();
289  return Items(*this);
290  }
291 
296  template<typename F>
297  void iterate(F&& func) {
298  auto n = built() ? numItems : nodes.size();
299  for (size_t i = 0; i < n; i++) {
300  func(nodes[i].getItem());
301  }
302  }
303 
307 
308  bool remove(const BoundsType& itemEnv, const ItemType& item) {
309  if (root == nullptr) {
310  return false;
311  }
312 
313  if (root->isLeaf()) {
314  if (!root->isDeleted() && root->getItem() == item) {
315  root->removeItem();
316  return true;
317  }
318  return false;
319  }
320 
321  return remove(itemEnv, *root, item);
322  }
323 
327 
329  bool built() const {
330  return root != nullptr;
331  }
332 
334  const Node* getRoot() {
335  build();
336  return root;
337  }
338 
340 
342  void build() {
343  std::lock_guard<std::mutex> lock(lock_);
344 
345  if (built()) {
346  return;
347  }
348 
349  if (nodes.empty()) {
350  return;
351  }
352 
353  numItems = nodes.size();
354 
355  // compute final size of tree and set it aside in a single
356  // block of memory
357  auto finalSize = treeSize(numItems);
358  nodes.reserve(finalSize);
359 
360  // begin and end define a range of nodes needing parents
361  auto begin = nodes.begin();
362  auto end = nodes.end();
363 
364  while (std::distance(begin, end) > 1) {
365  createParentNodes(begin, end);
366  begin = end; // parents just added become children in the next round
367  end = nodes.end();
368  }
369 
370  assert(finalSize == nodes.size());
371 
372  root = &nodes.back();
373  }
374 
375 protected:
376  std::mutex lock_;
377  NodeList nodes; //**< a list of all leaf and branch nodes in the tree. */
378  Node* root; //**< a pointer to the root node, if the tree has been built. */
379  size_t nodeCapacity; //*< maximum number of children of each node */
380  size_t numItems; //*< total number of items in the tree, if it has been built. */
381 
382  // Prevent instantiation of base class.
383  // ~TemplateSTRtreeImpl() = default;
384 
385  void createLeafNode(ItemType&& item, const BoundsType& env) {
386  nodes.emplace_back(std::forward<ItemType>(item), env);
387  }
388 
389  void createLeafNode(const ItemType& item, const BoundsType& env) {
390  nodes.emplace_back(item, env);
391  }
392 
393  void createBranchNode(const Node *begin, const Node *end) {
394  assert(nodes.size() < nodes.capacity());
395  nodes.emplace_back(begin, end);
396  }
397 
398  // calculate what the tree size will be when it is build. This is simply
399  // a version of createParentNodes that doesn't actually create anything.
400  size_t treeSize(size_t numLeafNodes) {
401  size_t nodesInTree = numLeafNodes;
402 
403  size_t nodesWithoutParents = numLeafNodes;
404  while (nodesWithoutParents > 1) {
405  auto numSlices = sliceCount(nodesWithoutParents);
406  auto nodesPerSlice = sliceCapacity(nodesWithoutParents, numSlices);
407 
408  size_t parentNodesAdded = 0;
409  for (size_t j = 0; j < numSlices; j++) {
410  auto nodesInSlice = std::min(nodesWithoutParents, nodesPerSlice);
411  nodesWithoutParents -= nodesInSlice;
412 
413  parentNodesAdded += static_cast<size_t>(std::ceil(
414  static_cast<double>(nodesInSlice) / static_cast<double>(nodeCapacity)));
415  }
416 
417  nodesInTree += parentNodesAdded;
418  nodesWithoutParents = parentNodesAdded;
419  }
420 
421  return nodesInTree;
422  }
423 
424  void createParentNodes(const NodeListIterator& begin, const NodeListIterator& end) {
425  // Arrange child nodes in two dimensions.
426  // First, divide them into vertical slices of a given size (left-to-right)
427  // Then create nodes within those slices (bottom-to-top)
428  auto numChildren = static_cast<std::size_t>(std::distance(begin, end));
429  auto numSlices = sliceCount(numChildren);
430  std::size_t nodesPerSlice = sliceCapacity(numChildren, numSlices);
431 
432  // We could sort all of the nodes here, but we don't actually need them to be
433  // completely sorted. They need to be sorted enough for each node to end up
434  // in the right vertical slice, but their relative position within the slice
435  // doesn't matter. So we do a partial sort for each slice below instead.
436  sortNodesX(begin, end);
437 
438  auto startOfSlice = begin;
439  for (decltype(numSlices) j = 0; j < numSlices; j++) {
440  auto nodesRemaining = static_cast<size_t>(std::distance(startOfSlice, end));
441  auto nodesInSlice = std::min(nodesRemaining, nodesPerSlice);
442  auto endOfSlice = std::next(startOfSlice, static_cast<long>(nodesInSlice));
443 
444  // Make sure that every node that should be in this slice ends up somewhere
445  // between startOfSlice and endOfSlice. We don't require any ordering among
446  // nodes between startOfSlice and endOfSlice.
447  //partialSortNodes(startOfSlice, endOfSlice, end);
448 
449  addParentNodesFromVerticalSlice(startOfSlice, endOfSlice);
450 
451  startOfSlice = endOfSlice;
452  }
453  }
454 
455  void addParentNodesFromVerticalSlice(const NodeListIterator& begin, const NodeListIterator& end) {
456  if (BoundsTraits::TwoDimensional::value) {
457  sortNodesY(begin, end);
458  }
459 
460  // Arrange the nodes vertically and full up parent nodes sequentially until they're full.
461  // A possible improvement would be to rework this such so that if we have 81 nodes we
462  // put 9 into each parent instead of 10 or 1.
463  auto firstChild = begin;
464  while (firstChild != end) {
465  auto childrenRemaining = static_cast<size_t>(std::distance(firstChild, end));
466  auto childrenForNode = std::min(nodeCapacity, childrenRemaining);
467  auto lastChild = std::next(firstChild, static_cast<long>(childrenForNode));
468 
469  //partialSortNodes(firstChild, lastChild, end);
470 
471  // Ideally we would be able to store firstChild and lastChild instead of
472  // having to convert them to pointers, but I wasn't sure how to access
473  // the NodeListIterator type from within Node without creating some weird
474  // circular dependency.
475  const Node *ptr_first = &*firstChild;
476  const Node *ptr_end = ptr_first + childrenForNode;
477 
478  createBranchNode(ptr_first, ptr_end);
479  firstChild = lastChild;
480  }
481  }
482 
483  void sortNodesX(const NodeListIterator& begin, const NodeListIterator& end) {
484  std::sort(begin, end, [](const Node &a, const Node &b) {
485  return BoundsTraits::getX(a.getBounds()) < BoundsTraits::getX(b.getBounds());
486  });
487  }
488 
489  void sortNodesY(const NodeListIterator& begin, const NodeListIterator& end) {
490  std::sort(begin, end, [](const Node &a, const Node &b) {
491  return BoundsTraits::getY(a.getBounds()) < BoundsTraits::getY(b.getBounds());
492  });
493  }
494 
495  // Helper function to visit an item using a visitor that has no return value.
496  // In this case, we will always return true, indicating that querying should
497  // continue.
498  template<typename Visitor,
499  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
500  bool visitLeaf(Visitor&& visitor, const Node& node)
501  {
502  visitor(node.getItem());
503  return true;
504  }
505 
506  // MSVC 2015 does not implement C++11 expression SFINAE and considers this a
507  // redefinition of a previous method
508 #if !defined(_MSC_VER) || _MSC_VER >= 1910
509  template<typename Visitor,
510  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<BoundsType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
511  bool visitLeaf(Visitor&& visitor, const Node& node)
512  {
513  visitor(node.getBounds(), node.getItem());
514  return true;
515  }
516 #endif
517 
518  // If the visitor function does return a value, we will use this to indicate
519  // that querying should continue.
520  template<typename Visitor,
521  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr>
522  bool visitLeaf(Visitor&& visitor, const Node& node)
523  {
524  return visitor(node.getItem());
525  }
526 
527  // MSVC 2015 does not implement C++11 expression SFINAE and considers this a
528  // redefinition of a previous method
529 #if !defined(_MSC_VER) || _MSC_VER >= 1910
530  template<typename Visitor,
531  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<BoundsType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr>
532  bool visitLeaf(Visitor&& visitor, const Node& node)
533  {
534  return visitor(node.getBounds(), node.getItem());
535  }
536 #endif
537 
538  template<typename Visitor>
539  void query(const BoundsType& queryEnv,
540  const Node& node,
541  Visitor&& visitor) {
542 
543  assert(!node.isLeaf());
544 
545  for (auto *child = node.beginChildren(); child < node.endChildren(); ++child) {
546  if (child->boundsIntersect(queryEnv)) {
547  if (child->isLeaf() && !child->isDeleted()) {
548  if (!visitLeaf(visitor, *child)) {
549  return;
550  }
551  } else {
552  query(queryEnv, *child, visitor);
553  }
554  }
555  }
556  }
557 
558  bool remove(const BoundsType& queryEnv,
559  const Node& node,
560  const ItemType& item) {
561 
562  assert(!node.isLeaf());
563 
564  for (auto *child = node.beginChildren(); child < node.endChildren(); ++child) {
565  if (child->boundsIntersect(queryEnv)) {
566  if (child->isLeaf()) {
567  if (!child->isDeleted() && child->getItem() == item) {
568  // const cast is ugly, but alternative seems to be to remove all
569  // const qualifiers in Node and open up mutability everywhere?
570  auto mutableChild = const_cast<Node*>(child);
571  mutableChild->removeItem();
572  return true;
573  }
574  } else {
575  bool removed = remove(queryEnv, *child, item);
576  if (removed) {
577  return true;
578  }
579  }
580  }
581  }
582 
583  return false;
584  }
585 
586  size_t sliceCount(size_t numNodes) const {
587  double minLeafCount = std::ceil(static_cast<double>(numNodes) / static_cast<double>(nodeCapacity));
588 
589  return static_cast<size_t>(std::ceil(std::sqrt(minLeafCount)));
590  }
591 
592  static size_t sliceCapacity(size_t numNodes, size_t numSlices) {
593  return static_cast<size_t>(std::ceil(static_cast<double>(numNodes) / static_cast<double>(numSlices)));
594  }
595 };
596 
597 struct EnvelopeTraits {
598  using BoundsType = geom::Envelope;
599  using TwoDimensional = std::true_type;
600 
601  static bool intersects(const BoundsType& a, const BoundsType& b) {
602  return a.intersects(b);
603  }
604 
605  static double size(const BoundsType& a) {
606  return a.getArea();
607  }
608 
609  static double distance(const BoundsType& a, const BoundsType& b) {
610  return a.distance(b);
611  }
612 
613  static BoundsType empty() {
614  return {};
615  }
616 
617  template<typename ItemType>
618  static const BoundsType& fromItem(const ItemType& i) {
619  return *(i->getEnvelopeInternal());
620  }
621 
622  template<typename ItemType>
623  static const BoundsType& fromItem(ItemType&& i) {
624  return *(i->getEnvelopeInternal());
625  }
626 
627  static double getX(const BoundsType& a) {
628  return a.getMinX() + a.getMaxX();
629  }
630 
631  static double getY(const BoundsType& a) {
632  return a.getMinY() + a.getMaxY();
633  }
634 
635  static void expandToInclude(BoundsType& a, const BoundsType& b) {
636  a.expandToInclude(b);
637  }
638 
639  static bool isNull(const BoundsType& a) {
640  return a.isNull();
641  }
642 };
643 
644 struct IntervalTraits {
645  using BoundsType = Interval;
646  using TwoDimensional = std::false_type;
647 
648  static bool intersects(const BoundsType& a, const BoundsType& b) {
649  return a.intersects(&b);
650  }
651 
652  static double size(const BoundsType& a) {
653  return a.getWidth();
654  }
655 
656  static double getX(const BoundsType& a) {
657  return a.getMin() + a.getMax();
658  }
659 
660  static double getY(const BoundsType& a) {
661  return a.getMin() + a.getMax();
662  }
663 
664  static void expandToInclude(BoundsType& a, const BoundsType& b) {
665  a.expandToInclude(&b);
666  }
667 
668  static bool isNull(const BoundsType& a) {
669  (void) a;
670  return false;
671  }
672 };
673 
674 
675 template<typename ItemType, typename BoundsTraits = EnvelopeTraits>
676 class TemplateSTRtree : public TemplateSTRtreeImpl<ItemType, BoundsTraits> {
677 public:
679 };
680 
681 // When ItemType is a pointer and our bounds are geom::Envelope, adopt
682 // the SpatialIndex interface which requires queries via an envelope
683 // and items to be representable as void*.
684 template<typename ItemType>
685 class TemplateSTRtree<ItemType*, EnvelopeTraits> : public TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>, public SpatialIndex {
686 public:
689  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::query;
690  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::remove;
691 
692  // The SpatialIndex methods only work when we are storing a pointer type.
693  void query(const geom::Envelope* queryEnv, std::vector<void*>& results) override {
694  query(*queryEnv, [&results](const ItemType* x) {
695  results.push_back(const_cast<void*>(static_cast<const void*>(x)));
696  });
697  }
698 
699  void query(const geom::Envelope* queryEnv, ItemVisitor& visitor) override {
700  query(*queryEnv, [&visitor](const ItemType* x) {
701  visitor.visitItem(const_cast<void*>(static_cast<const void*>(x)));
702  });
703  }
704 
705  bool remove(const geom::Envelope* itemEnv, void* item) override {
706  return remove(*itemEnv, static_cast<ItemType*>(item));
707  }
708 
709  void insert(const geom::Envelope* itemEnv, void* item) override {
710  insert(*itemEnv, std::move(static_cast<ItemType*>(item)));
711  }
712 };
713 
714 
715 }
716 }
717 }
A function method which computes the distance between two ItemBoundables in an STRtree....
Definition: ItemDistance.h:34
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:342
std::pair< ItemType, ItemType > nearestNeighbour(TemplateSTRtreeImpl< ItemType, BoundsTraits > &other)
Definition: TemplateSTRtree.h:227
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:215
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:334
bool built() const
Definition: TemplateSTRtree.h:329
void iterate(F &&func)
Definition: TemplateSTRtree.h:297
Items items()
Definition: TemplateSTRtree.h:287
Basic namespace for all GEOS functionalities.
Definition: Angle.h:26