135 using Rect = std::remove_cvref_t<decltype(std::declval<const S&>().bbox())>;
138 using WeightType = std::remove_cvref_t<std::invoke_result_t<const WeightFn&, const ShapeType&>>;
164 static constexpr bool usesFilter = detail::arbitraryPrecision<NumberType>;
176 static constexpr bool hasTotalBoundingBox =
177 requires(
const T& t) { t.bbox(); } &&
181 template <
class QueryRect>
189 struct NoQueryBoxes {};
198 template <
class Coordinate>
199 static double filterBound(
const Coordinate& value,
bool below) {
200 const detail::Approximate a = detail::approximate(value);
201 const double slack = a.error * detail::approximateMargin + 0x1p-1000;
202 return below ? a.value - slack : a.value + slack;
209 template <
class OtherRect>
210 static FilterBox filterBoxOf(
const OtherRect& r) {
211 const double xmin = filterBound(r.min().x(),
true);
212 const double ymin = filterBound(r.min().y(),
true);
213 const double xmax = filterBound(r.max().x(),
false);
214 const double ymax = filterBound(r.max().y(),
false);
215 if (std::isnan(xmin) || std::isnan(ymin) || std::isnan(xmax) || std::isnan(ymax)) {
216 const double lo = -detail::numeric_limits<double>::infinity();
217 const double hi = detail::numeric_limits<double>::infinity();
218 return FilterBox(lo, lo, hi, hi,
true);
220 return FilterBox(xmin, ymin, xmax, ymax,
true);
224 static auto queryBoxesOf(
const Q& q) {
225 if constexpr (hasTotalBoundingBox<Q>) {
228 if constexpr (usesFilter) {
229 filter = filterBoxOf(box);
231 return QueryBoxes<
decltype(box)>{std::move(box), filter};
233 return NoQueryBoxes{};
239 std::ptrdiff_t left = -1, right = -1;
240 std::size_t count = 0;
242 std::vector<std::size_t> elementIndices;
248 [[nodiscard]] std::size_t index(
const ShapeTree& tree)
const {
249 return static_cast<std::size_t
>(
this - tree.nodes_.data());
254 template <
class Q,
class QB>
255 [[nodiscard]]
bool boxMisses(
const ShapeTree& tree,
const Q&,
const QB& qb)
const {
256 if constexpr (std::is_same_v<QB, NoQueryBoxes> || boxShaped<Q>) {
259 if constexpr (usesFilter) {
260 if (!qb.filter.intersects(tree.nodeFilterBoxes_[index(tree)])) {
264 return !qb.box.intersects(box);
270 template <
class Q,
class QB>
271 [[nodiscard]]
bool elementBoxMisses(
const ShapeTree& tree,
const Q&,
const QB& qb,
272 std::size_t i)
const {
273 if constexpr (std::is_same_v<QB, NoQueryBoxes> ||
274 (boxShaped<Q> && boxShaped<ShapeType>)) {
276 }
else if constexpr (usesFilter) {
277 return !qb.filter.intersects(tree.filterBoxes_[i]);
279 return !qb.box.intersects(tree.elements_[i].bbox());
283 template <
class Q,
class QB>
284 [[nodiscard]] std::size_t countIntersecting(
const ShapeTree& tree,
const Q& q,
285 const QB& qb)
const {
286 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
289 if (q.contains(box)) {
294 for (std::size_t i : elementIndices) {
295 if (!elementBoxMisses(tree, q, qb, i) && tree.elements_[i].intersects(q)) {
300 ret += tree.nodes_[left].countIntersecting(tree, q, qb);
303 ret += tree.nodes_[right].countIntersecting(tree, q, qb);
308 template <
class Q,
class QB>
310 const QB& qb)
const {
311 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
314 if (q.contains(box)) {
319 for (std::size_t i : elementIndices) {
320 if (!elementBoxMisses(tree, q, qb, i) && tree.elements_[i].intersects(q)) {
321 ret = ret + tree.weight_(tree.elements_[i]);
325 ret = ret + tree.nodes_[left].sumIntersecting(tree, q, qb);
328 ret = ret + tree.nodes_[right].sumIntersecting(tree, q, qb);
334 void collectAll(
const ShapeTree& tree, std::vector<ShapeType>& out)
const {
335 for (std::size_t i : elementIndices) {
336 out.push_back(tree.elements_[i]);
339 tree.nodes_[left].collectAll(tree, out);
342 tree.nodes_[right].collectAll(tree, out);
346 template <
class Q,
class QB>
347 void reportIntersecting(
const ShapeTree& tree,
const Q& q,
const QB& qb,
348 std::vector<ShapeType>& out)
const {
349 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
352 if (q.contains(box)) {
354 collectAll(tree, out);
357 for (std::size_t i : elementIndices) {
358 if (!elementBoxMisses(tree, q, qb, i) && tree.elements_[i].intersects(q)) {
359 out.push_back(tree.elements_[i]);
363 tree.nodes_[left].reportIntersecting(tree, q, qb, out);
366 tree.nodes_[right].reportIntersecting(tree, q, qb, out);
373 [[nodiscard]]
bool visitAll(
const ShapeTree& tree, Fn& fn)
const {
374 for (std::size_t i : elementIndices) {
375 if (detail::invokeVisitor(fn, tree.elements_[i])) {
379 if (left != -1 && tree.nodes_[left].visitAll(tree, fn)) {
382 if (right != -1 && tree.nodes_[right].visitAll(tree, fn)) {
388 template <
class Q,
class QB,
class Fn>
389 [[nodiscard]]
bool visitIntersecting(
const ShapeTree& tree,
const Q& q,
const QB& qb,
391 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
394 if (q.contains(box)) {
396 return visitAll(tree, fn);
398 for (std::size_t i : elementIndices) {
399 if (!elementBoxMisses(tree, q, qb, i) && tree.elements_[i].intersects(q) &&
400 detail::invokeVisitor(fn, tree.elements_[i])) {
404 if (left != -1 && tree.nodes_[left].visitIntersecting(tree, q, qb, fn)) {
407 if (right != -1 && tree.nodes_[right].visitIntersecting(tree, q, qb, fn)) {
413 template <
class Q,
class QB>
414 [[nodiscard]]
bool anyIntersecting(
const ShapeTree& tree,
const Q& q,
415 const QB& qb)
const {
416 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
419 if (q.contains(box)) {
423 for (std::size_t i : elementIndices) {
424 if (!elementBoxMisses(tree, q, qb, i) && tree.elements_[i].intersects(q)) {
428 if (left != -1 && tree.nodes_[left].anyIntersecting(tree, q, qb)) {
431 if (right != -1 && tree.nodes_[right].anyIntersecting(tree, q, qb)) {
439 template <
class Q,
class QB>
440 [[nodiscard]] std::size_t countContainedIn(
const ShapeTree& tree,
const Q& q,
441 const QB& qb)
const {
442 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
445 if (q.contains(box)) {
450 for (std::size_t i : elementIndices) {
451 if (!elementBoxMisses(tree, q, qb, i) && q.contains(tree.elements_[i])) {
456 ret += tree.nodes_[left].countContainedIn(tree, q, qb);
459 ret += tree.nodes_[right].countContainedIn(tree, q, qb);
464 template <
class Q,
class QB>
466 const QB& qb)
const {
467 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
470 if (q.contains(box)) {
474 for (std::size_t i : elementIndices) {
475 if (!elementBoxMisses(tree, q, qb, i) && q.contains(tree.elements_[i])) {
476 ret = ret + tree.weight_(tree.elements_[i]);
480 ret = ret + tree.nodes_[left].sumContainedIn(tree, q, qb);
483 ret = ret + tree.nodes_[right].sumContainedIn(tree, q, qb);
488 template <
class Q,
class QB>
489 void reportContainedIn(
const ShapeTree& tree,
const Q& q,
const QB& qb,
490 std::vector<ShapeType>& out)
const {
491 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
494 if (q.contains(box)) {
495 collectAll(tree, out);
498 for (std::size_t i : elementIndices) {
499 if (!elementBoxMisses(tree, q, qb, i) && q.contains(tree.elements_[i])) {
500 out.push_back(tree.elements_[i]);
504 tree.nodes_[left].reportContainedIn(tree, q, qb, out);
507 tree.nodes_[right].reportContainedIn(tree, q, qb, out);
511 template <
class Q,
class QB,
class Fn>
512 [[nodiscard]]
bool visitContainedIn(
const ShapeTree& tree,
const Q& q,
const QB& qb,
514 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
517 if (q.contains(box)) {
518 return visitAll(tree, fn);
520 for (std::size_t i : elementIndices) {
521 if (!elementBoxMisses(tree, q, qb, i) && q.contains(tree.elements_[i]) &&
522 detail::invokeVisitor(fn, tree.elements_[i])) {
526 if (left != -1 && tree.nodes_[left].visitContainedIn(tree, q, qb, fn)) {
529 if (right != -1 && tree.nodes_[right].visitContainedIn(tree, q, qb, fn)) {
535 template <
class Q,
class QB>
536 [[nodiscard]]
bool anyContainedIn(
const ShapeTree& tree,
const Q& q,
537 const QB& qb)
const {
538 if (boxMisses(tree, q, qb) || !q.intersects(box)) {
541 if (q.contains(box)) {
544 for (std::size_t i : elementIndices) {
545 if (!elementBoxMisses(tree, q, qb, i) && q.contains(tree.elements_[i])) {
549 if (left != -1 && tree.nodes_[left].anyContainedIn(tree, q, qb)) {
552 if (right != -1 && tree.nodes_[right].anyContainedIn(tree, q, qb)) {
564 const Rect& sb)
const {
565 if (!box.contains(sb)) {
568 for (std::size_t i : elementIndices) {
569 if (tree.elements_[i] == shape) {
573 if (left != -1 && tree.nodes_[left].containsShape(tree, shape, sb)) {
576 if (right != -1 && tree.nodes_[right].containsShape(tree, shape, sb)) {
591 template <
class ResultNumber,
class Metric,
class Q>
592 void nearest(
const ShapeTree& tree,
const Q& q, ResultNumber& bestDist,
593 std::ptrdiff_t& bestIndex)
const {
594 if (bestIndex != -1) {
595 const ResultNumber lowerBound = Metric::template distance<ResultNumber>(q, box);
596 if (!(lowerBound < bestDist)) {
601 for (std::size_t i : elementIndices) {
602 const ResultNumber d = Metric::template distance<ResultNumber>(q, tree.elements_[i]);
603 if (bestIndex == -1 || d < bestDist) {
605 bestIndex =
static_cast<std::ptrdiff_t
>(i);
614 tree.nodes_[right].template nearest<ResultNumber, Metric>(tree, q, bestDist, bestIndex);
619 tree.nodes_[left].template nearest<ResultNumber, Metric>(tree, q, bestDist, bestIndex);
623 const ResultNumber leftBound = Metric::template distance<ResultNumber>(q, tree.nodes_[left].box);
624 const ResultNumber rightBound = Metric::template distance<ResultNumber>(q, tree.nodes_[right].box);
625 const std::ptrdiff_t nearChild = leftBound <= rightBound ? left : right;
626 const std::ptrdiff_t farChild = leftBound <= rightBound ? right : left;
627 tree.nodes_[nearChild].template nearest<ResultNumber, Metric>(tree, q, bestDist, bestIndex);
628 tree.nodes_[farChild].template nearest<ResultNumber, Metric>(tree, q, bestDist, bestIndex);
634 template <
class ResultNumber,
class Metric,
class Q>
635 void nearest(
const ShapeTree& tree,
const Q& q, std::size_t k,
636 std::vector<std::pair<ResultNumber, std::size_t>>& best)
const {
637 const auto nearer = [](
const auto& a,
const auto& b) {
638 return a.first < b.first;
641 if (best.size() == k) {
642 const ResultNumber lowerBound = Metric::template distance<ResultNumber>(q, box);
643 if (!(lowerBound < best.front().first)) {
648 for (std::size_t i : elementIndices) {
649 const ResultNumber d = Metric::template distance<ResultNumber>(q, tree.elements_[i]);
650 if (best.size() < k) {
651 best.emplace_back(d, i);
652 std::push_heap(best.begin(), best.end(), nearer);
653 }
else if (d < best.front().first) {
654 std::pop_heap(best.begin(), best.end(), nearer);
655 best.back() = {d, i};
656 std::push_heap(best.begin(), best.end(), nearer);
662 tree.nodes_[right].template nearest<ResultNumber, Metric>(tree, q, k, best);
667 tree.nodes_[left].template nearest<ResultNumber, Metric>(tree, q, k, best);
671 const ResultNumber leftBound = Metric::template distance<ResultNumber>(q, tree.nodes_[left].box);
672 const ResultNumber rightBound = Metric::template distance<ResultNumber>(q, tree.nodes_[right].box);
673 const std::ptrdiff_t nearChild = leftBound <= rightBound ? left : right;
674 const std::ptrdiff_t farChild = leftBound <= rightBound ? right : left;
675 tree.nodes_[nearChild].template nearest<ResultNumber, Metric>(tree, q, k, best);
676 tree.nodes_[farChild].template nearest<ResultNumber, Metric>(tree, q, k, best);
680 static constexpr std::size_t defaultLeafSize = 6;
682 std::vector<ShapeType> elements_;
683 std::vector<Node> nodes_;
685 std::vector<FilterBox> filterBoxes_;
686 std::vector<FilterBox> nodeFilterBoxes_;
687 std::ptrdiff_t root_ = -1;
688 std::size_t leafSize_ = defaultLeafSize;
689 [[no_unique_address]] WeightFn weight_{};
693 std::ptrdiff_t allocNode() {
694 const std::ptrdiff_t
id =
static_cast<std::ptrdiff_t
>(nodes_.size());
695 nodes_.push_back(Node{});
696 if constexpr (usesFilter) {
697 nodeFilterBoxes_.emplace_back();
703 void refreshNodeFilterBox(std::ptrdiff_t
id) {
704 if constexpr (usesFilter) {
705 nodeFilterBoxes_[
static_cast<std::size_t
>(id)] = filterBoxOf(nodes_[
id].box);
714 std::size_t straddlers = 0;
715 std::size_t maxChild = 0;
716 std::size_t score = 0;
735 std::vector<EndPoint> lo[2], hi[2];
739 void sortEndsOnAxis(
const std::vector<std::size_t>& indices, std::size_t axis,
740 std::vector<EndPoint>& lo, std::vector<EndPoint>& hi)
const {
741 lo.reserve(indices.size());
742 hi.reserve(indices.size());
743 for (std::size_t i : indices) {
744 const auto box = elements_[i].bbox();
745 lo.push_back(EndPoint{box.min()[axis], i});
746 hi.push_back(EndPoint{box.max()[axis], i});
748 const auto byValue = [](
const EndPoint& a,
const EndPoint& b) {
return a.value < b.value; };
749 std::sort(lo.begin(), lo.end(), byValue);
750 std::sort(hi.begin(), hi.end(), byValue);
756 Split bestSplitOnEnds(
const std::vector<EndPoint>& los,
const std::vector<EndPoint>& his,
757 std::size_t axis)
const {
758 const std::size_t n = los.size();
760 best.axis =
static_cast<int>(axis);
761 std::size_t loPos = 0;
762 std::size_t hiPos = 0;
763 while (loPos < n || hiPos < n) {
768 hiPos == n || (loPos < n && los[loPos].value < his[hiPos].value)
771 while (loPos < n && !(v < los[loPos].value)) {
774 while (hiPos < n && !(v < his[hiPos].value)) {
779 const std::size_t leftCount = hiPos;
780 const std::size_t rightCount = n - loPos;
781 if (leftCount >= n || rightCount >= n || leftCount + rightCount == 0) {
784 const std::size_t straddlers = n - leftCount - rightCount;
785 const std::size_t maxChild = std::max(leftCount, rightCount);
786 const std::size_t score = maxChild + straddlers;
787 if (!best.found || score < best.score ||
788 (score == best.score && straddlers < best.straddlers)) {
791 best.straddlers = straddlers;
792 best.maxChild = maxChild;
802 Split bestSplitOnAxis(
const std::vector<std::size_t>& indices, std::size_t axis)
const {
807 if constexpr (PointConcept<ShapeType>) {
808 const std::size_t n = indices.size();
809 std::vector<std::size_t> ordered = indices;
810 const auto middle = ordered.begin() +
static_cast<std::ptrdiff_t
>(n / 2);
812 ordered.begin(), middle, ordered.end(),
813 [&](std::size_t a, std::size_t b) {
814 return elements_[a][axis] < elements_[b][axis];
816 const NumberType& median = elements_[*middle][axis];
818 std::size_t less = 0;
819 std::size_t equal = 0;
820 std::size_t predecessor = 0;
821 bool hasPredecessor =
false;
822 for (std::size_t i : indices) {
823 const NumberType& coordinate = elements_[i][axis];
824 if (coordinate < median) {
826 if (!hasPredecessor || elements_[predecessor][axis] < coordinate) {
828 hasPredecessor =
true;
830 }
else if (!(median < coordinate)) {
836 best.axis =
static_cast<int>(axis);
837 const auto consider = [&](
const NumberType& value, std::size_t leftCount) {
838 const std::size_t rightCount = n - leftCount;
839 if (leftCount >= n || rightCount >= n) {
842 const std::size_t score = std::max(leftCount, rightCount);
843 if (!best.found || score < best.score) {
846 best.maxChild = score;
850 if (hasPredecessor) {
851 consider(elements_[predecessor][axis], less);
853 consider(median, less + equal);
857 std::vector<EndPoint> los, his;
858 sortEndsOnAxis(indices, axis, los, his);
859 return bestSplitOnEnds(los, his, axis);
865 template <
class SplitOnAxis>
866 static Split chooseSplitOverAxes(std::size_t n,
int level, SplitOnAxis&& splitOnAxis) {
868 for (
int k = 0; k < 2; ++k) {
869 const std::size_t axis =
static_cast<std::size_t
>((level + k) % 2);
870 const Split candidate = splitOnAxis(axis);
871 if (!candidate.found) {
874 if (!best.found || candidate.score < best.score ||
875 (candidate.score == best.score && candidate.straddlers < best.straddlers)) {
880 if (candidate.straddlers == 0 && candidate.score == (n + 1) / 2) {
888 Split chooseSplit(
const std::vector<std::size_t>& indices,
int level)
const {
889 return chooseSplitOverAxes(indices.size(), level, [&](std::size_t axis) {
890 return bestSplitOnAxis(indices, axis);
895 Split chooseSplit(
const SortedEnds& ends,
int level)
const {
896 return chooseSplitOverAxes(ends.lo[0].size(), level, [&](std::size_t axis) {
897 return bestSplitOnEnds(ends.lo[axis], ends.hi[axis], axis);
903 void partitionBySplit(
const std::vector<std::size_t>& indices,
const Split& split,
904 std::vector<std::size_t>& leftIndices,
905 std::vector<std::size_t>& rightIndices,
906 std::vector<std::size_t>& straddlers)
const {
907 const auto a =
static_cast<std::size_t
>(split.axis);
908 for (std::size_t i : indices) {
909 const NumberType lo = elements_[i].bbox().min()[a];
910 const NumberType hi = elements_[i].bbox().max()[a];
911 if (hi <= split.value) {
912 leftIndices.push_back(i);
913 }
else if (lo > split.value) {
914 rightIndices.push_back(i);
916 straddlers.push_back(i);
924 std::ptrdiff_t makeNode(
const std::vector<std::size_t>& indices) {
925 Rect box =
Rect(elements_[indices[0]].bbox());
926 WeightType weightSum = weight_(elements_[indices[0]]);
932 if constexpr (usesFilter) {
933 filter = filterBoxes_[indices[0]];
935 for (std::size_t k = 1; k < indices.size(); ++k) {
936 box.insert(elements_[indices[k]].bbox());
937 weightSum = weightSum + weight_(elements_[indices[k]]);
938 if constexpr (usesFilter) {
939 filter.insert(filterBoxes_[indices[k]]);
945 const std::ptrdiff_t
id = allocNode();
946 nodes_[id].box = box;
947 if constexpr (usesFilter) {
948 nodeFilterBoxes_[
static_cast<std::size_t
>(id)] = filter;
950 nodes_[id].count = indices.size();
951 nodes_[id].weightSum = weightSum;
959 std::ptrdiff_t build(
const std::vector<std::size_t>& indices,
int level) {
960 const std::ptrdiff_t
id = makeNode(indices);
962 if (indices.size() <= leafSize_) {
963 nodes_[id].elementIndices = indices;
967 const Split best = chooseSplit(indices, level);
971 nodes_[id].elementIndices = indices;
975 std::vector<std::size_t> leftIndices, rightIndices, straddlers;
976 partitionBySplit(indices, best, leftIndices, rightIndices, straddlers);
978 const std::ptrdiff_t leftChild = leftIndices.empty() ? -1 : build(leftIndices, level + 1);
979 const std::ptrdiff_t rightChild = rightIndices.empty() ? -1 : build(rightIndices, level + 1);
980 nodes_[id].left = leftChild;
981 nodes_[id].right = rightChild;
982 nodes_[id].elementIndices = std::move(straddlers);
991 std::ptrdiff_t buildFromEnds(SortedEnds& ends,
int level, std::vector<std::uint8_t>& side) {
997 std::vector<std::size_t> indices;
998 indices.reserve(ends.lo[0].size());
999 for (
const EndPoint&
end : ends.lo[0]) {
1000 indices.push_back(
end.index);
1003 const std::ptrdiff_t
id = makeNode(indices);
1005 if (indices.size() <= leafSize_) {
1006 nodes_[id].elementIndices = std::move(indices);
1010 const Split best = chooseSplit(ends, level);
1012 nodes_[id].elementIndices = std::move(indices);
1019 static constexpr std::uint8_t toLeft = 0, toRight = 1, stays = 2;
1020 const auto a =
static_cast<std::size_t
>(best.axis);
1021 std::vector<std::size_t> straddlers;
1022 std::size_t leftCount = 0, rightCount = 0;
1023 for (std::size_t i : indices) {
1024 const auto box = elements_[i].bbox();
1025 const std::uint8_t which = box.max()[a] <= best.value ? toLeft
1026 : box.min()[a] > best.value ? toRight
1029 if (which == toLeft) {
1031 }
else if (which == toRight) {
1034 straddlers.push_back(i);
1038 SortedEnds left, right;
1039 const auto deal = [&](std::vector<EndPoint>& source, std::vector<EndPoint>& toTheLeft,
1040 std::vector<EndPoint>& toTheRight) {
1041 toTheLeft.reserve(leftCount);
1042 toTheRight.reserve(rightCount);
1043 for (
const EndPoint&
end : source) {
1044 if (side[
end.index] == toLeft) {
1045 toTheLeft.push_back(
end);
1046 }
else if (side[
end.index] == toRight) {
1047 toTheRight.push_back(
end);
1054 source.shrink_to_fit();
1056 for (
int axis = 0; axis < 2; ++axis) {
1057 deal(ends.lo[axis], left.lo[axis], right.lo[axis]);
1058 deal(ends.hi[axis], left.hi[axis], right.hi[axis]);
1061 const std::ptrdiff_t leftChild =
1062 leftCount == 0 ? -1 : buildFromEnds(left, level + 1, side);
1063 const std::ptrdiff_t rightChild =
1064 rightCount == 0 ? -1 : buildFromEnds(right, level + 1, side);
1065 nodes_[id].left = leftChild;
1066 nodes_[id].right = rightChild;
1067 nodes_[id].elementIndices = std::move(straddlers);
1073 void splitNode(std::ptrdiff_t
id,
int level) {
1074 std::vector<std::size_t> indices = std::move(nodes_[
id].elementIndices);
1075 nodes_[id].elementIndices.clear();
1077 const Split best = chooseSplit(indices, level);
1080 nodes_[id].elementIndices = std::move(indices);
1084 std::vector<std::size_t> leftIndices, rightIndices, straddlers;
1085 partitionBySplit(indices, best, leftIndices, rightIndices, straddlers);
1087 const std::ptrdiff_t leftChild = leftIndices.empty() ? -1 : build(leftIndices, level + 1);
1088 const std::ptrdiff_t rightChild = rightIndices.empty() ? -1 : build(rightIndices, level + 1);
1089 nodes_[id].left = leftChild;
1090 nodes_[id].right = rightChild;
1091 nodes_[id].elementIndices = std::move(straddlers);
1095 static auto enlargement(
const Rect& box,
const Rect& other) {
1097 grown.insert(other);
1098 return grown.area() - box.area();
1104 void insertInto(std::ptrdiff_t
id, std::size_t i,
const Rect& eb,
int level) {
1105 nodes_[id].box.insert(eb);
1106 refreshNodeFilterBox(
id);
1107 nodes_[id].count += 1;
1108 nodes_[id].weightSum = nodes_[id].weightSum + weight_(elements_[i]);
1110 if (nodes_[
id].left == -1 && nodes_[
id].right == -1) {
1111 nodes_[id].elementIndices.push_back(i);
1112 if (nodes_[
id].elementIndices.size() > leafSize_) {
1113 splitNode(
id, level);
1118 const std::ptrdiff_t L = nodes_[id].left;
1119 const std::ptrdiff_t R = nodes_[id].right;
1123 bool leftOk =
false;
1124 bool rightOk =
false;
1126 Rect grown = nodes_[L].box;
1128 leftOk = (R == -1) || !grown.intersects(nodes_[R].box);
1131 Rect grown = nodes_[R].box;
1133 rightOk = (L == -1) || !grown.intersects(nodes_[L].box);
1136 std::ptrdiff_t target = -1;
1137 if (leftOk && rightOk) {
1139 target = enlargement(nodes_[L].box, eb) <= enlargement(nodes_[R].box, eb) ? L : R;
1140 }
else if (leftOk) {
1142 }
else if (rightOk) {
1148 nodes_[id].elementIndices.push_back(i);
1151 insertInto(target, i, eb, level + 1);
1156 static constexpr bool hasWeight = !std::is_same_v<WeightType, detail::EmptyWeight>;
1160 static bool nodeIsEmpty(
const Node& node) {
1161 return node.elementIndices.empty() && node.left == -1 && node.right == -1;
1167 bool recomputeBox(std::ptrdiff_t
id) {
1168 Node& node = nodes_[id];
1171 for (std::size_t i : node.elementIndices) {
1172 const Rect eb =
Rect(elements_[i].bbox());
1180 if (node.left != -1) {
1182 newBox = nodes_[node.left].box;
1185 newBox.insert(nodes_[node.left].box);
1188 if (node.right != -1) {
1190 newBox = nodes_[node.right].box;
1193 newBox.insert(nodes_[node.right].box);
1196 const bool changed = !(newBox == node.box);
1198 refreshNodeFilterBox(
id);
1210 bool eraseFrom(std::ptrdiff_t
id,
const ShapeType& shape,
const Rect& sb,
1211 std::size_t& removedIdx,
WeightType& removedWeight,
bool& boxChanged,
1212 std::vector<std::ptrdiff_t>& dead) {
1214 if (!nodes_[
id].box.contains(sb)) {
1218 bool removed =
false;
1219 bool needBoxRecompute =
false;
1222 auto& elems = nodes_[id].elementIndices;
1223 for (std::size_t k = 0; k < elems.size(); ++k) {
1224 if (elements_[elems[k]] == shape) {
1225 removedIdx = elems[k];
1226 if constexpr (hasWeight) {
1227 removedWeight = weight_(elements_[removedIdx]);
1229 elems.erase(elems.begin() +
static_cast<std::ptrdiff_t
>(k));
1231 needBoxRecompute =
true;
1237 for (std::ptrdiff_t side = 0; !removed && side < 2; ++side) {
1238 std::ptrdiff_t& child = side == 0 ? nodes_[id].left : nodes_[id].right;
1242 bool childBoxChanged =
false;
1243 if (eraseFrom(child, shape, sb, removedIdx, removedWeight, childBoxChanged, dead)) {
1245 if (nodeIsEmpty(nodes_[child])) {
1246 dead.push_back(child);
1248 needBoxRecompute =
true;
1249 }
else if (childBoxChanged) {
1250 needBoxRecompute =
true;
1259 nodes_[id].count -= 1;
1260 if constexpr (hasWeight) {
1261 nodes_[id].weightSum = nodes_[id].weightSum - removedWeight;
1263 if (nodeIsEmpty(nodes_[
id])) {
1267 if (needBoxRecompute) {
1268 boxChanged = recomputeBox(
id);
1278 void remapElementIndex(std::size_t oldIdx, std::size_t newIdx,
const Rect& eb) {
1279 for (std::ptrdiff_t
id = root_;
id != -1;) {
1280 for (std::size_t& ref : nodes_[
id].elementIndices) {
1281 if (ref == oldIdx) {
1286 const std::ptrdiff_t left = nodes_[id].left;
1289 id = (left != -1 && nodes_[left].box.contains(eb)) ? left : nodes_[id].right;
1298 void repointNodeRef(std::ptrdiff_t oldId, std::ptrdiff_t newId,
const Rect& b) {
1299 if (root_ == oldId) {
1303 for (std::ptrdiff_t
id = root_;
id != -1;) {
1304 if (nodes_[
id].left == oldId) {
1305 nodes_[id].left = newId;
1308 if (nodes_[
id].right == oldId) {
1309 nodes_[id].right = newId;
1312 const std::ptrdiff_t left = nodes_[id].left;
1313 id = (left != -1 && nodes_[left].box.contains(b)) ? left : nodes_[id].right;
1323 void compactNodes(std::vector<std::ptrdiff_t>& dead) {
1324 std::sort(dead.begin(), dead.end());
1325 for (
auto it = dead.rbegin(); it != dead.rend(); ++it) {
1326 const std::ptrdiff_t hole = *it;
1327 const std::ptrdiff_t last =
static_cast<std::ptrdiff_t
>(nodes_.size()) - 1;
1329 nodes_[hole] = std::move(nodes_[last]);
1330 repointNodeRef(last, hole, nodes_[hole].box);
1331 if constexpr (usesFilter) {
1332 nodeFilterBoxes_[
static_cast<std::size_t
>(hole)] =
1333 nodeFilterBoxes_[
static_cast<std::size_t
>(last)];
1337 if constexpr (usesFilter) {
1338 nodeFilterBoxes_.pop_back();
1346 template <
class Metric,
class ResultNumber,
class Q>
1347 [[nodiscard]]
const ShapeType& nearestNeighborByMetric(
const Q& q)
const {
1352 ResultNumber bestDist{};
1353 std::ptrdiff_t bestIndex = -1;
1354 nodes_[root_].template nearest<ResultNumber, Metric>(*
this, q, bestDist, bestIndex);
1355 return elements_[
static_cast<std::size_t
>(bestIndex)];
1360 template <
class Metric,
class ResultNumber,
class Q>
1361 [[nodiscard]] std::vector<ShapeType> nearestNeighborsByMetric(
const Q& q,
int k)
const {
1362 if (root_ == -1 || k <= 0) {
1365 const std::size_t count = std::min(
static_cast<std::size_t
>(k), elements_.size());
1366 std::vector<std::pair<ResultNumber, std::size_t>> best;
1367 best.reserve(count);
1368 nodes_[root_].template nearest<ResultNumber, Metric>(*
this, q, count, best);
1369 std::sort(best.begin(), best.end(), [](
const auto& a,
const auto& b) {
1370 return a.first < b.first;
1373 std::vector<ShapeType> result;
1374 result.reserve(best.size());
1375 for (
const auto& [distance, index] : best) {
1377 result.push_back(elements_[index]);
1383 void buildFromElements() {
1385 nodeFilterBoxes_.clear();
1386 if constexpr (usesFilter) {
1387 filterBoxes_.clear();
1388 filterBoxes_.reserve(elements_.size());
1390 filterBoxes_.push_back(filterBoxOf(e.bbox()));
1394 if (elements_.empty()) {
1397 std::vector<std::size_t> indices(elements_.size());
1398 for (std::size_t i = 0; i < indices.size(); ++i) {
1401 nodes_.reserve(2 * elements_.size() / leafSize_ + 1);
1402 if constexpr (PointConcept<ShapeType>) {
1405 root_ = build(indices, 0);
1408 for (
int axis = 0; axis < 2; ++axis) {
1409 sortEndsOnAxis(indices,
static_cast<std::size_t
>(axis), ends.lo[axis],
1412 std::vector<std::uint8_t> side(elements_.size());
1413 root_ = buildFromEnds(ends, 0, side);
1418 void collectBoundingBoxes(std::ptrdiff_t
id, std::vector<Rect>& out)
const {
1422 out.push_back(nodes_[
id].box);
1423 collectBoundingBoxes(nodes_[
id].left, out);
1424 collectBoundingBoxes(nodes_[
id].right, out);
1438 template <
class Container>
1440 WeightFn weight = WeightFn{})
1441 : leafSize_(leafSize > 0 ? leafSize : 1), weight_(std::move(weight)) {
1442 for (
const auto& s :
shapes) {
1443 elements_.push_back(s);
1445 buildFromElements();
1457 template <
class Container>
1462 [[nodiscard]] std::size_t
size()
const {
1463 return elements_.size();
1468 return elements_.empty();
1472 [[nodiscard]]
const std::vector<ShapeType>&
shapes()
const {
1478 return elements_.begin();
1483 return elements_.end();
1488 return elements_.cbegin();
1493 return elements_.cend();
1513 const Rect eb =
Rect(shape.bbox());
1514 const std::size_t i = elements_.size();
1515 elements_.push_back(shape);
1516 if constexpr (usesFilter) {
1517 filterBoxes_.push_back(filterBoxOf(eb));
1521 root_ = allocNode();
1522 nodes_[root_].box = eb;
1523 refreshNodeFilterBox(root_);
1524 nodes_[root_].count = 1;
1525 nodes_[root_].weightSum = weight_(elements_[i]);
1526 nodes_[root_].elementIndices.push_back(i);
1529 insertInto(root_, i, eb, 0);
1545 leafSize_ = leafSize;
1547 buildFromElements();
1573 const Rect sb =
Rect(shape.bbox());
1574 std::size_t removedIdx = 0;
1576 bool boxChanged =
false;
1577 std::vector<std::ptrdiff_t> dead;
1578 if (!eraseFrom(root_, shape, sb, removedIdx, removedWeight, boxChanged, dead)) {
1581 if (nodeIsEmpty(nodes_[root_])) {
1582 dead.push_back(root_);
1587 const std::size_t last = elements_.size() - 1;
1588 if (removedIdx != last) {
1589 elements_[removedIdx] = std::move(elements_[last]);
1590 remapElementIndex(last, removedIdx,
Rect(elements_[removedIdx].bbox()));
1591 if constexpr (usesFilter) {
1592 filterBoxes_[removedIdx] = filterBoxes_[last];
1595 elements_.pop_back();
1596 if constexpr (usesFilter) {
1597 filterBoxes_.pop_back();
1620 return nodes_[root_].countIntersecting(*
this, q, queryBoxesOf(q));
1639 return nodes_[root_].sumIntersecting(*
this, q, queryBoxesOf(q));
1654 std::vector<ShapeType> out;
1656 nodes_[root_].reportIntersecting(*
this, q, queryBoxesOf(q), out);
1678 template <
class Q,
class Fn>
1680 return root_ == -1 ? false : nodes_[root_].visitIntersecting(*
this, q, queryBoxesOf(q), fn);
1694 return root_ == -1 ? true : !nodes_[root_].anyIntersecting(*
this, q, queryBoxesOf(q));
1713 return nodes_[root_].countContainedIn(*
this, q, queryBoxesOf(q));
1728 return nodes_[root_].sumContainedIn(*
this, q, queryBoxesOf(q));
1740 std::vector<ShapeType> out;
1742 nodes_[root_].reportContainedIn(*
this, q, queryBoxesOf(q), out);
1760 template <
class Q,
class Fn>
1762 return root_ == -1 ? false : nodes_[root_].visitContainedIn(*
this, q, queryBoxesOf(q), fn);
1776 return root_ == -1 ? true : !nodes_[root_].anyContainedIn(*
this, q, queryBoxesOf(q));
1791 return root_ != -1 && nodes_[root_].containsShape(*
this, shape,
Rect(shape.bbox()));
1828 using ResultNumber = std::remove_cvref_t<
decltype(
1829 q.squaredDistance(std::declval<const ShapeType&>()))>;
1830 return nearestNeighborByMetric<detail::SquaredMetric, ResultNumber>(q);
1833 template <
class ResultNumber,
class Q>
1835 return nearestNeighborByMetric<detail::SquaredMetric, ResultNumber>(q);
1853 using ResultNumber = std::remove_cvref_t<
decltype(
1854 q.squaredDistance(std::declval<const ShapeType&>()))>;
1855 return nearestNeighborsByMetric<detail::SquaredMetric, ResultNumber>(q, k);
1858 template <
class ResultNumber,
class Q>
1860 return nearestNeighborsByMetric<detail::SquaredMetric, ResultNumber>(q, k);
1880 using ResultNumber = std::remove_cvref_t<
decltype(
1881 q.distanceL1(std::declval<const ShapeType&>()))>;
1882 return nearestNeighborByMetric<detail::L1Metric, ResultNumber>(q);
1885 template <
class ResultNumber,
class Q>
1887 return nearestNeighborByMetric<detail::L1Metric, ResultNumber>(q);
1907 using ResultNumber = std::remove_cvref_t<
decltype(
1908 q.distanceLInf(std::declval<const ShapeType&>()))>;
1909 return nearestNeighborByMetric<detail::LInfMetric, ResultNumber>(q);
1912 template <
class ResultNumber,
class Q>
1914 return nearestNeighborByMetric<detail::LInfMetric, ResultNumber>(q);
1926 std::vector<Rect> out;
1927 out.reserve(nodes_.size());
1928 collectBoundingBoxes(root_, out);