From 54954e780c66ac387fb8c10264b438970796caf2 Mon Sep 17 00:00:00 2001 From: dr-jts Date: Wed, 29 Nov 2023 22:14:55 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20libgeos/?= =?UTF-8?q?geos@635e833d6ccd6f6b97ffb5c5f84dda3bc4951700=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doxygen/TemplateSTRtree_8h_source.html | 1161 ++++++++++++------------ 1 file changed, 580 insertions(+), 581 deletions(-) diff --git a/doxygen/TemplateSTRtree_8h_source.html b/doxygen/TemplateSTRtree_8h_source.html index 23c96ec86b..ec9df77822 100644 --- a/doxygen/TemplateSTRtree_8h_source.html +++ b/doxygen/TemplateSTRtree_8h_source.html @@ -209,590 +209,589 @@
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 
-
253  template<typename ItemDistance>
-
254  bool isWithinDistance(TemplateSTRtreeImpl<ItemType, BoundsTraits>& other, double maxDistance) {
-
255  ItemDistance itemDist;
-
256 
-
257  if (!getRoot() || !other.getRoot()) {
-
258  return false;
-
259  }
-
260 
-
261  TemplateSTRtreeDistance<ItemType, BoundsTraits, ItemDistance> td(itemDist);
-
262  return td.isWithinDistance(*root, *other.root, maxDistance);
-
263  }
-
264 
-
268 
-
269  // Query the tree using the specified visitor. The visitor must be callable
-
270  // either with a single argument of `const ItemType&` or with the
-
271  // arguments `(const BoundsType&, const ItemType&).
-
272  // The visitor need not return a value, but if it does return a value,
-
273  // false values will be taken as a signal to stop the query.
-
274  template<typename Visitor>
-
275  void query(const BoundsType& queryEnv, Visitor &&visitor) {
-
276  if (!built()) {
-
277  build();
-
278  }
-
279 
-
280  if (root && root->boundsIntersect(queryEnv)) {
-
281  if (root->isLeaf()) {
-
282  visitLeaf(visitor, *root);
-
283  } else {
-
284  query(queryEnv, *root, visitor);
-
285  }
-
286  }
-
287  }
-
288 
-
289  // Query the tree for all pairs whose bounds intersect. The visitor must
-
290  // be callable with arguments (const ItemType&, const ItemType&).
-
291  // The visitor will be called for each pair once, with first-inserted
-
292  // item used for the first argument.
-
293  // The visitor need not return a value, but if it does return a value,
-
294  // false values will be taken as a signal to stop the query.
-
295  template<typename Visitor>
-
296  void queryPairs(Visitor&& visitor) {
-
297  if (!built()) {
-
298  build();
-
299  }
-
300 
-
301  if (numItems < 2) {
-
302  return;
-
303  }
-
304 
-
305  for (std::size_t i = 0; i < numItems; i++) {
-
306  queryPairs(nodes[i], *root, visitor);
-
307  }
-
308  }
-
309 
-
310  // Query the tree and collect items in the provided vector.
-
311  void query(const BoundsType& queryEnv, std::vector<ItemType>& results) {
-
312  query(queryEnv, [&results](const ItemType& x) {
-
313  results.push_back(x);
-
314  });
-
315  }
-
316 
-
320  Items items() {
-
321  build();
-
322  return Items(*this);
-
323  }
-
324 
-
329  template<typename F>
-
330  void iterate(F&& func) {
-
331  auto n = built() ? numItems : nodes.size();
-
332  for (size_t i = 0; i < n; i++) {
-
333  if (!nodes[i].isDeleted()) {
-
334  func(nodes[i].getItem());
-
335  }
-
336  }
-
337  }
-
338 
-
342 
-
343  bool remove(const BoundsType& itemEnv, const ItemType& item) {
-
344  build();
-
345 
-
346  if (root == nullptr) {
-
347  return false;
-
348  }
-
349 
-
350  if (root->isLeaf()) {
-
351  if (!root->isDeleted() && root->getItem() == item) {
-
352  root->removeItem();
-
353  return true;
-
354  }
-
355  return false;
-
356  }
-
357 
-
358  return remove(itemEnv, *root, item);
-
359  }
-
360 
-
364 
-
366  bool built() const {
-
367  return root != nullptr;
-
368  }
-
369 
-
371  const Node* getRoot() {
-
372  build();
-
373  return root;
-
374  }
-
375 
-
377 
-
379  void build() {
-
380  std::lock_guard<std::mutex> lock(lock_);
-
381 
-
382  if (built()) {
-
383  return;
-
384  }
-
385 
-
386  if (nodes.empty()) {
-
387  return;
-
388  }
-
389 
-
390  numItems = nodes.size();
-
391 
-
392  // compute final size of tree and set it aside in a single
-
393  // block of memory
-
394  auto finalSize = treeSize(numItems);
-
395  nodes.reserve(finalSize);
-
396 
-
397  // begin and end define a range of nodes needing parents
-
398  auto begin = nodes.begin();
-
399  auto number = static_cast<size_t>(std::distance(begin, nodes.end()));
-
400 
-
401  while (number > 1) {
-
402  createParentNodes(begin, number);
-
403  std::advance(begin, static_cast<long>(number)); // parents just added become children in the next round
-
404  number = static_cast<size_t>(std::distance(begin, nodes.end()));
-
405  }
-
406 
-
407  assert(finalSize == nodes.size());
-
408 
-
409  root = &nodes.back();
-
410  }
-
411 
-
412 protected:
-
413  std::mutex lock_;
-
414  NodeList nodes; //**< a list of all leaf and branch nodes in the tree. */
-
415  Node* root; //**< a pointer to the root node, if the tree has been built. */
-
416  size_t nodeCapacity; //*< maximum number of children of each node */
-
417  size_t numItems; //*< total number of items in the tree, if it has been built. */
-
418 
-
419  // Prevent instantiation of base class.
-
420  // ~TemplateSTRtreeImpl() = default;
-
421 
-
422  void createLeafNode(ItemType&& item, const BoundsType& env) {
-
423  nodes.emplace_back(std::forward<ItemType>(item), env);
-
424  }
-
425 
-
426  void createLeafNode(const ItemType& item, const BoundsType& env) {
-
427  nodes.emplace_back(item, env);
-
428  }
-
429 
-
430  void createBranchNode(const Node *begin, const Node *end) {
-
431  assert(nodes.size() < nodes.capacity());
-
432  nodes.emplace_back(begin, end);
-
433  }
-
434 
-
435  // calculate what the tree size will be when it is build. This is simply
-
436  // a version of createParentNodes that doesn't actually create anything.
-
437  size_t treeSize(size_t numLeafNodes) {
-
438  size_t nodesInTree = numLeafNodes;
-
439 
-
440  size_t nodesWithoutParents = numLeafNodes;
-
441  while (nodesWithoutParents > 1) {
-
442  auto numSlices = sliceCount(nodesWithoutParents);
-
443  auto nodesPerSlice = sliceCapacity(nodesWithoutParents, numSlices);
-
444 
-
445  size_t parentNodesAdded = 0;
-
446  for (size_t j = 0; j < numSlices; j++) {
-
447  auto nodesInSlice = std::min(nodesWithoutParents, nodesPerSlice);
-
448  nodesWithoutParents -= nodesInSlice;
-
449 
-
450  parentNodesAdded += static_cast<size_t>(std::ceil(
-
451  static_cast<double>(nodesInSlice) / static_cast<double>(nodeCapacity)));
-
452  }
-
453 
-
454  nodesInTree += parentNodesAdded;
-
455  nodesWithoutParents = parentNodesAdded;
-
456  }
-
457 
-
458  return nodesInTree;
-
459  }
-
460 
-
461  void createParentNodes(const NodeListIterator& begin, size_t number) {
-
462  // Arrange child nodes in two dimensions.
-
463  // First, divide them into vertical slices of a given size (left-to-right)
-
464  // Then create nodes within those slices (bottom-to-top)
-
465  auto numSlices = sliceCount(number);
-
466  std::size_t nodesPerSlice = sliceCapacity(number, numSlices);
-
467 
-
468  // We could sort all of the nodes here, but we don't actually need them to be
-
469  // completely sorted. They need to be sorted enough for each node to end up
-
470  // in the right vertical slice, but their relative position within the slice
-
471  // doesn't matter. So we do a partial sort for each slice below instead.
-
472  auto end = begin + static_cast<long>(number);
-
473  sortNodesX(begin, end);
-
474 
-
475  auto startOfSlice = begin;
-
476  for (decltype(numSlices) j = 0; j < numSlices; j++) {
-
477  // end iterator is being invalidated at each iteration
-
478  end = begin + static_cast<long>(number);
-
479  auto nodesRemaining = static_cast<size_t>(std::distance(startOfSlice, end));
-
480  auto nodesInSlice = std::min(nodesRemaining, nodesPerSlice);
-
481  auto endOfSlice = std::next(startOfSlice, static_cast<long>(nodesInSlice));
-
482 
-
483  // Make sure that every node that should be in this slice ends up somewhere
-
484  // between startOfSlice and endOfSlice. We don't require any ordering among
-
485  // nodes between startOfSlice and endOfSlice.
-
486  //partialSortNodes(startOfSlice, endOfSlice, end);
-
487 
-
488  addParentNodesFromVerticalSlice(startOfSlice, endOfSlice);
-
489 
-
490  startOfSlice = endOfSlice;
-
491  }
-
492  }
-
493 
-
494  void addParentNodesFromVerticalSlice(const NodeListIterator& begin, const NodeListIterator& end) {
-
495  if (BoundsTraits::TwoDimensional::value) {
-
496  sortNodesY(begin, end);
-
497  }
-
498 
-
499  // Arrange the nodes vertically and full up parent nodes sequentially until they're full.
-
500  // A possible improvement would be to rework this such so that if we have 81 nodes we
-
501  // put 9 into each parent instead of 10 or 1.
-
502  auto firstChild = begin;
-
503  while (firstChild != end) {
-
504  auto childrenRemaining = static_cast<size_t>(std::distance(firstChild, end));
-
505  auto childrenForNode = std::min(nodeCapacity, childrenRemaining);
-
506  auto lastChild = std::next(firstChild, static_cast<long>(childrenForNode));
-
507 
-
508  //partialSortNodes(firstChild, lastChild, end);
-
509 
-
510  // Ideally we would be able to store firstChild and lastChild instead of
-
511  // having to convert them to pointers, but I wasn't sure how to access
-
512  // the NodeListIterator type from within Node without creating some weird
-
513  // circular dependency.
-
514  const Node *ptr_first = &*firstChild;
-
515  const Node *ptr_end = ptr_first + childrenForNode;
-
516 
-
517  createBranchNode(ptr_first, ptr_end);
-
518  firstChild = lastChild;
-
519  }
-
520  }
-
521 
-
522  void sortNodesX(const NodeListIterator& begin, const NodeListIterator& end) {
-
523  std::sort(begin, end, [](const Node &a, const Node &b) {
-
524  return BoundsTraits::getX(a.getBounds()) < BoundsTraits::getX(b.getBounds());
-
525  });
-
526  }
-
527 
-
528  void sortNodesY(const NodeListIterator& begin, const NodeListIterator& end) {
-
529  std::sort(begin, end, [](const Node &a, const Node &b) {
-
530  return BoundsTraits::getY(a.getBounds()) < BoundsTraits::getY(b.getBounds());
-
531  });
-
532  }
-
533 
-
534  // Helper function to visit an item using a visitor that has no return value.
-
535  // In this case, we will always return true, indicating that querying should
-
536  // continue.
-
537  template<typename Visitor,
-
538  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
-
539  bool visitLeaf(Visitor&& visitor, const Node& node)
-
540  {
-
541  visitor(node.getItem());
-
542  return true;
-
543  }
-
544 
-
545  template<typename Visitor,
-
546  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
-
547  bool visitLeaves(Visitor&& visitor, const Node& node1, const Node& node2)
-
548  {
-
549  visitor(node1.getItem(), node2.getItem());
-
550  return true;
-
551  }
-
552 
-
553  // MSVC 2015 does not implement C++11 expression SFINAE and considers this a
-
554  // redefinition of a previous method
-
555 #if !defined(_MSC_VER) || _MSC_VER >= 1910
-
556  template<typename Visitor,
-
557  typename std::enable_if<std::is_void<decltype(std::declval<Visitor>()(std::declval<BoundsType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
-
558  bool visitLeaf(Visitor&& visitor, const Node& node)
-
559  {
-
560  visitor(node.getBounds(), node.getItem());
-
561  return true;
-
562  }
-
563 #endif
-
564 
-
565  // If the visitor function does return a value, we will use this to indicate
-
566  // that querying should continue.
-
567  template<typename Visitor,
-
568  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr>
-
569  bool visitLeaf(Visitor&& visitor, const Node& node)
-
570  {
-
571  return visitor(node.getItem());
-
572  }
-
573 
-
574  template<typename Visitor,
-
575  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<ItemType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr >
-
576  bool visitLeaves(Visitor&& visitor, const Node& node1, const Node& node2)
-
577  {
-
578  return visitor(node1.getItem(), node2.getItem());
-
579  }
-
580 
-
581  // MSVC 2015 does not implement C++11 expression SFINAE and considers this a
-
582  // redefinition of a previous method
-
583 #if !defined(_MSC_VER) || _MSC_VER >= 1910
-
584  template<typename Visitor,
-
585  typename std::enable_if<!std::is_void<decltype(std::declval<Visitor>()(std::declval<BoundsType>(), std::declval<ItemType>()))>::value, std::nullptr_t>::type = nullptr>
-
586  bool visitLeaf(Visitor&& visitor, const Node& node)
-
587  {
-
588  return visitor(node.getBounds(), node.getItem());
-
589  }
-
590 #endif
-
591 
-
592  template<typename Visitor>
-
593  bool query(const BoundsType& queryEnv,
-
594  const Node& node,
-
595  Visitor&& visitor) {
-
596 
-
597  assert(!node.isLeaf());
-
598 
-
599  for (auto *child = node.beginChildren(); child < node.endChildren(); ++child) {
-
600  if (child->boundsIntersect(queryEnv)) {
-
601  if (child->isLeaf()) {
-
602  if (!child->isDeleted()) {
-
603  if (!visitLeaf(visitor, *child)) {
-
604  return false; // abort query
-
605  }
-
606  }
-
607  } else {
-
608  if (!query(queryEnv, *child, visitor)) {
-
609  return false; // abort query
-
610  }
-
611  }
-
612  }
-
613  }
-
614  return true; // continue searching
-
615  }
-
616 
-
617  template<typename Visitor>
-
618  bool queryPairs(const Node& queryNode,
-
619  const Node& searchNode,
-
620  Visitor&& visitor) {
-
621 
-
622  assert(!searchNode.isLeaf());
-
623 
-
624  for (auto* child = searchNode.beginChildren(); child < searchNode.endChildren(); ++child) {
-
625  if (child->isLeaf()) {
-
626  // Only visit leaf nodes if they have a higher address than the query node,
-
627  // to avoid processing the same pairs twice.
-
628  if (child > &queryNode && !child->isDeleted() && child->boundsIntersect(queryNode.getBounds())) {
-
629  if (!visitLeaves(visitor, queryNode, *child)) {
-
630  return false; // abort query
-
631  }
-
632  }
-
633  } else {
-
634  if (child->boundsIntersect(queryNode.getBounds())) {
-
635  if (!queryPairs(queryNode, *child, visitor)) {
-
636  return false; // abort query
-
637  }
-
638  }
-
639  }
-
640  }
-
641 
-
642  return true; // continue searching
-
643  }
-
644 
-
645  bool remove(const BoundsType& queryEnv,
-
646  const Node& node,
-
647  const ItemType& item) {
-
648 
-
649  assert(!node.isLeaf());
-
650 
-
651  for (auto *child = node.beginChildren(); child < node.endChildren(); ++child) {
-
652  if (child->boundsIntersect(queryEnv)) {
-
653  if (child->isLeaf()) {
-
654  if (!child->isDeleted() && child->getItem() == item) {
-
655  // const cast is ugly, but alternative seems to be to remove all
-
656  // const qualifiers in Node and open up mutability everywhere?
-
657  auto mutableChild = const_cast<Node*>(child);
-
658  mutableChild->removeItem();
-
659  return true;
-
660  }
-
661  } else {
-
662  bool removed = remove(queryEnv, *child, item);
-
663  if (removed) {
-
664  return true;
-
665  }
-
666  }
-
667  }
-
668  }
-
669 
-
670  return false;
-
671  }
-
672 
-
673  size_t sliceCount(size_t numNodes) const {
-
674  double minLeafCount = std::ceil(static_cast<double>(numNodes) / static_cast<double>(nodeCapacity));
-
675 
-
676  return static_cast<size_t>(std::ceil(std::sqrt(minLeafCount)));
-
677  }
-
678 
-
679  static size_t sliceCapacity(size_t numNodes, size_t numSlices) {
-
680  return static_cast<size_t>(std::ceil(static_cast<double>(numNodes) / static_cast<double>(numSlices)));
-
681  }
-
682 };
-
683 
-
684 struct EnvelopeTraits {
-
685  using BoundsType = geom::Envelope;
-
686  using TwoDimensional = std::true_type;
-
687 
-
688  static bool intersects(const BoundsType& a, const BoundsType& b) {
-
689  return a.intersects(b);
-
690  }
-
691 
-
692  static double size(const BoundsType& a) {
-
693  return a.getArea();
-
694  }
-
695 
-
696  static double distance(const BoundsType& a, const BoundsType& b) {
-
697  return a.distance(b);
-
698  }
-
699 
-
700  static double maxDistance(const BoundsType& a, const BoundsType& b) {
-
701  return a.maxDistance(b);
-
702  }
-
703 
-
704  static BoundsType empty() {
-
705  return {};
-
706  }
-
707 
-
708  template<typename ItemType>
-
709  static const BoundsType& fromItem(const ItemType& i) {
-
710  return *(i->getEnvelopeInternal());
-
711  }
-
712 
-
713  template<typename ItemType>
-
714  static const BoundsType& fromItem(ItemType&& i) {
-
715  return *(i->getEnvelopeInternal());
-
716  }
-
717 
-
718  static double getX(const BoundsType& a) {
-
719  return a.getMinX() + a.getMaxX();
-
720  }
-
721 
-
722  static double getY(const BoundsType& a) {
-
723  return a.getMinY() + a.getMaxY();
-
724  }
-
725 
-
726  static void expandToInclude(BoundsType& a, const BoundsType& b) {
-
727  a.expandToInclude(b);
-
728  }
-
729 
-
730  static bool isNull(const BoundsType& a) {
-
731  return a.isNull();
-
732  }
-
733 };
-
734 
-
735 struct IntervalTraits {
-
736  using BoundsType = Interval;
-
737  using TwoDimensional = std::false_type;
-
738 
-
739  static bool intersects(const BoundsType& a, const BoundsType& b) {
-
740  return a.intersects(&b);
-
741  }
-
742 
-
743  static double size(const BoundsType& a) {
-
744  return a.getWidth();
-
745  }
-
746 
-
747  static double getX(const BoundsType& a) {
-
748  return a.getMin() + a.getMax();
-
749  }
-
750 
-
751  static double getY(const BoundsType& a) {
-
752  return a.getMin() + a.getMax();
-
753  }
-
754 
-
755  static void expandToInclude(BoundsType& a, const BoundsType& b) {
-
756  a.expandToInclude(&b);
-
757  }
-
758 
-
759  static bool isNull(const BoundsType& a) {
-
760  (void) a;
-
761  return false;
-
762  }
-
763 };
+
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 
-
766 template<typename ItemType, typename BoundsTraits = EnvelopeTraits>
-
767 class TemplateSTRtree : public TemplateSTRtreeImpl<ItemType, BoundsTraits> {
-
768 public:
-
769  using TemplateSTRtreeImpl<ItemType, BoundsTraits>::TemplateSTRtreeImpl;
-
770 };
-
771 
-
772 // When ItemType is a pointer and our bounds are geom::Envelope, adopt
-
773 // the SpatialIndex interface which requires queries via an envelope
-
774 // and items to be representable as void*.
-
775 template<typename ItemType>
-
776 class TemplateSTRtree<ItemType*, EnvelopeTraits> : public TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>, public SpatialIndex {
-
777 public:
-
778  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::TemplateSTRtreeImpl;
-
779  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::insert;
-
780  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::query;
-
781  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::remove;
-
782 
-
783  // The SpatialIndex methods only work when we are storing a pointer type.
-
784  void query(const geom::Envelope* queryEnv, std::vector<void*>& results) override {
-
785  query(*queryEnv, [&results](const ItemType* x) {
-
786  results.push_back(const_cast<void*>(static_cast<const void*>(x)));
-
787  });
-
788  }
-
789 
-
790  void query(const geom::Envelope* queryEnv, ItemVisitor& visitor) override {
-
791  query(*queryEnv, [&visitor](const ItemType* x) {
-
792  visitor.visitItem(const_cast<void*>(static_cast<const void*>(x)));
-
793  });
-
794  }
-
795 
-
796  bool remove(const geom::Envelope* itemEnv, void* item) override {
-
797  return remove(*itemEnv, static_cast<ItemType*>(item));
-
798  }
-
799 
-
800  void insert(const geom::Envelope* itemEnv, void* item) override {
-
801  insert(*itemEnv, std::move(static_cast<ItemType*>(item)));
-
802  }
-
803 };
+
765 template<typename ItemType, typename BoundsTraits = EnvelopeTraits>
+
766 class TemplateSTRtree : public TemplateSTRtreeImpl<ItemType, BoundsTraits> {
+
767 public:
+
768  using TemplateSTRtreeImpl<ItemType, BoundsTraits>::TemplateSTRtreeImpl;
+
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:
+
777  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::TemplateSTRtreeImpl;
+
778  using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::insert;
+
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 
+
805 }
806 }
807 }
-
808 }
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:379
-
std::pair< ItemType, ItemType > nearestNeighbour(TemplateSTRtreeImpl< ItemType, BoundsTraits > &other)
Definition: TemplateSTRtree.h:227
+
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:215
+
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
@@ -801,10 +800,10 @@
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:371
-
bool built() const
Definition: TemplateSTRtree.h:366
-
void iterate(F &&func)
Definition: TemplateSTRtree.h:330
-
Items items()
Definition: TemplateSTRtree.h:320
+
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