34 #include <boost/container/static_vector.hpp> 43 #ifndef DOXYGEN_SHOULD_SKIP_THIS 52 template<
typename U, std::
size_t N>
82 template<
typename T,
typename U =
float, std::
size_t Size = 16>
84 static_assert(Size > 0,
"Size can not be 0");
105 Node *node = m_root.chooseNode(bounds);
107 if (node ==
nullptr) {
111 return node->insert(std::move(value), bounds);
123 return m_root.query(bounds, callback, kind);
135 std::vector<SpatialStructure<U, 2>> structures;
136 m_root.appendToStructure(structures, 0);
149 : m_children(
nullptr)
151 m_entries.reserve(Size);
156 , m_children(
nullptr)
158 m_entries.reserve(Size);
161 bool isLeaf()
const {
162 return m_children ==
nullptr;
166 if (!m_bounds.contains(bounds)) {
171 if (m_entries.size() < Size) {
178 if (m_entries.size() < Size) {
183 for (std::size_t i = 0; i < 4; ++i) {
184 if (m_children[i].chooseNode(bounds) !=
nullptr) {
185 return &m_children[i];
189 clearChildrenIfEmpty();
194 bool insert(
T&& value,
const Box<U, 2>& bounds) {
195 m_entries.push_back({ std::move(value), bounds });
200 if (!m_bounds.intersects(bounds)) {
204 std::size_t found = 0;
206 for (
auto& entry : m_entries) {
209 if (bounds.
contains(entry.bounds)) {
210 callback(entry.value);
217 callback(entry.value);
225 for (std::size_t i = 0; i < 4; ++i) {
226 found += m_children[i].query(bounds, callback, kind);
237 m_children =
nullptr;
243 for (
auto& entry : m_entries) {
248 for (std::size_t i = 0; i < 4; ++i) {
249 m_children[i].appendToStructure(structures, level + 1);
256 m_children = std::make_unique<Node[]>(4);
263 std::vector<Entry> entries;
265 for (
auto& entry : m_entries) {
266 bool inserted =
false;
268 for (std::size_t i = 0; i < 4; ++i) {
269 if (m_children[i].m_bounds.contains(entry.bounds)) {
270 m_children[i].m_entries.push_back(std::move(entry));
277 entries.push_back(std::move(entry));
281 std::swap(m_entries, entries);
284 void clearChildrenIfEmpty() {
287 for (std::size_t i = 0; i < 4; ++i) {
288 if (!m_children[i].m_entries.empty()) {
293 m_children =
nullptr;
298 std::vector<Entry> m_entries;
299 std::unique_ptr<Node[]> m_children;
315 template<
typename T,
typename U =
float, std::
size_t N = 2, std::
size_t MaxSize = 16, std::
size_t MinSize = 4>
317 static_assert(
N > 0,
"N can not be 0");
318 static_assert(2 <= MinSize,
"MinSize must be at least 2");
319 static_assert(MinSize <= MaxSize / 2,
"MinSize must be less than MaxSize/2");
345 m_root = std::exchange(other.m_root,
nullptr);
352 std::swap(m_root, other.m_root);
371 Leaf *leaf = m_root->chooseSubtree(bounds);
373 Node *splitted = leaf->tryInsert(std::move(value), bounds);
374 Node *current = leaf;
376 while (splitted !=
nullptr) {
377 auto splittedBounds = splitted->computeBounds();
378 splitted->updateOriginalBounds(splittedBounds);
380 auto currentBounds = current->computeBounds();
381 current->updateOriginalBounds(currentBounds);
383 if (current == m_root) {
384 auto branch =
new Branch;
386 current->setParent(branch);
387 branch->tryInsert(current, currentBounds);
389 splitted->setParent(branch);
390 branch->tryInsert(splitted, splittedBounds);
392 branch->updateOriginalBounds(branch->computeBounds());
398 Branch *parent = current->getParent();
399 assert(parent !=
nullptr);
401 parent->updateBoundsForChild(currentBounds, current);
403 splitted->setParent(parent);
404 splitted = parent->tryInsert(splitted, splittedBounds);
410 while (current != m_root) {
411 auto currentBounds = current->computeBounds();
413 Branch *parent = current->getParent();
414 assert(parent !=
nullptr);
416 parent->updateBoundsForChild(currentBounds, current);
433 return m_root->query(bounds, callback, kind);
445 std::vector<SpatialStructure<U, N>> structures;
446 m_root->appendToStructure(structures, 0);
451 static constexpr std::size_t Size = MaxSize + 1;
472 Branch *getParent() noexcept {
476 void setParent(Branch *parent) {
480 bool hasOriginalBounds()
const {
481 return !m_orig.isEmpty();
484 U getOriginalCenterAxisValue(std::size_t axis)
const {
485 return (m_orig.min[axis] + m_orig.max[axis]) / 2;
488 void updateOriginalBounds(
Box<U, N> orig) {
492 virtual ~
Node() =
default;
494 virtual Leaf *chooseSubtree(
const Box<U, N>& bounds) = 0;
496 virtual Box<U, N> computeBounds()
const = 0;
521 struct LeafEntry : Entry {
525 class Leaf :
public Node {
527 using typename Node::SplitOrder;
531 std::size_t found = 0;
535 for (
auto& entry : m_entries) {
536 if (bounds.
contains(entry.bounds)) {
537 callback(entry.value);
544 for (
auto& entry : m_entries) {
546 callback(entry.value);
557 virtual Leaf *chooseSubtree(
const Box<U, N>& bounds)
override {
562 virtual Box<U,N> computeBounds()
const override {
563 assert(!m_entries.empty());
566 for (
auto& entry : m_entries) {
567 res.extend(entry.bounds);
573 virtual void appendToStructure(std::vector<
SpatialStructure<U, N>>& structures,
int level)
const override {
574 for (
auto& entry : m_entries) {
579 Leaf *tryInsert(
T&& value,
const Box<U, N>& bounds) {
581 entry.bounds = bounds;
582 entry.value = std::move(value);
583 m_entries.push_back(std::move(entry));
585 if (m_entries.size() < Size) {
589 std::vector<Box<U, N>> boxes;
591 std::transform(m_entries.begin(), m_entries.end(), std::back_inserter(boxes), [](
const Entry& entry) {
597 switch (split.order) {
598 case SplitOrder::Min:
599 std::sort(m_entries.begin(), m_entries.end(), EntryMinAxisComparator<LeafEntry>(split.axis));
601 case SplitOrder::Max:
602 std::sort(m_entries.begin(), m_entries.end(), EntryMaxAxisComparator<LeafEntry>(split.axis));
606 auto leaf =
new Leaf;
608 auto splitIteratorBegin = std::next(m_entries.begin(), split.index + 1);
609 auto splitIteratorEnd = m_entries.end();
611 std::move(splitIteratorBegin, splitIteratorEnd, std::back_inserter(leaf->m_entries));
612 m_entries.erase(splitIteratorBegin, splitIteratorEnd);
620 std::tie(split.
axis, split.
order) = computeSplitAxis(boxes);
622 switch (split.
order) {
623 case SplitOrder::Min:
624 std::sort(boxes.begin(), boxes.end(), MinAxisComparator(split.
axis));
626 case SplitOrder::Max:
627 std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(split.
axis));
631 split.
index = computeSplitIndex(boxes, split.
axis);
635 std::tuple<std::size_t, SplitOrder> computeSplitAxis(std::vector<
Box<U, N>>& boxes) {
636 std::size_t currentAxis = 0;
637 U currentValue = std::numeric_limits<U>::max();
638 SplitOrder currentOrder = SplitOrder::Min;
640 for (std::size_t axis = 0; axis <
N; ++axis) {
641 std::sort(boxes.begin(), boxes.end(), MinAxisComparator(axis));
643 U value = computeAxisValue(boxes);
645 if (value < currentValue) {
647 currentValue = value;
648 currentOrder = SplitOrder::Min;
651 std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(axis));
653 value = computeAxisValue(boxes);
655 if (value < currentValue) {
657 currentValue = value;
658 currentOrder = SplitOrder::Max;
662 return std::make_tuple(currentAxis, currentOrder);
665 U computeAxisValue(
const std::vector<
Box<U, N>>& boxes) {
666 std::vector<Box<U, N>> firstBounds;
668 std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
672 std::vector<Box<U, N>> secondBounds;
674 std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
680 for (std::size_t j = MinSize; j <= MaxSize - MinSize + 1; ++j) {
681 value += firstBounds[j].getExtentDistance() + secondBounds[Size - j].getExtentDistance();
687 std::size_t computeSplitIndex(
const std::vector<
Box<U, N>>& boxes, std::size_t axis) {
688 std::vector<Box<U, N>> firstBounds;
690 std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
694 std::vector<Box<U, N>> secondBounds;
696 std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
703 const auto& bounds = firstBounds.back();
706 if (Node::hasOriginalBounds()) {
707 asym = 2.0f * ((bounds.max[axis] + bounds.min[axis]) / 2 - Node::getOriginalCenterAxisValue(axis)) / (bounds.max[axis] - bounds.min[axis]);
710 assert(-1.0f <= asym && asym <= 1.0f);
712 static constexpr
float S = 0.5f;
713 const float mu = (1 - 2.0f * MinSize / (MaxSize + 1)) * asym;
714 const float rho = S * (1 + std::abs(mu));
715 const float y1 = std::exp(- 1 / (S * S));
716 const float ys = 1 / (1 - y1);
718 auto wf = [mu,rho,y1,ys](std::size_t i) {
719 const float xi = 2.0f * i / (MaxSize + 1.0f) - 1.0f;
720 return ys * (std::exp(-
gf::square((xi - mu) / rho) - y1));
725 std::size_t currentIndex = 0;
726 U currentValue = std::numeric_limits<U>::max();
730 if (firstBounds[MinSize].getVolume() == 0 || secondBounds[MinSize].getVolume() == 0) {
738 bool overlapFree =
false;
740 U perimeterMax = 2 * bounds.getExtentDistance() - bounds.getMinimumEdge();
742 for (std::size_t index = MinSize; index <= MaxSize - MinSize + 1; ++index) {
743 auto weight = (firstBounds[index].*overlapFn)(secondBounds[Size - index - 1]);
749 auto value = weight * wf(index);
751 if (value < currentValue) {
752 currentValue = value;
753 currentIndex = index;
758 if (overlapFree && weight == 0) {
759 weight = firstBounds[index].getExtentDistance() + secondBounds[Size - index - 1].getExtentDistance() - perimeterMax;
762 auto value = weight / wf(index);
764 if (value < currentValue) {
765 currentValue = value;
766 currentIndex = index;
775 boost::container::static_vector<LeafEntry, Size> m_entries;
782 struct BranchEntry : Entry {
786 class Branch :
public Node {
788 using typename Node::SplitOrder;
792 for (
auto& entry : m_entries) {
798 std::size_t found = 0;
800 for (
auto& entry : m_entries) {
802 found += entry.child->query(bounds, callback, kind);
809 virtual Leaf *chooseSubtree(
const Box<U, N>& bounds)
override {
810 return chooseNode(bounds)->chooseSubtree(bounds);
814 Node *bestNodeForVolume =
nullptr;
815 U bestVolume = std::numeric_limits<U>::max();
817 Node *bestNodeForExtentDistance =
nullptr;
818 U bestExtentDistance = std::numeric_limits<U>::max();
820 for (
auto& entry : m_entries) {
821 if (entry.bounds.getIntersection(bounds) == bounds) {
822 U volume = entry.bounds.getVolume();
824 if (bestNodeForVolume ==
nullptr || volume < bestVolume) {
826 bestNodeForVolume = entry.child;
829 U extentDistance = entry.bounds.getExtentDistance();
831 if (bestNodeForExtentDistance ==
nullptr || extentDistance < bestExtentDistance) {
832 bestExtentDistance = extentDistance;
833 bestNodeForExtentDistance = entry.child;
838 if (bestNodeForVolume !=
nullptr) {
839 if (bestVolume > 0) {
840 return bestNodeForVolume;
843 assert(bestNodeForExtentDistance);
844 return bestNodeForExtentDistance;
851 Node *covering = searchForCoveringNode(bounds);
853 if (covering !=
nullptr) {
857 std::sort(m_entries.begin(), m_entries.end(), ExtentDistanceEnlargement(bounds));
859 OverlapExtentDistanceEnlargement extentDistanceEnlargement(bounds, m_entries.front());
863 for (p = m_entries.size() - 1; p > 0; --p) {
864 if (extentDistanceEnlargement(m_entries[p]) != 0) {
870 return m_entries[0].child;
873 std::vector<Candidate> candidates(p + 1, { 0,
false,
U() });
874 Node *node =
nullptr;
876 if (existsEmptyVolumeExtension(bounds)) {
877 node = findCandidates<OverlapExtentDistanceEnlargement>(0, p, bounds, candidates);
879 node = findCandidates<OverlapVolumeEnlargement>(0, p, bounds, candidates);
882 if (node !=
nullptr) {
886 candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [](
const Candidate& candidate) {
887 return !candidate.isCandidate;
888 }), candidates.end());
890 assert(!candidates.empty());
892 auto it = std::min_element(candidates.begin(), candidates.end(), [](
const Candidate& lhs,
const Candidate& rhs) {
893 return lhs.overlap < rhs.overlap;
896 return m_entries[it->index].child;
899 virtual Box<U,N> computeBounds()
const override {
900 assert(!m_entries.empty());
903 for (
auto& entry : m_entries) {
904 res.extend(entry.bounds);
910 virtual void appendToStructure(std::vector<
SpatialStructure<U, N>>& structures,
int level)
const override {
911 for (
auto& entry : m_entries) {
913 entry.child->appendToStructure(structures, level + 1);
917 void updateBoundsForChild(
const Box<U, N>& bounds,
Node *child) {
918 for (
auto& entry : m_entries) {
919 if (entry.child == child) {
920 entry.bounds = bounds;
930 entry.bounds = bounds;
932 m_entries.push_back(std::move(entry));
934 if (m_entries.size() < Size) {
938 std::vector<Box<U, N>> boxes;
940 std::transform(m_entries.begin(), m_entries.end(), std::back_inserter(boxes), [](
const Entry& entry) {
946 switch (split.order) {
947 case SplitOrder::Min:
948 std::sort(m_entries.begin(), m_entries.end(), EntryMinAxisComparator<BranchEntry>(split.axis));
950 case SplitOrder::Max:
951 std::sort(m_entries.begin(), m_entries.end(), EntryMaxAxisComparator<BranchEntry>(split.axis));
955 auto branch =
new Branch;
957 auto splitIteratorBegin = std::next(m_entries.begin(), split.index + 1);
958 auto splitIteratorEnd = m_entries.end();
960 std::move(splitIteratorBegin, splitIteratorEnd, std::back_inserter(branch->m_entries));
961 m_entries.erase(splitIteratorBegin, splitIteratorEnd);
963 for (
auto& entry : branch->m_entries) {
964 entry.child->setParent(branch);
977 bool existsEmptyVolumeExtension(
const Box<U, N>& bounds) {
978 for (
auto& entry : m_entries) {
979 if (entry.bounds.getExtended(bounds).getVolume() == 0) {
987 template<
typename OverlapEnlargement>
988 Node *findCandidates(std::size_t t, std::size_t p,
const Box<U, N>& bounds, std::vector<Candidate>& candidates) {
989 candidates[t].index = t;
990 candidates[t].isCandidate =
true;
992 OverlapEnlargement enlargement(bounds, m_entries[t]);
996 for (std::size_t i = 0; i <= p; ++i) {
1001 U localOverlap = enlargement(m_entries[i]);
1002 overlap += localOverlap;
1004 if (localOverlap == 0 && !candidates[i].isCandidate) {
1005 Node *node = findCandidates<OverlapEnlargement>(i, p, bounds, candidates);
1007 if (node !=
nullptr) {
1014 return m_entries[t].child;
1017 candidates[t].overlap = overlap;
1021 struct SplitStatus {
1022 bool overlapFree =
false;
1023 U currentValue = std::numeric_limits<U>::max();
1030 for (std::size_t axis = 0; axis <
N; ++axis) {
1031 std::sort(boxes.begin(), boxes.end(), MinAxisComparator(axis));
1032 computeBestSplitValue(boxes, result, status, axis, SplitOrder::Min);
1034 std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(axis));
1035 computeBestSplitValue(boxes, result, status, axis, SplitOrder::Max);
1041 void computeBestSplitValue(std::vector<
Box<U, N>>& boxes,
SplitResult& result, SplitStatus& status, std::size_t axis, SplitOrder order) {
1042 std::vector<Box<U, N>> firstBounds;
1044 std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
1048 std::vector<Box<U, N>> secondBounds;
1050 std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
1056 const auto& bounds = firstBounds.back();
1059 if (Node::hasOriginalBounds()) {
1060 asym = 2.0f * ((bounds.max[axis] + bounds.min[axis]) / 2 - Node::getOriginalCenterAxisValue(axis)) / (bounds.max[axis] - bounds.min[axis]);
1063 assert(-1.0f <= asym && asym <= 1.0f);
1065 static constexpr
float S = 0.5f;
1066 const float mu = (1 - 2.0f * MinSize / (MaxSize + 1)) * asym;
1067 const float rho = S * (1 + std::abs(mu));
1068 const float y1 = std::exp(- 1 / (S * S));
1069 const float ys = 1 / (1 - y1);
1071 auto wf = [mu,rho,y1,ys](std::size_t i) {
1072 const float xi = 2.0f * i / (MaxSize + 1.0f) - 1.0f;
1073 return ys * (std::exp(-
gf::square((xi - mu) / rho) - y1));
1080 if (firstBounds[MinSize].getVolume() == 0 || secondBounds[MinSize].getVolume() == 0) {
1088 U perimeterMax = 2 * bounds.getExtentDistance() - bounds.getMinimumEdge();
1090 for (std::size_t index = MinSize; index <= MaxSize - MinSize + 1; ++index) {
1091 auto weight = (firstBounds[index].*overlapFn)(secondBounds[Size - index - 1]);
1093 if (!status.overlapFree) {
1095 status.overlapFree =
true;
1097 auto value = weight * wf(index);
1099 if (value < status.currentValue) {
1100 status.currentValue = value;
1101 result.
index = index;
1103 result.
order = order;
1108 if (status.overlapFree && weight == 0) {
1109 weight = firstBounds[index].getExtentDistance() + secondBounds[Size - index - 1].getExtentDistance() - perimeterMax;
1110 assert(weight <= 0);
1112 auto value = weight / wf(index);
1114 if (value < status.currentValue) {
1115 status.currentValue = value;
1116 result.
index = index;
1118 result.
order = order;
1125 boost::container::static_vector<BranchEntry, Size> m_entries;
1132 class ExtentDistanceEnlargement {
1134 ExtentDistanceEnlargement(
const Box<U, N>& bounds)
1140 bool operator()(
const Entry& lhs,
const Entry& rhs)
const {
1141 return getExtentDistanceEnlargement(lhs) < getExtentDistanceEnlargement(rhs);
1144 U getExtentDistanceEnlargement(
const Entry& entry)
const {
1145 return entry.bounds.getExtended(m_bounds).getExtentDistance() - entry.bounds.getExtentDistance();
1152 class OverlapExtentDistanceEnlargement {
1154 OverlapExtentDistanceEnlargement(
const Box<U, N>& bounds,
const Entry& reference)
1156 , m_reference(reference)
1157 , m_extended(reference.bounds.getExtended(bounds))
1162 U operator()(
const Entry& entry)
const {
1163 return getOverlapExtentDistanceEnlargement(entry);
1166 U getOverlapExtentDistanceEnlargement(
const Entry& entry)
const {
1167 return m_extended.getIntersectionExtentDistance(entry.bounds) - m_reference.bounds.getIntersectionExtentDistance(entry.bounds);
1172 const Entry& m_reference;
1177 class OverlapVolumeEnlargement {
1179 OverlapVolumeEnlargement(
const Box<U, N>& bounds,
const Entry& reference)
1181 , m_reference(reference)
1182 , m_extended(reference.bounds.getExtended(bounds))
1187 U operator()(
const Entry& entry)
const {
1188 return getOverlapVolumeEnlargement(entry);
1191 U getOverlapVolumeEnlargement(
const Entry& entry)
const {
1192 return m_extended.getIntersectionVolume(entry.bounds) - m_reference.bounds.getIntersectionVolume(entry.bounds);
1197 const Entry& m_reference;
1201 class MinAxisComparator {
1203 MinAxisComparator(std::size_t axis)
1210 return std::make_tuple(lhs.
min[m_axis], lhs.
max[m_axis]) < std::make_tuple(rhs.
min[m_axis], rhs.
max[m_axis]);
1217 template<
typename Entry>
1218 class EntryMinAxisComparator {
1220 EntryMinAxisComparator(std::size_t axis)
1226 bool operator()(
const Entry& lhs,
const Entry& rhs) {
1227 return std::make_tuple(lhs.bounds.min[m_axis], lhs.bounds.max[m_axis]) < std::make_tuple(rhs.bounds.min[m_axis], rhs.bounds.max[m_axis]);
1234 class MaxAxisComparator {
1236 MaxAxisComparator(std::size_t axis)
1243 return std::make_tuple(lhs.
max[m_axis], lhs.
min[m_axis]) < std::make_tuple(rhs.
max[m_axis], rhs.
min[m_axis]);
1250 template<
typename Entry>
1251 class EntryMaxAxisComparator {
1253 EntryMaxAxisComparator(std::size_t axis)
1259 bool operator()(
const Entry& lhs,
const Entry& rhs) {
1260 return std::make_tuple(lhs.bounds.max[m_axis], lhs.bounds.min[m_axis]) < std::make_tuple(rhs.bounds.max[m_axis], rhs.bounds.min[m_axis]);
1268 void updateBounds(
Node *node) {
1269 while (node !=
nullptr) {
1270 Box<U, N> bounds = node->computeBounds();
1272 Branch *parent = node->getParent();
1274 if (parent !=
nullptr) {
1275 parent->updateBoundsForChild(bounds, node);
1287 #ifndef DOXYGEN_SHOULD_SKIP_THIS 1292 #endif // GF_SPATIAL_H constexpr Box< T, N > getExtended(const Box< T, N > &other) const noexcept
Definition: Box.h:196
bool insert(T value, const Box< U, N > &bounds)
Insert an object in the tree.
Definition: Spatial.h:370
constexpr bool intersects(const Box< T, N > &other) const noexcept
Definition: Box.h:118
void unused(Args &&...)
A simple way to avoid warnings about unused variables.
Definition: Unused.h:35
void clear()
Remove all the objects from the tree.
Definition: Spatial.h:129
std::size_t query(const Box< U, N > &bounds, SpatialQueryCallback< T > callback, SpatialQuery kind=SpatialQuery::Intersect) const
Query objects in the tree.
Definition: Spatial.h:432
std::function< void(const T &)> SpatialQueryCallback
A callback for spatial query.
Definition: Spatial.h:73
std::vector< SpatialStructure< U, N > > getStructure() const
Definition: Spatial.h:444
constexpr Vector2f transform(const Matrix3f &mat, Vector2f point)
Apply an affine transformation to a 2D point.
Definition: Transform.h:331
SpatialStructureType type
Definition: Spatial.h:55
Box< U, N > bounds
Definition: Spatial.h:54
Vector< T, N > min
Definition: Box.h:49
Search for all objects that contain the given bounds.
~RStarTree()
Destructor.
Definition: Spatial.h:359
std::vector< SpatialStructure< U, 2 > > getStructure() const
Definition: Spatial.h:134
constexpr T square(T val)
Square function.
Definition: Math.h:275
std::size_t index
Definition: Spatial.h:507
SpatialStructureType
Definition: Spatial.h:47
std::size_t query(const Box< U, 2 > &bounds, SpatialQueryCallback< T > callback, SpatialQuery kind=SpatialQuery::Intersect) const
Query objects in the tree.
Definition: Spatial.h:122
Search for all objects that intersect the given bounds.
RStarTree & operator=(RStarTree &&other) noexcept
Move assignement.
Definition: Spatial.h:351
void clear()
Remove all the objects from the tree.
Definition: Spatial.h:439
The namespace for gf classes.
Definition: Action.h:34
QuadTree(const Box< U, 2 > &bounds)
Constructor.
Definition: Spatial.h:91
RStarTree()
Constructor.
Definition: Spatial.h:324
An implementation of quadtree.
Definition: Spatial.h:83
Vector< T, N > max
Definition: Box.h:50
Definition: Spatial.h:506
Box< T, 2 > computeBoxQuadrant(const Box< T, 2 > &box, Quadrant quadrant)
Definition: Box.h:263
int level
Definition: Spatial.h:56
RStarTree(RStarTree &&other) noexcept
Move constructor.
Definition: Spatial.h:343
An implemntation of a R* tree.
Definition: Spatial.h:316
SpatialQuery
A kind of spatial query.
Definition: Spatial.h:63
bool insert(T value, const Box< U, 2 > &bounds)
Insert an object in the tree.
Definition: Spatial.h:104
SplitOrder order
Definition: Spatial.h:509
constexpr bool contains(Vector< T, N > point) const noexcept
Definition: Box.h:98
std::size_t axis
Definition: Spatial.h:508