GEOS 3.14.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
32namespace geos {
33namespace index {
34namespace strtree {
35
56template<typename ItemType, typename BoundsTraits>
58public:
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
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>
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
411protected:
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
683struct 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
734struct 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
765template<typename ItemType, typename BoundsTraits = EnvelopeTraits>
766class TemplateSTRtree : public TemplateSTRtreeImpl<ItemType, BoundsTraits> {
767public:
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*.
774template<typename ItemType>
775class TemplateSTRtree<ItemType*, EnvelopeTraits> : public TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>, public SpatialIndex {
776public:
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}
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()
Definition TemplateSTRtree.h:208
std::pair< ItemType, ItemType > nearestNeighbour(TemplateSTRtreeImpl< ItemType, BoundsTraits > &other, ItemDistance &distance)
Definition TemplateSTRtree.h:214
std::pair< ItemType, ItemType > nearestNeighbour(ItemDistance &distance)
Definition TemplateSTRtree.h:202
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
bool built() const
Definition TemplateSTRtree.h:365
const Node * getRoot()
Definition TemplateSTRtree.h:370
void iterate(F &&func)
Definition TemplateSTRtree.h:329
Items items()
Definition TemplateSTRtree.h:319
Basic namespace for all GEOS functionalities.
Definition geos.h:39