GEOS 3.10.1
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 ItemDistance id;
210 return nearestNeighbour(*this);
211 }
212
214 template<typename ItemDistance>
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
375protected:
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
597struct 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
644struct 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
675template<typename ItemType, typename BoundsTraits = EnvelopeTraits>
676class TemplateSTRtree : public TemplateSTRtreeImpl<ItemType, BoundsTraits> {
677public:
678 using TemplateSTRtreeImpl<ItemType, BoundsTraits>::TemplateSTRtreeImpl;
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*.
684template<typename ItemType>
685class TemplateSTRtree<ItemType*, EnvelopeTraits> : public TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>, public SpatialIndex {
686public:
687 using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::TemplateSTRtreeImpl;
688 using TemplateSTRtreeImpl<ItemType*, EnvelopeTraits>::insert;
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()
Definition: TemplateSTRtree.h:208
std::pair< ItemType, ItemType > nearestNeighbour(TemplateSTRtreeImpl< ItemType, BoundsTraits > &other, ItemDistance &distance)
Definition: TemplateSTRtree.h:215
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:329
const Node * getRoot()
Definition: TemplateSTRtree.h:334
void iterate(F &&func)
Definition: TemplateSTRtree.h:297
Items items()
Definition: TemplateSTRtree.h:287
Basic namespace for all GEOS functionalities.
Definition: geos.h:40