@@ -1756,19 +1756,31 @@ std::vector<size_t> Flatbush<ArrayType>::searchImpl(const Box<ArrayType>& iBound
17561756 // find the end index of the node
17571757 const size_t wEnd = std::min (wNodeIndex + wNodeSize, upperBound (wNodeIndex));
17581758
1759- // search through child nodes
1760- for (size_t wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1761- // check if node bbox intersects with query bbox
1762- if (!detail::boxesIntersect (iBounds, mBoxes [wPosition])) {
1763- continue ;
1759+ // Split node-vs-leaf: the check is invariant across all children of a node
1760+ if (wNodeIndex >= wNumItems) {
1761+ // Internal node: just collect intersecting child node indices
1762+ for (size_t wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1763+ if (detail::boxesIntersect (iBounds, mBoxes [wPosition])) {
1764+ wQueue.push_back (getIndex<IsWideIndex>(wPosition));
1765+ }
17641766 }
1765-
1766- const size_t wIndex = getIndex<IsWideIndex>(wPosition);
1767-
1768- if (wNodeIndex >= wNumItems) {
1769- wQueue.push_back (wIndex); // node; add it to the search queue
1770- } else if (!iFilterFn || iFilterFn (wIndex, mBoxes [wPosition])) {
1771- wResults.push_back (wIndex); // leaf item
1767+ } else if (iFilterFn) {
1768+ // Leaf node with filter
1769+ for (size_t wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1770+ if (!detail::boxesIntersect (iBounds, mBoxes [wPosition])) {
1771+ continue ;
1772+ }
1773+ const auto wIndex = getIndex<IsWideIndex>(wPosition);
1774+ if (iFilterFn (wIndex, mBoxes [wPosition])) {
1775+ wResults.push_back (wIndex);
1776+ }
1777+ }
1778+ } else {
1779+ // Leaf node without filter
1780+ for (size_t wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1781+ if (detail::boxesIntersect (iBounds, mBoxes [wPosition])) {
1782+ wResults.push_back (getIndex<IsWideIndex>(wPosition));
1783+ }
17721784 }
17731785 }
17741786
@@ -1812,6 +1824,7 @@ std::vector<size_t> Flatbush<ArrayType>::neighborsImpl(const Point<ArrayType>& i
18121824 const auto wNumItems = numItems ();
18131825 const auto wNodeSize = nodeSize ();
18141826 auto wNodeIndex = mBoxes .size () - 1UL ;
1827+ auto wMaxDistance = iMaxDistSquared;
18151828 std::vector<IndexDistance> wQueueStorage;
18161829 wQueueStorage.reserve (wNodeSize << 2U );
18171830 std::priority_queue<IndexDistance> wQueue (std::less<IndexDistance>(), std::move (wQueueStorage));
@@ -1822,18 +1835,18 @@ std::vector<size_t> Flatbush<ArrayType>::neighborsImpl(const Point<ArrayType>& i
18221835 // find the end index of the node
18231836 const auto wEnd = std::min (wNodeIndex + wNodeSize, upperBound (wNodeIndex));
18241837
1825- // search through child nodes
18261838 for (auto wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1827- const size_t wIndex = getIndex<IsWideIndex>(wPosition);
18281839 const auto wDistSquared = detail::computeDistanceSquared (iPoint, mBoxes [wPosition]);
18291840
1830- if (wDistSquared > iMaxDistSquared ) {
1841+ if (wDistSquared > wMaxDistance ) {
18311842 continue ;
1832- } else if (wNodeIndex >= wNumItems) {
1833- wQueue.emplace (wIndex << 1U , wDistSquared);
1834- } else if (!iFilterFn || iFilterFn (wIndex, mBoxes [wPosition])) {
1835- // put an odd index if it's an item rather than a node, to recognize later
1836- wQueue.emplace ((wIndex << 1U ) + 1U , wDistSquared); // leaf node
1843+ }
1844+
1845+ const auto wIndex = getIndex<IsWideIndex>(wPosition);
1846+ const auto wIsInternalNode = wNodeIndex >= wNumItems;
1847+
1848+ if (wIsInternalNode || !iFilterFn || iFilterFn (wIndex, mBoxes [wPosition])) {
1849+ wQueue.emplace ((wIndex << 1U ) + !wIsInternalNode, wDistSquared);
18371850 }
18381851 }
18391852
@@ -1848,6 +1861,11 @@ std::vector<size_t> Flatbush<ArrayType>::neighborsImpl(const Point<ArrayType>& i
18481861
18491862 if (wQueue.empty ()) {
18501863 break ;
1864+ } else if (wResults.size () + 1U >= iMaxResults) {
1865+ // Tighten search radius: if we have enough pending results and the queue
1866+ // top is a node, its distance is the minimum possible for any future leaf.
1867+ // Any child farther than the farthest queued leaf can't contribute.
1868+ wMaxDistance = std::min (wMaxDistance, static_cast <double >(wQueue.top ().mDistance ));
18511869 }
18521870
18531871 wNodeIndex = wQueue.top ().mId >> 3U ; // 1 to undo indexing + 2 for binary compatibility with JS
0 commit comments