@@ -1392,7 +1392,7 @@ class Flatbush {
13921392 std::vector<size_t > searchImpl (const Box<ArrayType>& iBounds,
13931393 const FilterCb& iFilterFn) const noexcept ;
13941394
1395- template <bool IsWideIndex>
1395+ template <bool IsWideIndex, bool UseHeap >
13961396 std::vector<size_t > neighborsImpl (const Point<ArrayType>& iPoint,
13971397 size_t iMaxResults,
13981398 double iMaxDistSquared,
@@ -1816,13 +1816,11 @@ std::vector<size_t> Flatbush<ArrayType>::search(const Box<ArrayType>& iBounds,
18161816}
18171817
18181818template <typename ArrayType>
1819- template <bool IsWideIndex>
1819+ template <bool IsWideIndex, bool UseHeap >
18201820std::vector<size_t > Flatbush<ArrayType>::neighborsImpl(const Point<ArrayType>& iPoint,
18211821 size_t iMaxResults,
18221822 double iMaxDistSquared,
18231823 const FilterCb& iFilterFn) const noexcept {
1824- static constexpr auto kMergeThreshold = 64UL ;
1825- const auto wUseHeap = iMaxResults > kMergeThreshold ;
18261824 const auto wNumItems = numItems ();
18271825 const auto wNodeSize = nodeSize ();
18281826 auto wNodeIndex = mBoxes .size () - 1UL ;
@@ -1834,55 +1832,47 @@ std::vector<size_t> Flatbush<ArrayType>::neighborsImpl(const Point<ArrayType>& i
18341832 while (true ) {
18351833 // find the end index of the node
18361834 const auto wEnd = std::min (wNodeIndex + wNodeSize, upperBound (wNodeIndex));
1835+ const auto wIsInternalNode = wNodeIndex >= wNumItems;
1836+ const auto wQueueSize = wQueue.size ();
18371837
1838- if (wUseHeap) {
1839- // Heap strategy: push_heap after each insert, pop from front
1840- for (auto wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1841- const auto wDistSquared = detail::computeDistanceSquared (iPoint, mBoxes [wPosition]);
1842- if (wDistSquared > iMaxDistSquared) {
1843- continue ;
1844- }
1845- const auto wIndex = getIndex<IsWideIndex>(wPosition);
1846- const auto wIsInternalNode = wNodeIndex >= wNumItems;
1847- if (wIsInternalNode || !iFilterFn || iFilterFn (wIndex, mBoxes [wPosition])) {
1848- wQueue.emplace_back ((wIndex << 1U ) + !wIsInternalNode, wDistSquared);
1849- std::push_heap (wQueue.begin (), wQueue.end ());
1850- }
1838+ for (auto wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1839+ const auto wDistSquared = detail::computeDistanceSquared (iPoint, mBoxes [wPosition]);
1840+
1841+ if (wDistSquared > iMaxDistSquared) {
1842+ continue ;
1843+ }
1844+
1845+ const auto wIndex = getIndex<IsWideIndex>(wPosition);
1846+
1847+ if (wIsInternalNode || !iFilterFn || iFilterFn (wIndex, mBoxes [wPosition])) {
1848+ wQueue.emplace_back ((wIndex << 1U ) + !wIsInternalNode, wDistSquared);
1849+ if (UseHeap) std::push_heap (wQueue.begin (), wQueue.end ());
18511850 }
1851+ }
18521852
1853+ if (UseHeap) { // Heap strategy: push_heap after each insert, pop from front
18531854 while (!wQueue.empty () && (wQueue.front ().mId & 1U )) {
18541855 wResults.push_back (wQueue.front ().mId >> 1U );
18551856 std::pop_heap (wQueue.begin (), wQueue.end ());
18561857 wQueue.pop_back ();
1858+
18571859 if (wResults.size () >= iMaxResults) {
18581860 return wResults;
18591861 }
18601862 }
1861- } else {
1862- // Sorted-vector strategy: batch insert, sort+merge, pop from back
1863- const auto wOldSize = wQueue.size ();
1864-
1865- for (auto wPosition = wNodeIndex; wPosition < wEnd; ++wPosition) {
1866- const auto wDistSquared = detail::computeDistanceSquared (iPoint, mBoxes [wPosition]);
1867- if (wDistSquared > iMaxDistSquared) {
1868- continue ;
1869- }
1870- const auto wIndex = getIndex<IsWideIndex>(wPosition);
1871- const auto wIsInternalNode = wNodeIndex >= wNumItems;
1872- if (wIsInternalNode || !iFilterFn || iFilterFn (wIndex, mBoxes [wPosition])) {
1873- wQueue.emplace_back ((wIndex << 1U ) + !wIsInternalNode, wDistSquared);
1874- }
1875- }
18761863
1877- if (wQueue.size () > wOldSize) {
1878- const auto wMid = wQueue.begin () + static_cast <ptrdiff_t >(wOldSize);
1879- std::sort (wMid, wQueue.end (), std::less<IndexDistance>());
1880- std::inplace_merge (wQueue.begin (), wMid, wQueue.end (), std::less<IndexDistance>());
1864+ std::pop_heap (wQueue.begin (), wQueue.end ());
1865+ } else { // Sorted-vector strategy: batch insert, sort+merge, pop from back
1866+ if (wQueue.size () > wQueueSize) {
1867+ const auto wMid = wQueue.begin () + static_cast <ptrdiff_t >(wQueueSize);
1868+ std::sort (wMid, wQueue.end ());
1869+ std::inplace_merge (wQueue.begin (), wMid, wQueue.end ());
18811870 }
18821871
18831872 while (!wQueue.empty () && (wQueue.back ().mId & 1U )) {
18841873 wResults.push_back (wQueue.back ().mId >> 1U );
18851874 wQueue.pop_back ();
1875+
18861876 if (wResults.size () >= iMaxResults) {
18871877 return wResults;
18881878 }
@@ -1893,8 +1883,7 @@ std::vector<size_t> Flatbush<ArrayType>::neighborsImpl(const Point<ArrayType>& i
18931883 break ;
18941884 }
18951885
1896- if (wUseHeap) std::pop_heap (wQueue.begin (), wQueue.end ());
1897- wNodeIndex = wQueue.back ().mId >> 3U ;
1886+ wNodeIndex = wQueue.back ().mId >> 3U ; // undo indexing + for binary compatibility with JS
18981887 wQueue.pop_back ();
18991888
19001889#ifdef __GNUC__
@@ -1912,17 +1901,29 @@ std::vector<size_t> Flatbush<ArrayType>::neighbors(const Point<ArrayType>& iPoin
19121901 size_t iMaxResults,
19131902 double iMaxDistance,
19141903 const FilterCb& iFilterFn) const noexcept {
1904+ static constexpr auto kMergeThreshold = 64UL ;
1905+ static constexpr auto kWideIndex = true ;
1906+ static constexpr auto kUseHeap = true ;
19151907 const auto wMaxDistSquared = iMaxDistance * iMaxDistance;
1908+ const auto wNeedHeap = iMaxResults > kMergeThreshold ;
19161909
19171910 if (!canDoNeighbors (iPoint, iMaxResults, iMaxDistance, wMaxDistSquared)) {
19181911 return {};
19191912 }
19201913
19211914 if (mIsWideIndex ) {
1922- return neighborsImpl<true >(iPoint, iMaxResults, wMaxDistSquared, iFilterFn);
1915+ if (wNeedHeap) {
1916+ return neighborsImpl<kWideIndex , kUseHeap >(iPoint, iMaxResults, wMaxDistSquared, iFilterFn);
1917+ }
1918+
1919+ return neighborsImpl<kWideIndex , !kUseHeap >(iPoint, iMaxResults, wMaxDistSquared, iFilterFn);
1920+ }
1921+
1922+ if (wNeedHeap) {
1923+ return neighborsImpl<!kWideIndex , kUseHeap >(iPoint, iMaxResults, wMaxDistSquared, iFilterFn);
19231924 }
19241925
1925- return neighborsImpl<false >(iPoint, iMaxResults, wMaxDistSquared, iFilterFn);
1926+ return neighborsImpl<! kWideIndex , ! kUseHeap >(iPoint, iMaxResults, wMaxDistSquared, iFilterFn);
19261927}
19271928} // namespace flatbush
19281929
0 commit comments