34 #include <boost/container/static_vector.hpp> 43 #ifndef DOXYGEN_SHOULD_SKIP_THIS 66 template<
typename U, std::
size_t N>
96 template<
typename T,
typename U =
float, std::
size_t Size = 16>
98 static_assert(Size > 0,
"Size can not be 0");
119 Node *node = m_root.chooseNode(bounds);
121 if (node ==
nullptr) {
125 return node->insert(std::move(value), bounds);
137 return m_root.query(bounds, callback, kind);
149 std::vector<SpatialStructure<U, 2>> structures;
150 m_root.appendToStructure(structures, 0);
163 : m_children(
nullptr)
165 m_entries.reserve(Size);
170 , m_children(
nullptr)
172 m_entries.reserve(Size);
175 bool isLeaf()
const {
176 return m_children ==
nullptr;
180 if (!m_bounds.contains(bounds)) {
185 if (m_entries.size() < Size) {
192 if (m_entries.size() < Size) {
197 for (std::size_t i = 0; i < 4; ++i) {
198 if (m_children[i].chooseNode(bounds) !=
nullptr) {
199 return &m_children[i];
203 clearChildrenIfEmpty();
208 bool insert(
T&& value,
const Box<U, 2>& bounds) {
209 m_entries.push_back({ std::move(value), bounds });
214 if (!m_bounds.intersects(bounds)) {
218 std::size_t found = 0;
220 for (
auto& entry : m_entries) {
223 if (bounds.
contains(entry.bounds)) {
224 callback(entry.value);
231 callback(entry.value);
239 for (std::size_t i = 0; i < 4; ++i) {
240 found += m_children[i].query(bounds, callback, kind);
251 m_children =
nullptr;
257 for (
auto& entry : m_entries) {
262 for (std::size_t i = 0; i < 4; ++i) {
263 m_children[i].appendToStructure(structures, level + 1);
270 m_children = std::make_unique<Node[]>(4);
277 std::vector<Entry> entries;
279 for (
auto& entry : m_entries) {
280 bool inserted =
false;
282 for (std::size_t i = 0; i < 4; ++i) {
283 if (m_children[i].m_bounds.contains(entry.bounds)) {
284 m_children[i].m_entries.push_back(std::move(entry));
291 entries.push_back(std::move(entry));
295 std::swap(m_entries, entries);
298 void clearChildrenIfEmpty() {
301 for (std::size_t i = 0; i < 4; ++i) {
302 if (!m_children[i].m_entries.empty()) {
307 m_children =
nullptr;
312 std::vector<Entry> m_entries;
313 std::unique_ptr<Node[]> m_children;
329 template<
typename T,
typename U =
float, std::
size_t N = 2, std::
size_t MaxSize = 16, std::
size_t MinSize = 4>
331 static_assert(
N > 0,
"N can not be 0");
332 static_assert(2 <= MinSize,
"MinSize must be at least 2");
333 static_assert(MinSize <= MaxSize / 2,
"MinSize must be less than MaxSize/2");
359 m_root = std::exchange(other.m_root,
nullptr);
366 std::swap(m_root, other.m_root);
385 Leaf *leaf = m_root->chooseSubtree(bounds);
387 Node *splitted = leaf->tryInsert(std::move(value), bounds);
388 Node *current = leaf;
390 while (splitted !=
nullptr) {
391 auto splittedBounds = splitted->computeBounds();
392 splitted->updateOriginalBounds(splittedBounds);
394 auto currentBounds = current->computeBounds();
395 current->updateOriginalBounds(currentBounds);
397 if (current == m_root) {
398 auto branch =
new Branch;
400 current->setParent(branch);
401 branch->tryInsert(current, currentBounds);
403 splitted->setParent(branch);
404 branch->tryInsert(splitted, splittedBounds);
406 branch->updateOriginalBounds(branch->computeBounds());
412 Branch *parent = current->getParent();
413 assert(parent !=
nullptr);
415 parent->updateBoundsForChild(currentBounds, current);
417 splitted->setParent(parent);
418 splitted = parent->tryInsert(splitted, splittedBounds);
424 while (current != m_root) {
425 auto currentBounds = current->computeBounds();
427 Branch *parent = current->getParent();
428 assert(parent !=
nullptr);
430 parent->updateBoundsForChild(currentBounds, current);
447 return m_root->query(bounds, callback, kind);
459 std::vector<SpatialStructure<U, N>> structures;
460 m_root->appendToStructure(structures, 0);
465 static constexpr std::size_t Size = MaxSize + 1;
497 Branch *getParent() noexcept {
501 void setParent(Branch *parent) {
505 bool hasOriginalBounds()
const {
506 return !m_orig.isEmpty();
509 U getOriginalCenterAxisValue(std::size_t axis)
const {
510 return (m_orig.min[axis] + m_orig.max[axis]) / 2;
513 void updateOriginalBounds(
Box<U, N> orig) {
517 virtual ~
Node() =
default;
519 virtual Leaf *chooseSubtree(
const Box<U, N>& bounds) = 0;
521 virtual Box<U, N> computeBounds()
const = 0;
534 struct LeafEntry : Entry {
538 class Leaf :
public Node {
541 std::size_t found = 0;
545 for (
auto& entry : m_entries) {
546 if (bounds.
contains(entry.bounds)) {
547 callback(entry.value);
554 for (
auto& entry : m_entries) {
556 callback(entry.value);
567 virtual Leaf *chooseSubtree(
const Box<U, N>& bounds)
override {
572 virtual Box<U,N> computeBounds()
const override {
573 assert(!m_entries.empty());
576 for (
auto& entry : m_entries) {
577 res.extend(entry.bounds);
583 virtual void appendToStructure(std::vector<
SpatialStructure<U, N>>& structures,
int level)
const override {
584 for (
auto& entry : m_entries) {
589 Leaf *tryInsert(
T&& value,
const Box<U, N>& bounds) {
592 entry.bounds = bounds;
593 entry.value = std::move(value);
594 m_entries.push_back(std::move(entry));
597 if (m_entries.size() < Size) {
601 std::vector<Box<U, N>> boxes;
603 std::transform(m_entries.begin(), m_entries.end(), std::back_inserter(boxes), [](
const Entry& entry) {
607 SplitResult split = computeSplit(boxes);
609 switch (split.order) {
610 case SplitOrder::Min:
611 std::sort(m_entries.begin(), m_entries.end(), EntryMinAxisComparator<LeafEntry>(split.axis));
613 case SplitOrder::Max:
614 std::sort(m_entries.begin(), m_entries.end(), EntryMaxAxisComparator<LeafEntry>(split.axis));
618 auto leaf =
new Leaf;
620 auto splitIteratorBegin = std::next(m_entries.begin(), split.index + 1);
621 auto splitIteratorEnd = m_entries.end();
623 std::move(splitIteratorBegin, splitIteratorEnd, std::back_inserter(leaf->m_entries));
624 m_entries.erase(splitIteratorBegin, splitIteratorEnd);
630 SplitResult computeSplit(std::vector<
Box<U, N>>& boxes) {
632 std::tie(split.axis, split.order) = computeSplitAxis(boxes);
634 switch (split.order) {
635 case SplitOrder::Min:
636 std::sort(boxes.begin(), boxes.end(), MinAxisComparator(split.axis));
638 case SplitOrder::Max:
639 std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(split.axis));
643 split.index = computeSplitIndex(boxes, split.axis);
647 std::tuple<std::size_t, SplitOrder> computeSplitAxis(std::vector<
Box<U, N>>& boxes) {
648 std::size_t currentAxis = 0;
649 U currentValue = std::numeric_limits<U>::max();
650 SplitOrder currentOrder = SplitOrder::Min;
652 for (std::size_t axis = 0; axis <
N; ++axis) {
653 std::sort(boxes.begin(), boxes.end(), MinAxisComparator(axis));
655 U value = computeAxisValue(boxes);
657 if (value < currentValue) {
659 currentValue = value;
660 currentOrder = SplitOrder::Min;
663 std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(axis));
665 value = computeAxisValue(boxes);
667 if (value < currentValue) {
669 currentValue = value;
670 currentOrder = SplitOrder::Max;
674 return std::make_tuple(currentAxis, currentOrder);
677 U computeAxisValue(
const std::vector<
Box<U, N>>& boxes) {
678 std::vector<Box<U, N>> firstBounds;
680 std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
684 std::vector<Box<U, N>> secondBounds;
686 std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
692 for (std::size_t j = MinSize; j <= MaxSize - MinSize + 1; ++j) {
693 value += firstBounds[j].getExtentLength() + secondBounds[Size - j].getExtentLength();
699 std::size_t computeSplitIndex(
const std::vector<
Box<U, N>>& boxes, std::size_t axis) {
700 std::vector<Box<U, N>> firstBounds;
702 std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
706 std::vector<Box<U, N>> secondBounds;
708 std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
715 const auto& bounds = firstBounds.back();
718 if (Node::hasOriginalBounds()) {
719 asym = 2.0f * ((bounds.max[axis] + bounds.min[axis]) / 2 - Node::getOriginalCenterAxisValue(axis)) / (bounds.max[axis] - bounds.min[axis]);
722 assert(-1.0f <= asym && asym <= 1.0f);
724 static constexpr
float S = 0.5f;
725 const float mu = (1 - 2.0f * MinSize / (MaxSize + 1)) * asym;
726 const float rho = S * (1 + std::abs(mu));
727 const float y1 = std::exp(- 1 / (S * S));
728 const float ys = 1 / (1 - y1);
730 auto wf = [mu,rho,y1,ys](std::size_t i) {
731 const float xi = 2.0f * i / (MaxSize + 1.0f) - 1.0f;
732 return ys * (std::exp(-
gf::square((xi - mu) / rho) - y1));
737 std::size_t currentIndex = 0;
738 U currentValue = std::numeric_limits<U>::max();
742 if (firstBounds[MinSize].getVolume() == 0 || secondBounds[MinSize].getVolume() == 0) {
750 bool overlapFree =
false;
752 U perimeterMax = 2 * bounds.getExtentLength() - bounds.getMinimumEdge();
754 for (std::size_t index = MinSize; index <= MaxSize - MinSize + 1; ++index) {
755 auto weight = (firstBounds[index].*overlapFn)(secondBounds[Size - index - 1]);
761 auto value = weight * wf(index);
763 if (value < currentValue) {
764 currentValue = value;
765 currentIndex = index;
770 if (overlapFree && weight == 0) {
771 weight = firstBounds[index].getExtentLength() + secondBounds[Size - index - 1].getExtentLength() - perimeterMax;
774 auto value = weight / wf(index);
776 if (value < currentValue) {
777 currentValue = value;
778 currentIndex = index;
787 boost::container::static_vector<LeafEntry, Size> m_entries;
794 struct BranchEntry : Entry {
798 class Branch :
public Node {
801 for (
auto& entry : m_entries) {
807 std::size_t found = 0;
809 for (
auto& entry : m_entries) {
811 found += entry.child->query(bounds, callback, kind);
818 virtual Leaf *chooseSubtree(
const Box<U, N>& bounds)
override {
819 return chooseNode(bounds)->chooseSubtree(bounds);
823 Node *bestNodeForVolume =
nullptr;
824 U bestVolume = std::numeric_limits<U>::max();
826 Node *bestNodeForExtentLength =
nullptr;
827 U bestExtentLength = std::numeric_limits<U>::max();
829 for (
auto& entry : m_entries) {
830 if (entry.bounds.getIntersection(bounds) == bounds) {
831 U volume = entry.bounds.getVolume();
833 if (bestNodeForVolume ==
nullptr || volume < bestVolume) {
835 bestNodeForVolume = entry.child;
838 U extentDistance = entry.bounds.getExtentLength();
840 if (bestNodeForExtentLength ==
nullptr || extentDistance < bestExtentLength) {
841 bestExtentLength = extentDistance;
842 bestNodeForExtentLength = entry.child;
847 if (bestNodeForVolume !=
nullptr) {
848 if (bestVolume > 0) {
849 return bestNodeForVolume;
852 assert(bestNodeForExtentLength);
853 return bestNodeForExtentLength;
860 Node *covering = searchForCoveringNode(bounds);
862 if (covering !=
nullptr) {
866 std::sort(m_entries.begin(), m_entries.end(), ExtentLengthEnlargement(bounds));
868 OverlapExtentLengthEnlargement extentDistanceEnlargement(bounds, m_entries.front());
872 for (p = m_entries.size() - 1; p > 0; --p) {
873 if (extentDistanceEnlargement(m_entries[p]) != 0) {
879 return m_entries[0].child;
882 std::vector<Candidate> candidates(p + 1, { 0,
false,
U() });
883 Node *node =
nullptr;
885 if (existsEmptyVolumeExtension(bounds)) {
886 node = findCandidates<OverlapExtentLengthEnlargement>(0, p, bounds, candidates);
888 node = findCandidates<OverlapVolumeEnlargement>(0, p, bounds, candidates);
891 if (node !=
nullptr) {
895 candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [](
const Candidate& candidate) {
896 return !candidate.isCandidate;
897 }), candidates.end());
899 assert(!candidates.empty());
901 auto it = std::min_element(candidates.begin(), candidates.end(), [](
const Candidate& lhs,
const Candidate& rhs) {
902 return lhs.overlap < rhs.overlap;
905 return m_entries[it->index].child;
908 virtual Box<U,N> computeBounds()
const override {
909 assert(!m_entries.empty());
912 for (
auto& entry : m_entries) {
913 res.extend(entry.bounds);
919 virtual void appendToStructure(std::vector<
SpatialStructure<U, N>>& structures,
int level)
const override {
920 for (
auto& entry : m_entries) {
922 entry.child->appendToStructure(structures, level + 1);
926 void updateBoundsForChild(
const Box<U, N>& bounds,
Node *child) {
927 for (
auto& entry : m_entries) {
928 if (entry.child == child) {
929 entry.bounds = bounds;
940 entry.bounds = bounds;
942 m_entries.push_back(std::move(entry));
945 if (m_entries.size() < Size) {
949 std::vector<Box<U, N>> boxes;
951 std::transform(m_entries.begin(), m_entries.end(), std::back_inserter(boxes), [](
const Entry& entry) {
955 SplitResult split = computeSplit(boxes);
957 switch (split.order) {
958 case SplitOrder::Min:
959 std::sort(m_entries.begin(), m_entries.end(), EntryMinAxisComparator<BranchEntry>(split.axis));
961 case SplitOrder::Max:
962 std::sort(m_entries.begin(), m_entries.end(), EntryMaxAxisComparator<BranchEntry>(split.axis));
966 auto branch =
new Branch;
968 auto splitIteratorBegin = std::next(m_entries.begin(), split.index + 1);
969 auto splitIteratorEnd = m_entries.end();
971 std::move(splitIteratorBegin, splitIteratorEnd, std::back_inserter(branch->m_entries));
972 m_entries.erase(splitIteratorBegin, splitIteratorEnd);
974 for (
auto& entry : branch->m_entries) {
975 entry.child->setParent(branch);
988 bool existsEmptyVolumeExtension(
const Box<U, N>& bounds) {
989 for (
auto& entry : m_entries) {
990 if (entry.bounds.getExtended(bounds).getVolume() == 0) {
998 template<
typename OverlapEnlargement>
999 Node *findCandidates(std::size_t t, std::size_t p,
const Box<U, N>& bounds, std::vector<Candidate>& candidates) {
1000 candidates[t].index = t;
1001 candidates[t].isCandidate =
true;
1003 OverlapEnlargement enlargement(bounds, m_entries[t]);
1007 for (std::size_t i = 0; i <= p; ++i) {
1012 U localOverlap = enlargement(m_entries[i]);
1013 overlap += localOverlap;
1015 if (localOverlap == 0 && !candidates[i].isCandidate) {
1016 Node *node = findCandidates<OverlapEnlargement>(i, p, bounds, candidates);
1018 if (node !=
nullptr) {
1025 return m_entries[t].child;
1028 candidates[t].overlap = overlap;
1032 struct SplitStatus {
1033 bool overlapFree =
false;
1034 U currentValue = std::numeric_limits<U>::max();
1037 SplitResult computeSplit(std::vector<
Box<U, N>>& boxes) {
1041 for (std::size_t axis = 0; axis <
N; ++axis) {
1042 std::sort(boxes.begin(), boxes.end(), MinAxisComparator(axis));
1043 computeBestSplitValue(boxes, result, status, axis, SplitOrder::Min);
1045 std::sort(boxes.begin(), boxes.end(), MaxAxisComparator(axis));
1046 computeBestSplitValue(boxes, result, status, axis, SplitOrder::Max);
1052 void computeBestSplitValue(std::vector<
Box<U, N>>& boxes, SplitResult& result, SplitStatus& status, std::size_t axis, SplitOrder order) {
1053 std::vector<Box<U, N>> firstBounds;
1055 std::partial_sum(boxes.begin(), boxes.end(), std::back_inserter(firstBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
1059 std::vector<Box<U, N>> secondBounds;
1061 std::partial_sum(boxes.rbegin(), boxes.rend(), std::back_inserter(secondBounds), [](
const Box<U, N>& lhs,
const Box<U, N>& rhs) {
1067 const auto& bounds = firstBounds.back();
1070 if (Node::hasOriginalBounds()) {
1071 asym = 2.0f * ((bounds.max[axis] + bounds.min[axis]) / 2 - Node::getOriginalCenterAxisValue(axis)) / (bounds.max[axis] - bounds.min[axis]);
1074 assert(-1.0f <= asym && asym <= 1.0f);
1076 static constexpr
float S = 0.5f;
1077 const float mu = (1 - 2.0f * MinSize / (MaxSize + 1)) * asym;
1078 const float rho = S * (1 + std::abs(mu));
1079 const float y1 = std::exp(- 1 / (S * S));
1080 const float ys = 1 / (1 - y1);
1082 auto wf = [mu,rho,y1,ys](std::size_t i) {
1083 const float xi = 2.0f * i / (MaxSize + 1.0f) - 1.0f;
1084 return ys * (std::exp(-
gf::square((xi - mu) / rho) - y1));
1091 if (firstBounds[MinSize].getVolume() == 0 || secondBounds[MinSize].getVolume() == 0) {
1099 U perimeterMax = 2 * bounds.getExtentLength() - bounds.getMinimumEdge();
1101 for (std::size_t index = MinSize; index <= MaxSize - MinSize + 1; ++index) {
1102 auto weight = (firstBounds[index].*overlapFn)(secondBounds[Size - index - 1]);
1104 if (!status.overlapFree) {
1106 status.overlapFree =
true;
1108 auto value = weight * wf(index);
1110 if (value < status.currentValue) {
1111 status.currentValue = value;
1112 result.index = index;
1114 result.order = order;
1119 if (status.overlapFree && weight == 0) {
1120 weight = firstBounds[index].getExtentLength() + secondBounds[Size - index - 1].getExtentLength() - perimeterMax;
1121 assert(weight <= 0);
1123 auto value = weight / wf(index);
1125 if (value < status.currentValue) {
1126 status.currentValue = value;
1127 result.index = index;
1129 result.order = order;
1136 boost::container::static_vector<BranchEntry, Size> m_entries;
1143 class ExtentLengthEnlargement {
1145 ExtentLengthEnlargement(
const Box<U, N>& bounds)
1151 bool operator()(
const Entry& lhs,
const Entry& rhs)
const {
1152 return getExtentLengthEnlargement(lhs) < getExtentLengthEnlargement(rhs);
1155 U getExtentLengthEnlargement(
const Entry& entry)
const {
1156 return entry.bounds.getExtended(m_bounds).getExtentLength() - entry.bounds.getExtentLength();
1163 class OverlapExtentLengthEnlargement {
1165 OverlapExtentLengthEnlargement(
const Box<U, N>& bounds,
const Entry& reference)
1167 , m_reference(reference)
1168 , m_extended(reference.bounds.getExtended(bounds))
1173 U operator()(
const Entry& entry)
const {
1174 return getOverlapExtentLengthEnlargement(entry);
1177 U getOverlapExtentLengthEnlargement(
const Entry& entry)
const {
1178 return m_extended.getIntersectionExtentLength(entry.bounds) - m_reference.bounds.getIntersectionExtentLength(entry.bounds);
1183 const Entry& m_reference;
1188 class OverlapVolumeEnlargement {
1190 OverlapVolumeEnlargement(
const Box<U, N>& bounds,
const Entry& reference)
1192 , m_reference(reference)
1193 , m_extended(reference.bounds.getExtended(bounds))
1198 U operator()(
const Entry& entry)
const {
1199 return getOverlapVolumeEnlargement(entry);
1202 U getOverlapVolumeEnlargement(
const Entry& entry)
const {
1203 return m_extended.getIntersectionVolume(entry.bounds) - m_reference.bounds.getIntersectionVolume(entry.bounds);
1208 const Entry& m_reference;
1212 class MinAxisComparator {
1214 MinAxisComparator(std::size_t axis)
1221 return std::make_tuple(lhs.
min[m_axis], lhs.
max[m_axis]) < std::make_tuple(rhs.
min[m_axis], rhs.
max[m_axis]);
1228 template<
typename Entry>
1229 class EntryMinAxisComparator {
1231 EntryMinAxisComparator(std::size_t axis)
1237 bool operator()(
const Entry& lhs,
const Entry& rhs) {
1238 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]);
1245 class MaxAxisComparator {
1247 MaxAxisComparator(std::size_t axis)
1254 return std::make_tuple(lhs.
max[m_axis], lhs.
min[m_axis]) < std::make_tuple(rhs.
max[m_axis], rhs.
min[m_axis]);
1261 template<
typename Entry>
1262 class EntryMaxAxisComparator {
1264 EntryMaxAxisComparator(std::size_t axis)
1270 bool operator()(
const Entry& lhs,
const Entry& rhs) {
1271 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]);
1279 void updateBounds(
Node *node) {
1280 while (node !=
nullptr) {
1281 Box<U, N> bounds = node->computeBounds();
1283 Branch *parent = node->getParent();
1285 if (parent !=
nullptr) {
1286 parent->updateBoundsForChild(bounds, node);
1298 #ifndef DOXYGEN_SHOULD_SKIP_THIS 1303 #endif // GF_SPATIAL_H constexpr Box< T, N > getExtended(const Box< T, N > &other) const noexcept
Get the box extended by another box.
Definition: Box.h:335
bool insert(T value, const Box< U, N > &bounds)
Insert an object in the tree.
Definition: Spatial.h:384
constexpr bool intersects(const Box< T, N > &other) const noexcept
Check if two boxes interset.
Definition: Box.h:203
Upper-right quarter.
Definition: Quarter.h:35
The structure represents an internal node.
void clear()
Remove all the objects from the tree.
Definition: Spatial.h:143
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:446
std::function< void(const T &)> SpatialQueryCallback
A callback for spatial query.
Definition: Spatial.h:87
std::vector< SpatialStructure< U, N > > getStructure() const
Definition: Spatial.h:458
constexpr Vector2f transform(const Matrix3f &mat, Vector2f point)
Apply an affine transformation to a 2D point.
Definition: Transform.h:323
SpatialStructureType type
The type of the structure.
Definition: Spatial.h:69
SpatialStructureType
A type of spatial structure.
Definition: Spatial.h:53
Box< U, N > bounds
The bounds of the structure.
Definition: Spatial.h:68
Vector< T, N > min
The minimum point of the box.
Definition: Box.h:53
Search for all objects that contain the given bounds.
constexpr Box< T, 2 > computeBoxQuarter(const Box< T, 2 > &box, Quarter quarter)
Divide a box in quarters.
Definition: Box.h:466
~RStarTree()
Destructor.
Definition: Spatial.h:373
Lower-right quarter.
Definition: Quarter.h:36
A spatial structure.
Definition: Spatial.h:67
Upper-left quarter.
Definition: Quarter.h:34
std::vector< SpatialStructure< U, 2 > > getStructure() const
Definition: Spatial.h:148
constexpr T square(T val)
Square function.
Definition: Math.h:289
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:136
Search for all objects that intersect the given bounds.
RStarTree & operator=(RStarTree &&other) noexcept
Move assignement.
Definition: Spatial.h:365
void clear()
Remove all the objects from the tree.
Definition: Spatial.h:453
The namespace for gf classes.
Definition: Action.h:35
QuadTree(const Box< U, 2 > &bounds)
Constructor.
Definition: Spatial.h:105
RStarTree()
Constructor.
Definition: Spatial.h:338
An implementation of quadtree.
Definition: Spatial.h:97
Lower-left quarter.
Definition: Quarter.h:37
The structure represents an actuel object.
Vector< T, N > max
The maximum point of the box.
Definition: Box.h:54
int level
The level of the structure.
Definition: Spatial.h:70
RStarTree(RStarTree &&other) noexcept
Move constructor.
Definition: Spatial.h:357
An implemntation of a R* tree.
Definition: Spatial.h:330
SpatialQuery
A kind of spatial query.
Definition: Spatial.h:77
bool insert(T value, const Box< U, 2 > &bounds)
Insert an object in the tree.
Definition: Spatial.h:118
constexpr bool contains(Vector< T, N > point) const noexcept
Check if a point is inside the box.
Definition: Box.h:171
constexpr void unused(Args &&...)
A simple way to avoid warnings about unused variables.
Definition: Unused.h:35