72#include <condition_variable>
89#include <unordered_map>
93#define NANOFLANN_VERSION_STRING "1.12.1"
95#define NANOFLANN_VERSION 0x010C01
98#if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64))
111#if defined(__GNUC__) || defined(__clang__)
112#define NANOFLANN_RESTRICT __restrict__
113#elif defined(_MSC_VER)
114#define NANOFLANN_RESTRICT __restrict
116#define NANOFLANN_RESTRICT
120#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
121#define NANOFLANN_NODISCARD [[nodiscard]]
123#define NANOFLANN_NODISCARD
127#if defined(__has_cpp_attribute) && __has_cpp_attribute(fallthrough)
128#define NANOFLANN_FALLTHROUGH [[fallthrough]]
130#define NANOFLANN_FALLTHROUGH
134#ifndef NANOFLANN_NODE_ALIGNMENT
135#define NANOFLANN_NODE_ALIGNMENT 16
147 return static_cast<T
>(3.14159265358979323846);
154template <
typename T,
typename =
int>
164template <
typename T,
typename =
int>
177template <
typename Container>
178inline typename std::enable_if<has_resize<Container>::value,
void>::type
resize(
179 Container& c,
const size_t nElements)
188template <
typename Container>
189inline typename std::enable_if<!has_resize<Container>::value,
void>::type
resize(
190 Container& c,
const size_t nElements)
192 if (nElements != c.size())
throw std::logic_error(
"Attempt to resize a fixed size container.");
198template <
typename Container,
typename T>
199inline typename std::enable_if<has_assign<Container>::value,
void>::type
assign(
200 Container& c,
const size_t nElements,
const T& value)
202 c.assign(nElements, value);
208template <
typename Container,
typename T>
209inline typename std::enable_if<!has_assign<Container>::value,
void>::type
assign(
210 Container& c,
const size_t nElements,
const T& value)
212 for (
size_t i = 0; i < nElements; i++) c[i] = value;
219 template <
typename PairType>
220 bool operator()(
const PairType& p1,
const PairType& p2)
const
222 return p1.second < p2.second;
234template <
typename IndexType =
size_t,
typename DistanceType =
double>
237 ResultItem() =
default;
238 ResultItem(
const IndexType index,
const DistanceType distance) :
first(index),
second(distance)
252template <
typename DistanceType,
typename IndexType,
typename CountType>
253bool addPointToSortedResultSet(
254 DistanceType* dists, IndexType* indices, CountType& count, CountType capacity,
255 DistanceType dist, IndexType index)
258 for (i = count; i > 0; --i)
260#ifdef NANOFLANN_FIRST_MATCH
261 if ((dists[i - 1] > dist) || ((dist == dists[i - 1]) && (indices[i - 1] > index)))
264 if (dists[i - 1] > dist)
269 dists[i] = dists[i - 1];
270 indices[i] = indices[i - 1];
281 if (count < capacity) count++;
290template <
typename _DistanceType,
typename _IndexType =
size_t,
typename _CountType =
size_t>
294 using DistanceType = _DistanceType;
295 using IndexType = _IndexType;
296 using CountType = _CountType;
305 explicit KNNResultSet(CountType capacity_)
306 : indices(
nullptr), dists(
nullptr), capacity(capacity_), count(0)
310 void init(IndexType* indices_, DistanceType* dists_)
317 NANOFLANN_NODISCARD CountType size()
const noexcept {
return count; }
318 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return count == 0; }
319 NANOFLANN_NODISCARD
bool full()
const noexcept {
return count == capacity; }
328 return detail::addPointToSortedResultSet(dists, indices, count, capacity, dist, index);
333 NANOFLANN_NODISCARD DistanceType
worstDist() const noexcept
335 return (count < capacity || !count) ? std::numeric_limits<DistanceType>::max()
346template <
typename _DistanceType,
typename _IndexType =
size_t,
typename _CountType =
size_t>
350 using DistanceType = _DistanceType;
351 using IndexType = _IndexType;
352 using CountType = _CountType;
359 DistanceType maximumSearchDistanceSquared;
362 explicit RKNNResultSet(CountType capacity_, DistanceType maximumSearchDistanceSquared_)
367 maximumSearchDistanceSquared(maximumSearchDistanceSquared_)
371 void init(IndexType* indices_, DistanceType* dists_)
376 if (capacity) dists[capacity - 1] = maximumSearchDistanceSquared;
379 NANOFLANN_NODISCARD CountType size()
const noexcept {
return count; }
380 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return count == 0; }
381 NANOFLANN_NODISCARD
bool full()
const noexcept {
return count == capacity; }
390 return detail::addPointToSortedResultSet(dists, indices, count, capacity, dist, index);
395 NANOFLANN_NODISCARD DistanceType
worstDist() const noexcept
397 return (count < capacity || !count) ? maximumSearchDistanceSquared : dists[count - 1];
409template <
typename _DistanceType,
typename _IndexType =
size_t>
413 using DistanceType = _DistanceType;
414 using IndexType = _IndexType;
417 const DistanceType radius;
419 std::vector<ResultItem<IndexType, DistanceType>>& m_indices_dists;
421 explicit RadiusResultSet(
423 : radius(radius_), m_indices_dists(indices_dists)
428 void init() { clear(); }
429 void clear() { m_indices_dists.clear(); }
431 NANOFLANN_NODISCARD
size_t size()
const noexcept {
return m_indices_dists.size(); }
432 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return m_indices_dists.empty(); }
433 NANOFLANN_NODISCARD
bool full()
const noexcept {
return true; }
442 if (dist < radius) m_indices_dists.emplace_back(index, dist);
446 NANOFLANN_NODISCARD DistanceType worstDist() const noexcept {
return radius; }
454 if (m_indices_dists.empty())
455 throw std::runtime_error(
456 "Cannot invoke RadiusResultSet::worst_item() on "
457 "an empty list of results.");
459 std::max_element(m_indices_dists.begin(), m_indices_dists.end(),
IndexDist_Sorter());
463 void sort() { std::sort(m_indices_dists.begin(), m_indices_dists.end(),
IndexDist_Sorter()); }
471template <
typename _IndexType =
size_t>
475 using IndexType = _IndexType;
477 std::vector<IndexType>& m_indices;
479 explicit BoxResultSet(std::vector<IndexType>& indices) : m_indices(indices)
484 NANOFLANN_NODISCARD
size_t size()
const noexcept {
return m_indices.size(); }
485 NANOFLANN_NODISCARD
bool empty()
const noexcept {
return m_indices.empty(); }
486 NANOFLANN_NODISCARD
bool full()
const noexcept {
return true; }
490 template <
typename DistanceType>
493 m_indices.push_back(index);
497 void sort() { std::sort(m_indices.begin(), m_indices.end()); }
505void save_value(std::ostream& stream,
const T& value)
507 stream.write(
reinterpret_cast<const char*
>(&value),
sizeof(T));
511void save_value(std::ostream& stream,
const std::vector<T>& value)
513 size_t size = value.size();
514 stream.write(
reinterpret_cast<const char*
>(&size),
sizeof(
size_t));
515 stream.write(
reinterpret_cast<const char*
>(value.data()),
sizeof(T) * size);
519void load_value(std::istream& stream, T& value)
521 stream.read(
reinterpret_cast<char*
>(&value),
sizeof(T));
525void load_value(std::istream& stream, std::vector<T>& value)
528 stream.read(
reinterpret_cast<char*
>(&size),
sizeof(
size_t));
530 stream.read(
reinterpret_cast<char*
>(value.data()),
sizeof(T) * size);
551template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
554 using ElementType = T;
555 using DistanceType = _DistanceType;
557 const DataSource& data_source;
559 L1_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
561 inline DistanceType evalMetric(
562 const T* NANOFLANN_RESTRICT a,
const IndexType b_idx,
size_t size)
const
564 DistanceType result = DistanceType();
565 const size_t multof4 = (size >> 2) << 2;
568 for (d = 0; d < multof4; d += 4)
570 const DistanceType diff0 = std::abs(a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0));
571 const DistanceType diff1 = std::abs(a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1));
572 const DistanceType diff2 = std::abs(a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2));
573 const DistanceType diff3 = std::abs(a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3));
575 result += (diff0 + diff1) + (diff2 + diff3);
579 switch (size - multof4)
582 result += std::abs(a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2));
583 NANOFLANN_FALLTHROUGH;
585 result += std::abs(a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1));
586 NANOFLANN_FALLTHROUGH;
588 result += std::abs(a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0));
589 NANOFLANN_FALLTHROUGH;
596 template <
typename U,
typename V>
597 inline DistanceType accum_dist(
const U a,
const V b,
const size_t)
const
599 return std::abs(a - b);
613template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
616 using ElementType = T;
617 using DistanceType = _DistanceType;
619 const DataSource& data_source;
621 L2_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
623 inline DistanceType evalMetric(
624 const T* NANOFLANN_RESTRICT a,
const IndexType b_idx,
size_t size)
const
626 DistanceType result = DistanceType();
627 const size_t multof4 = (size >> 2) << 2;
630 for (d = 0; d < multof4; d += 4)
632 const DistanceType diff0 = a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0);
633 const DistanceType diff1 = a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1);
634 const DistanceType diff2 = a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2);
635 const DistanceType diff3 = a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3);
637 result += (diff0 * diff0 + diff1 * diff1) + (diff2 * diff2 + diff3 * diff3);
642 switch (size - multof4)
645 diff = a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2);
646 result += diff * diff;
647 NANOFLANN_FALLTHROUGH;
649 diff = a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1);
650 result += diff * diff;
651 NANOFLANN_FALLTHROUGH;
653 diff = a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0);
654 result += diff * diff;
655 NANOFLANN_FALLTHROUGH;
662 template <
typename U,
typename V>
663 inline DistanceType accum_dist(
const U a,
const V b,
const size_t)
const
680template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
681struct L2_Simple_Adaptor
683 using ElementType = T;
684 using DistanceType = _DistanceType;
686 const DataSource& data_source;
688 L2_Simple_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
690 inline DistanceType evalMetric(
const T* a,
const IndexType b_idx,
size_t size)
const
692 DistanceType result = DistanceType();
693 for (
size_t i = 0; i < size; ++i)
695 const DistanceType diff = a[i] - data_source.kdtree_get_pt(b_idx, i);
696 result += diff * diff;
701 template <
typename U,
typename V>
702 inline DistanceType accum_dist(
const U a,
const V b,
const size_t)
const
719template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
722 using ElementType = T;
723 using DistanceType = _DistanceType;
725 const DataSource& data_source;
727 SO2_Adaptor(
const DataSource& _data_source) : data_source(_data_source) {}
729 inline DistanceType evalMetric(
const T* a,
const IndexType b_idx,
size_t size)
const
731 return accum_dist(a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1), size - 1);
739 template <
typename U,
typename V>
740 inline DistanceType
accum_dist(
const U a,
const V b,
const size_t)
const
742 DistanceType diff =
static_cast<DistanceType
>(b) -
static_cast<DistanceType
>(a);
748 return diff < DistanceType(0) ? -diff : diff;
762template <
class T,
class DataSource,
typename _DistanceType = T,
typename IndexType =
size_t>
765 using ElementType = T;
766 using DistanceType = _DistanceType;
770 SO3_Adaptor(
const DataSource& _data_source) : distance_L2_Simple(_data_source) {}
772 inline DistanceType evalMetric(
const T* a,
const IndexType b_idx,
size_t size)
const
774 return distance_L2_Simple.evalMetric(a, b_idx, size);
777 template <
typename U,
typename V>
778 inline DistanceType accum_dist(
const U a,
const V b,
const size_t idx)
const
780 return distance_L2_Simple.accum_dist(a, b, idx);
787 template <
class T,
class DataSource,
typename IndexType =
size_t>
797 template <
class T,
class DataSource,
typename IndexType =
size_t>
807 template <
class T,
class DataSource,
typename IndexType =
size_t>
816 template <
class T,
class DataSource,
typename IndexType =
size_t>
825 template <
class T,
class DataSource,
typename IndexType =
size_t>
837enum class KDTreeSingleIndexAdaptorFlags
840 SkipInitialBuildIndex = 1
843inline std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type operator&(
844 KDTreeSingleIndexAdaptorFlags lhs, KDTreeSingleIndexAdaptorFlags rhs)
846 using underlying =
typename std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type;
847 return static_cast<underlying
>(lhs) &
static_cast<underlying
>(rhs);
852inline bool has_flag(KDTreeSingleIndexAdaptorFlags f, KDTreeSingleIndexAdaptorFlags flag)
854 return (f & flag) != 0;
858struct KDTreeSingleIndexAdaptorParams
860 KDTreeSingleIndexAdaptorParams(
861 size_t _leaf_max_size = 10,
862 KDTreeSingleIndexAdaptorFlags _flags = KDTreeSingleIndexAdaptorFlags::None,
863 unsigned int _n_thread_build = 1)
864 : leaf_max_size(_leaf_max_size), flags(_flags), n_thread_build(_n_thread_build)
868 size_t leaf_max_size;
869 KDTreeSingleIndexAdaptorFlags flags;
870 unsigned int n_thread_build;
874struct SearchParameters
876 SearchParameters(
float eps_ = 0,
bool sorted_ =
true) :
eps(eps_),
sorted(sorted_) {}
903 static constexpr size_t WORDSIZE = 16;
904 static constexpr size_t BLOCKSIZE = 8192;
915 void* base_ =
nullptr;
916 void* loc_ =
nullptr;
928 Size wastedMemory = 0;
943 while (base_ !=
nullptr)
946 void* prev = *(
static_cast<void**
>(base_));
963 const Size size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
968 if (size > remaining_)
970 wastedMemory += remaining_;
973 const Size blocksize = size > BLOCKSIZE ? size + WORDSIZE : BLOCKSIZE + WORDSIZE;
976 void* m = ::malloc(blocksize);
979 throw std::bad_alloc();
983 static_cast<void**
>(m)[0] = base_;
986 remaining_ = blocksize - WORDSIZE;
987 loc_ =
static_cast<char*
>(m) + WORDSIZE;
990 loc_ =
static_cast<char*
>(loc_) + size;
1005 template <
typename T>
1008 T* mem =
static_cast<T*
>(this->
allocateBytes(
sizeof(T) * count));
1020template <
int32_t DIM,
typename T>
1023 using type = std::array<T, DIM>;
1026template <
typename T>
1029 using type = std::vector<T>;
1049 class Derived,
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
1050 typename index_t = uint32_t>
1058 obj.pool_.free_all();
1059 obj.root_node_ =
nullptr;
1060 obj.size_at_index_build_ = 0;
1063 using ElementType =
typename Distance::ElementType;
1064 using DistanceType =
typename Distance::DistanceType;
1065 using IndexType = index_t;
1072 using Offset =
typename decltype(
vAcc_)::size_type;
1073 using Size =
typename decltype(
vAcc_)::size_type;
1074 using Dimension = int32_t;
1088 struct alignas(NANOFLANN_NODE_ALIGNMENT)
Node
1102 DistanceType divlow, divhigh;
1110 using NodePtr =
Node*;
1111 using NodeConstPtr =
const Node*;
1115 ElementType low, high;
1118 NodePtr root_node_ =
nullptr;
1120 Size leaf_max_size_ = 0;
1151 NANOFLANN_NODISCARD Size
size(
const Derived& obj)
const noexcept {
return obj.size_; }
1157 NANOFLANN_NODISCARD Size
veclen(
const Derived& obj)
const noexcept
1159#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
1160 if constexpr (DIM > 0)
1169 return DIM > 0 ? DIM : obj.dim_;
1174 ElementType
dataset_get(
const Derived& obj, IndexType element, Dimension component)
const
1176 return obj.dataset_.kdtree_get_pt(element, component);
1185 return obj.pool_.usedMemory + obj.pool_.wastedMemory +
1186 obj.dataset_.kdtree_get_point_count() *
1194 const Derived& obj, Offset ind, Size count, Dimension element, ElementType& min_elem,
1195 ElementType& max_elem)
const
1198 max_elem = min_elem;
1199 for (Offset i = 1; i < count; ++i)
1202 if (val < min_elem) min_elem = val;
1203 if (val > max_elem) max_elem = val;
1210 NANOFLANN_NODISCARD
bool isActive(IndexType )
const {
return true; }
1217 Derived& obj =
static_cast<Derived&
>(*this);
1218 const Dimension dims =
static_cast<Dimension
>(
veclen(obj));
1220 if (obj.dataset_.kdtree_get_bbox(bbox))
return;
1222 throw std::runtime_error(
1223 "[nanoflann] computeBoundingBox() called but "
1224 "no data points found.");
1225 for (Dimension i = 0; i < dims; ++i)
1227 for (Offset k = 1; k <
size_; ++k)
1228 for (Dimension i = 0; i < dims; ++i)
1231 if (val < bbox[i].low) bbox[i].low = val;
1232 if (val > bbox[i].high) bbox[i].high = val;
1244 template <
class RESULTSET>
1246 RESULTSET& result_set,
const ElementType* vec,
const NodePtr node, DistanceType mindist,
1249 const Derived& obj =
static_cast<const Derived&
>(*this);
1256 const Size dim =
veclen(obj);
1257 for (Offset i = node->
node_type.lr.left; i < node->node_type.lr.right; ++i)
1259 const IndexType accessor =
vAcc_[i];
1260 if (!obj.isActive(accessor))
continue;
1261 DistanceType dist = obj.distance_.evalMetric(vec, accessor, dim);
1262 if (dist < result_set.worstDist())
1264 if (!result_set.addPoint(
1265 static_cast<typename RESULTSET::DistanceType
>(dist),
1266 static_cast<typename RESULTSET::IndexType
>(accessor)))
1274 Dimension idx = node->
node_type.sub.divfeat;
1275 ElementType val = vec[idx];
1276 DistanceType diff1 = val - node->
node_type.sub.divlow;
1277 DistanceType diff2 = val - node->
node_type.sub.divhigh;
1281 DistanceType cut_dist;
1282 if ((diff1 + diff2) < 0)
1284 bestChild = node->
child1;
1285 otherChild = node->child2;
1286 cut_dist = obj.distance_.accum_dist(val, node->
node_type.sub.divhigh, idx);
1290 bestChild = node->child2;
1291 otherChild = node->
child1;
1292 cut_dist = obj.distance_.accum_dist(val, node->
node_type.sub.divlow, idx);
1296 if (!
searchLevel(result_set, vec, bestChild, mindist, dists, epsError))
return false;
1298 DistanceType dst = dists[idx];
1299 mindist = mindist + cut_dist - dst;
1300 dists[idx] = cut_dist;
1301 if (mindist * epsError <= result_set.worstDist())
1303 if (!
searchLevel(result_set, vec, otherChild, mindist, dists, epsError))
return false;
1329 Derived& obj, NodePtr node,
const Offset left,
const Offset right,
BoundingBox& bbox,
1330 Offset& idx, Dimension& cutfeat, DistanceType& cutval)
1332 const Dimension dims =
static_cast<Dimension
>(
veclen(obj));
1335 if ((right - left) <=
static_cast<Offset
>(obj.leaf_max_size_))
1337 node->
child1 = node->child2 =
nullptr;
1342 for (Dimension i = 0; i < dims; ++i)
1344 bbox[i].low =
dataset_get(obj, obj.vAcc_[left], i);
1345 bbox[i].high =
dataset_get(obj, obj.vAcc_[left], i);
1347 for (Offset k = left + 1; k < right; ++k)
1349 for (Dimension i = 0; i < dims; ++i)
1351 const auto val =
dataset_get(obj, obj.vAcc_[k], i);
1352 if (bbox[i].low > val) bbox[i].low = val;
1353 if (bbox[i].high < val) bbox[i].high = val;
1360 middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox);
1371 Derived& obj, NodePtr node,
const Dimension cutfeat,
const BoundingBox& left_bbox,
1374 node->
node_type.sub.divlow = left_bbox[cutfeat].high;
1375 node->
node_type.sub.divhigh = right_bbox[cutfeat].low;
1377 const Dimension dims =
static_cast<Dimension
>(
veclen(obj));
1378 for (Dimension i = 0; i < dims; ++i)
1380 bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
1381 bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
1385 NodePtr divideTree(Derived& obj,
const Offset left,
const Offset right, BoundingBox& bbox)
1387 assert(
static_cast<Size
>(obj.vAcc_.at(left)) < obj.dataset_.kdtree_get_point_count());
1389 NodePtr node = obj.pool_.template allocate<Node>();
1392 DistanceType cutval;
1393 if (makeNode(obj, node, left, right, bbox, idx, cutfeat, cutval))
return node;
1396 BoundingBox left_bbox(bbox);
1397 left_bbox[cutfeat].high = cutval;
1398 node->child1 = this->divideTree(obj, left, left + idx, left_bbox);
1401 BoundingBox right_bbox(bbox);
1402 right_bbox[cutfeat].low = cutval;
1403 node->child2 = this->divideTree(obj, left + idx, right, right_bbox);
1405 finalizeSplitNode(obj, node, cutfeat, left_bbox, right_bbox, bbox);
1423 Derived& obj,
const Offset left,
const Offset right,
BoundingBox& bbox,
1424 std::atomic<unsigned int>& thread_count, std::mutex& mutex)
1426 std::unique_lock<std::mutex> lock(mutex);
1427 NodePtr node = obj.pool_.template allocate<Node>();
1432 DistanceType cutval;
1433 if (
makeNode(obj, node, left, right, bbox, idx, cutfeat, cutval))
return node;
1435 std::future<NodePtr> right_future;
1440 right_bbox[cutfeat].low = cutval;
1445 right_future = std::async(
1447 left + idx, right, std::ref(right_bbox), std::ref(thread_count), std::ref(mutex));
1457 left_bbox[cutfeat].high = cutval;
1461 if (right_future.valid())
1465 node->child2 = right_future.get();
1482 const Derived& obj,
const Offset ind,
const Size count, Offset& index, Dimension& cutfeat,
1483 DistanceType& cutval,
const BoundingBox& bbox)
1485 const Dimension dims =
static_cast<Dimension
>(veclen(obj));
1486 const auto EPS =
static_cast<DistanceType
>(0.00001);
1489 ElementType max_span = bbox[0].high - bbox[0].low;
1490 for (Dimension i = 1; i < dims; ++i)
1492 ElementType span = bbox[i].high - bbox[i].low;
1493 if (span > max_span) max_span = span;
1499 ElementType max_spread = -1;
1500 ElementType min_elem = 0, max_elem = 0;
1501 const ElementType threshold = (1 - EPS) * max_span;
1503 for (Dimension dim = 0; dim < dims; ++dim)
1505 if (bbox[dim].high - bbox[dim].low < threshold)
continue;
1507 ElementType local_min = dataset_get(obj, vAcc_[ind], dim);
1508 ElementType local_max = local_min;
1511 constexpr size_t UNROLL = 4;
1513 for (; k + UNROLL <= count; k += UNROLL)
1515 ElementType v0 = dataset_get(obj, vAcc_[ind + k], dim);
1516 ElementType v1 = dataset_get(obj, vAcc_[ind + k + 1], dim);
1517 ElementType v2 = dataset_get(obj, vAcc_[ind + k + 2], dim);
1518 ElementType v3 = dataset_get(obj, vAcc_[ind + k + 3], dim);
1520 local_min = std::min({local_min, v0, v1, v2, v3});
1521 local_max = std::max({local_max, v0, v1, v2, v3});
1525 for (; k < count; ++k)
1527 ElementType val = dataset_get(obj, vAcc_[ind + k], dim);
1528 local_min = std::min(local_min, val);
1529 local_max = std::max(local_max, val);
1532 ElementType spread = local_max - local_min;
1533 if (spread > max_spread)
1536 max_spread = spread;
1537 min_elem = local_min;
1538 max_elem = local_max;
1543 DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2;
1544 if (split_val < min_elem) split_val = min_elem;
1545 if (split_val > max_elem) split_val = max_elem;
1551 planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2);
1553 index = (lim1 > count / 2) ? lim1 : (lim2 < count / 2) ? lim2 : count / 2;
1566 const Derived& obj,
const Offset ind,
const Size count,
const Dimension cutfeat,
1567 const DistanceType& cutval, Offset& lim1, Offset& lim2)
1572 Offset right = count - 1;
1574 while (mid <= right)
1580 std::swap(
vAcc_[ind + left],
vAcc_[ind + mid]);
1584 else if (val > cutval)
1586 std::swap(
vAcc_[ind + mid],
vAcc_[ind + right]);
1599 DistanceType computeInitialDistances(
1600 const Derived& obj,
const ElementType* vec, distance_vector_t& dists)
const
1603 DistanceType dist = DistanceType();
1605 const Dimension dims =
static_cast<Dimension
>(veclen(obj));
1606 for (Dimension i = 0; i < dims; ++i)
1608 if (vec[i] < obj.root_bbox_[i].low)
1610 dists[i] = obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].low, i);
1613 else if (vec[i] > obj.root_bbox_[i].high)
1615 dists[i] = obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].high, i);
1622 static void save_tree(
const Derived& obj, std::ostream& stream,
const NodeConstPtr tree)
1624 save_value(stream, *tree);
1625 if (tree->child1 !=
nullptr)
1627 save_tree(obj, stream, tree->child1);
1629 if (tree->child2 !=
nullptr)
1631 save_tree(obj, stream, tree->child2);
1635 static void load_tree(Derived& obj, std::istream& stream, NodePtr& tree)
1637 tree = obj.pool_.template allocate<Node>();
1638 load_value(stream, *tree);
1639 if (tree->child1 !=
nullptr)
1641 load_tree(obj, stream, tree->child1);
1643 if (tree->child2 !=
nullptr)
1645 load_tree(obj, stream, tree->child2);
1671 void saveIndex(
const Derived& obj, std::ostream& stream)
const
1679 const uint32_t hdr_version =
static_cast<uint32_t
>(NANOFLANN_VERSION);
1680 const uint8_t hdr_sz_st =
static_cast<uint8_t
>(
sizeof(size_t));
1681 const uint8_t hdr_sz_idx =
static_cast<uint8_t
>(
sizeof(IndexType));
1682 const uint8_t hdr_sz_elem =
static_cast<uint8_t
>(
sizeof(ElementType));
1683 const uint8_t hdr_sz_dist =
static_cast<uint8_t
>(
sizeof(DistanceType));
1684 save_value(stream, hdr_magic);
1685 save_value(stream, hdr_version);
1686 save_value(stream, hdr_sz_st);
1687 save_value(stream, hdr_sz_idx);
1688 save_value(stream, hdr_sz_elem);
1689 save_value(stream, hdr_sz_dist);
1691 save_value(stream, obj.size_);
1692 save_value(stream, obj.dim_);
1693 save_value(stream, obj.root_bbox_);
1694 save_value(stream, obj.leaf_max_size_);
1695 save_value(stream, obj.vAcc_);
1698 save_tree(obj, stream, obj.root_node_);
1721 load_value(stream, magic);
1724 throw std::runtime_error(
1725 "nanoflann loadIndex: invalid file (wrong magic number). "
1726 "The stream was not written by nanoflann saveIndex().");
1729 uint32_t file_version = 0;
1730 load_value(stream, file_version);
1731 if (file_version !=
static_cast<uint32_t
>(NANOFLANN_VERSION))
1736 "nanoflann loadIndex: version mismatch "
1737 "(file=0x%03X, library=0x%03X). Rebuild the index.",
1738 file_version,
static_cast<unsigned>(NANOFLANN_VERSION));
1739 throw std::runtime_error(msg);
1742 uint8_t sz_size_t = 0;
1744 uint8_t sz_elem = 0;
1745 uint8_t sz_dist = 0;
1746 load_value(stream, sz_size_t);
1747 load_value(stream, sz_idx);
1748 load_value(stream, sz_elem);
1749 load_value(stream, sz_dist);
1750 if (sz_size_t !=
static_cast<uint8_t
>(
sizeof(
size_t)) ||
1751 sz_idx !=
static_cast<uint8_t
>(
sizeof(IndexType)) ||
1752 sz_elem !=
static_cast<uint8_t
>(
sizeof(ElementType)) ||
1753 sz_dist !=
static_cast<uint8_t
>(
sizeof(DistanceType)))
1755 throw std::runtime_error(
1756 "nanoflann loadIndex: type-size mismatch between saved index and "
1757 "current template instantiation (sizeof size_t / IndexType / "
1758 "ElementType / DistanceType differ). Rebuild the index.");
1761 load_value(stream, obj.size_);
1762 load_value(stream, obj.dim_);
1763 load_value(stream, obj.root_bbox_);
1764 load_value(stream, obj.leaf_max_size_);
1765 load_value(stream, obj.vAcc_);
1769 load_tree(obj, stream, obj.root_node_);
1774 throw std::runtime_error(
1775 "nanoflann loadIndex: unexpected end of stream or read error.");
1833template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename index_t = uint32_t>
1836 KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, index_t>, Distance,
1837 DatasetAdaptor, DIM, index_t>
1853 DatasetAdaptor, DIM, index_t>;
1855 using Offset =
typename Base::Offset;
1856 using Size =
typename Base::Size;
1857 using Dimension =
typename Base::Dimension;
1859 using ElementType =
typename Base::ElementType;
1860 using DistanceType =
typename Base::DistanceType;
1861 using IndexType =
typename Base::IndexType;
1863 using Node =
typename Base::Node;
1864 using NodePtr = Node*;
1866 using Interval =
typename Base::Interval;
1896 template <
class... Args>
1898 const Dimension dimensionality,
const DatasetAdaptor& inputData,
1901 indexParams(params),
1902 distance_(inputData, std::forward<Args>(args)...)
1904 init(dimensionality, params);
1908 const Dimension dimensionality,
const DatasetAdaptor& inputData,
1910 : dataset_(inputData), indexParams(params), distance_(inputData)
1912 init(dimensionality, params);
1916 void init(
const Dimension dimensionality,
const KDTreeSingleIndexAdaptorParams& params)
1918 Base::size_ = dataset_.kdtree_get_point_count();
1919 Base::size_at_index_build_ = Base::size_;
1920 Base::dim_ = dimensionality;
1921 if (DIM > 0) Base::dim_ = DIM;
1922 Base::leaf_max_size_ = params.leaf_max_size;
1923 if (params.n_thread_build > 0)
1925 Base::n_thread_build_ = params.n_thread_build;
1929 Base::n_thread_build_ = std::max(std::thread::hardware_concurrency(), 1u);
1932 if (!
has_flag(params.flags, KDTreeSingleIndexAdaptorFlags::SkipInitialBuildIndex))
1945 Base::size_ =
dataset_.kdtree_get_point_count();
1946 Base::size_at_index_build_ = Base::size_;
1949 Base::size_at_index_build_ = Base::size_;
1950 if (Base::size_ == 0)
return;
1953 if (Base::n_thread_build_ == 1)
1955 Base::root_node_ = this->divideTree(*
this, 0, Base::size_, Base::root_bbox_);
1959#ifndef NANOFLANN_NO_THREADS
1960 std::atomic<unsigned int> thread_count(0u);
1963 *
this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
1965 throw std::runtime_error(
"Multithreading is disabled");
1989 template <
typename RESULTSET>
1991 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
1994 if (this->size(*
this) == 0)
return false;
1995 if (!Base::root_node_)
1996 throw std::runtime_error(
1997 "[nanoflann] findNeighbors() called before building the "
1999 DistanceType epsError = 1 +
static_cast<DistanceType
>(searchParams.eps);
2002 distance_vector_t dists;
2004 auto zero =
static_cast<typename RESULTSET::DistanceType
>(0);
2005 assign(dists, this->veclen(*
this), zero);
2006 DistanceType dist = this->computeInitialDistances(*
this, vec, dists);
2007 this->searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
2009 if (searchParams.sorted) result.sort();
2011 return result.full();
2029 template <
typename RESULTSET>
2032 if (this->size(*
this) == 0)
return 0;
2033 if (!Base::root_node_)
2034 throw std::runtime_error(
2035 "[nanoflann] findWithinBox() called before building the "
2038 std::stack<NodePtr> stack;
2039 stack.push(Base::root_node_);
2041 while (!stack.empty())
2043 const NodePtr node = stack.top();
2049 for (Offset i = node->node_type.lr.left; i < node->node_type.lr.right; ++i)
2051 if (contains(bbox, Base::vAcc_[i]))
2053 if (!result.addPoint(0, Base::vAcc_[i]))
2057 return result.size();
2064 const Dimension idx = node->node_type.sub.divfeat;
2065 const auto low_bound = node->node_type.sub.divlow;
2066 const auto high_bound = node->node_type.sub.divhigh;
2068 if (bbox[idx].low <= low_bound) stack.push(node->child1);
2069 if (bbox[idx].high >= high_bound) stack.push(node->child2);
2073 return result.size();
2092 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
2093 DistanceType* out_distances)
const
2096 resultSet.init(out_indices, out_distances);
2098 return resultSet.size();
2121 const ElementType* query_point,
const DistanceType& radius,
2126 const Size nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);
2135 template <
class SEARCH_CALLBACK>
2137 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
2140 findNeighbors(resultSet, query_point, searchParams);
2141 return resultSet.size();
2160 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
2161 DistanceType* out_distances,
const DistanceType& radius)
const
2164 resultSet.init(out_indices, out_distances);
2166 return resultSet.size();
2177 Base::size_ =
dataset_.kdtree_get_point_count();
2178 if (Base::vAcc_.
size() != Base::size_) Base::vAcc_.resize(Base::size_);
2179 for (IndexType i = 0; i < static_cast<IndexType>(Base::size_); i++) Base::vAcc_[i] = i;
2182 bool contains(
const BoundingBox& bbox, IndexType idx)
const
2184 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
2185 for (Dimension i = 0; i < dims; ++i)
2187 const auto point = this->dataset_.kdtree_get_pt(idx, i);
2188 if (point < bbox[i].low || point > bbox[i].high)
return false;
2199 void saveIndex(std::ostream& stream)
const { Base::saveIndex(*
this, stream); }
2206 void loadIndex(std::istream& stream) { Base::loadIndex(*
this, stream); }
2247template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
2250 KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>, Distance,
2251 DatasetAdaptor, DIM, IndexType>
2261 std::vector<int>& treeIndex_;
2267 Distance, DatasetAdaptor, DIM, IndexType>;
2269 using ElementType =
typename Base::ElementType;
2270 using DistanceType =
typename Base::DistanceType;
2272 using Offset =
typename Base::Offset;
2273 using Size =
typename Base::Size;
2274 using Dimension =
typename Base::Dimension;
2276 using Node =
typename Base::Node;
2277 using NodePtr = Node*;
2279 using Interval =
typename Base::Interval;
2289 NANOFLANN_NODISCARD
bool isActive(IndexType idx)
const {
return treeIndex_[idx] != -1; }
2307 const Dimension dimensionality,
const DatasetAdaptor& inputData,
2308 std::vector<int>& treeIndex,
2310 :
dataset_(inputData), index_params_(params), treeIndex_(treeIndex), distance_(inputData)
2313 Base::size_at_index_build_ = 0;
2314 for (
auto& v : Base::root_bbox_) v = {};
2315 Base::dim_ = dimensionality;
2316 if (DIM > 0) Base::dim_ = DIM;
2317 Base::leaf_max_size_ = params.leaf_max_size;
2318 if (params.n_thread_build > 0)
2320 Base::n_thread_build_ = params.n_thread_build;
2324 Base::n_thread_build_ = std::max(std::thread::hardware_concurrency(), 1u);
2334 if (
this == &rhs)
return *
this;
2336 std::swap(Base::vAcc_, tmp.Base::vAcc_);
2337 std::swap(Base::leaf_max_size_, tmp.Base::leaf_max_size_);
2338 std::swap(index_params_, tmp.index_params_);
2340 std::swap(Base::size_, tmp.Base::size_);
2341 std::swap(Base::size_at_index_build_, tmp.Base::size_at_index_build_);
2342 std::swap(Base::root_node_, tmp.Base::root_node_);
2343 std::swap(Base::root_bbox_, tmp.Base::root_bbox_);
2344 std::swap(Base::pool_, tmp.Base::pool_);
2353 Base::size_ = Base::vAcc_.size();
2355 Base::size_at_index_build_ = Base::size_;
2356 if (Base::size_ == 0)
return;
2359 if (Base::n_thread_build_ == 1)
2361 Base::root_node_ = this->divideTree(*
this, 0, Base::size_, Base::root_bbox_);
2365#ifndef NANOFLANN_NO_THREADS
2366 std::atomic<unsigned int> thread_count(0u);
2369 *
this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
2371 throw std::runtime_error(
"Multithreading is disabled");
2399 template <
typename RESULTSET>
2401 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
2404 if (this->size(*
this) == 0)
return false;
2405 if (!Base::root_node_)
return false;
2406 DistanceType epsError = 1 +
static_cast<DistanceType
>(searchParams.eps);
2409 distance_vector_t dists;
2411 assign(dists, this->veclen(*
this),
static_cast<typename distance_vector_t::value_type
>(0));
2412 DistanceType dist = this->computeInitialDistances(*
this, vec, dists);
2413 this->searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
2415 if (searchParams.sorted) result.sort();
2417 return result.full();
2435 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
2436 DistanceType* out_distances,
const SearchParameters& searchParams = {})
const
2439 resultSet.init(out_indices, out_distances);
2440 findNeighbors(resultSet, query_point, searchParams);
2441 return resultSet.size();
2464 const ElementType* query_point,
const DistanceType& radius,
2469 const Size nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);
2478 template <
class SEARCH_CALLBACK>
2480 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
2483 findNeighbors(resultSet, query_point, searchParams);
2484 return resultSet.size();
2496 void saveIndex(std::ostream& stream) { Base::saveIndex(*
this, stream); }
2503 void loadIndex(std::istream& stream) { Base::loadIndex(*
this, stream); }
2520template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
2524 using ElementType =
typename Distance::ElementType;
2525 using DistanceType =
typename Distance::DistanceType;
2527 using Offset =
typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Offset;
2528 using Size =
typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Size;
2530 typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Dimension;
2533 Size leaf_max_size_;
2554 using index_container_t =
2556 std::vector<index_container_t> index_;
2565 int First0Bit(Size num)
2579 using my_kd_tree_t =
2580 KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>;
2581 std::vector<my_kd_tree_t> index(
2582 treeCount_, my_kd_tree_t(dim_ , dataset_, treeIndex_, index_params_));
2605 const int dimensionality,
const DatasetAdaptor& inputData,
2607 const size_t maximumPointCount = 1000000000U)
2608 :
dataset_(inputData), index_params_(params), distance_(inputData)
2610 treeCount_ =
static_cast<size_t>(std::log2(maximumPointCount)) + 1;
2612 dim_ = dimensionality;
2614 if (DIM > 0)
dim_ = DIM;
2615 leaf_max_size_ = params.leaf_max_size;
2617 const size_t num_initial_points =
dataset_.kdtree_get_point_count();
2618 if (num_initial_points > 0)
2620 addPoints(0,
static_cast<IndexType
>(num_initial_points - 1));
2632 for (IndexType idx = start; idx <= end; idx++)
2647 const int pos = First0Bit(pointCount_);
2648 maxIndex = std::max(pos, maxIndex);
2649 if (
treeIndex_.size() <=
static_cast<size_t>(pointCount_))
2650 treeIndex_.resize(
static_cast<size_t>(pointCount_) + 1);
2653 for (
int i = 0; i < pos; i++)
2655 for (
size_t j = 0; j < index_[i].vAcc_.size(); j++)
2657 const IndexType e = index_[i].
vAcc_[j];
2658 index_[pos].vAcc_.push_back(e);
2664 index_[i].vAcc_.clear();
2666 index_[pos].vAcc_.push_back(idx);
2670 for (
int i = 0; i <= maxIndex; ++i)
2672 index_[i].freeIndex(index_[i]);
2673 if (!index_[i].vAcc_.empty()) index_[i].buildIndex();
2680 if (idx >= pointCount_)
return;
2704 template <
typename RESULTSET>
2706 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
2708 for (
size_t i = 0; i < treeCount_; i++)
2710 index_[i].findNeighbors(result, &vec[0], searchParams);
2712 return result.full();
2728struct KDTreeIncrementalIndexParams
2730 KDTreeIncrementalIndexParams(
float alpha_balance_ = 0.75f,
float alpha_deleted_ = 0.5f)
2731 : alpha_balance(alpha_balance_), alpha_deleted(alpha_deleted_)
2735 float alpha_balance;
2736 float alpha_deleted;
2773template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
2776 KDTreeSingleIndexIncrementalAdaptor<Distance, DatasetAdaptor, DIM, IndexType>, Distance,
2777 DatasetAdaptor, DIM, IndexType>
2782 DatasetAdaptor, DIM, IndexType>;
2784 using ElementType =
typename Base::ElementType;
2785 using DistanceType =
typename Base::DistanceType;
2787 using Offset =
typename Base::Offset;
2788 using Size =
typename Base::Size;
2789 using Dimension =
typename Base::Dimension;
2791 using Interval =
typename Base::Interval;
2792 using BoundingBox =
typename Base::BoundingBox;
2793 using distance_vector_t =
typename Base::distance_vector_t;
2818 typename array_or_vector<DIM, ElementType>::type pcoord;
2825#if defined(NANOFLANN_INCREMENTAL_NO_COORD_CACHE)
2832 INode* iroot_ =
nullptr;
2833 INode* freeList_ =
nullptr;
2835 Size liveCount_ = 0;
2836 Size totalCount_ = 0;
2838 float alphaBal_ = 0.75f;
2839 float alphaDel_ = 0.5f;
2841 static constexpr Size kMinBalanceRebuild = 4;
2844 static constexpr double kBulkInsertFraction = 0.5;
2847 INode* pendingRebuild_ =
nullptr;
2853 bool inlineRebuild_ =
true;
2856 std::vector<INode*> nodeOfPoint_;
2859 std::vector<IndexType> buildBuf_;
2862 bool collectRemoved_ =
false;
2863 std::vector<IndexType> removedSink_;
2875 const Dimension dimensionality,
const DatasetAdaptor& inputData,
2877 : dataset_(inputData), distance_(inputData)
2879 Base::dim_ = dimensionality;
2880 if (DIM > 0) Base::dim_ = DIM;
2881 alphaBal_ = params.alpha_balance;
2882 alphaDel_ = params.alpha_deleted;
2883 resize(Base::root_bbox_,
static_cast<Dimension
>(this->veclen(*
this)));
2914 if (end < start)
return;
2916 const Size batch =
static_cast<Size
>(end - start) + 1;
2918 static_cast<double>(batch) >= kBulkInsertFraction *
static_cast<double>(liveCount_))
2921 if (iroot_) collectLiveAndFree(iroot_, buildBuf_);
2922 for (IndexType idx = start; idx <= end; ++idx) buildBuf_.push_back(idx);
2923 iroot_ = buildBalanced(buildBuf_, 0, buildBuf_.size(), 0,
nullptr);
2924 liveCount_ = buildBuf_.size();
2925 totalCount_ = liveCount_;
2929 for (IndexType idx = start; idx <= end; ++idx) insertOne(idx);
2937 if (idx >= nodeOfPoint_.size())
return;
2938 INode* n = nodeOfPoint_[idx];
2939 if (!n || n->deleted)
return;
2942 for (INode* p = n->parent; p; p = p->parent)
2943 if (p->treeDeleted)
return;
2946 for (INode* p = n; p; p = p->parent) ++p->invalid_count;
2948 maybeRebuildForDeletion();
2955 if (iroot_) removeBoxRec(iroot_, box);
2956 maybeRebuildForDeletion();
2964 if (iroot_) removeOutsideBoxRec(iroot_, keep);
2965 maybeRebuildForDeletion();
2973 collectRemoved_ = enable;
2974 if (!enable) std::vector<IndexType>().swap(removedSink_);
2981 std::vector<IndexType> out;
2982 out.swap(removedSink_);
3004 return idx < nodeOfPoint_.size() && nodeOfPoint_[idx] !=
nullptr;
3013 IndexType maxIdx = 0;
3014 for (IndexType v : idxs) maxIdx = std::max(maxIdx, v);
3015 if (!idxs.empty()) ensureNodeMap(maxIdx);
3020 collectLiveAndFree(iroot_, buildBuf_);
3023 buildBuf_.assign(idxs.begin(), idxs.end());
3024 iroot_ = buildBalanced(buildBuf_, 0, buildBuf_.size(), 0,
nullptr);
3025 liveCount_ = buildBuf_.size();
3026 totalCount_ = liveCount_;
3036 NANOFLANN_NODISCARD Size
size() const noexcept {
return liveCount_; }
3037 NANOFLANN_NODISCARD
bool empty() const noexcept {
return liveCount_ == 0; }
3040 NANOFLANN_NODISCARD Size
physicalSize() const noexcept {
return totalCount_; }
3045 return Base::pool_.usedMemory + Base::pool_.wastedMemory +
3046 nodeOfPoint_.capacity() *
sizeof(INode*);
3052 NANOFLANN_NODISCARD BoundingBox
boundingBox()
const {
return Base::root_bbox_; }
3058 nodeOfPoint_.reserve(n);
3059 buildBuf_.reserve(n);
3068 template <
typename RESULTSET>
3070 RESULTSET& result,
const ElementType* vec,
const SearchParameters& searchParams = {})
const
3073 if (!iroot_ || liveCount_ == 0)
return false;
3074 const DistanceType epsError = 1 +
static_cast<DistanceType
>(searchParams.eps);
3076 distance_vector_t dists;
3077 assign(dists, this->veclen(*
this),
static_cast<typename distance_vector_t::value_type
>(0));
3078 const DistanceType dist = this->computeInitialDistances(*
this, vec, dists);
3079 searchLevelInc(result, vec, iroot_, dist, dists, epsError, this->veclen(*
this));
3080 if (searchParams.sorted) result.sort();
3081 return result.full();
3086 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
3087 DistanceType* out_distances,
const SearchParameters& searchParams = {})
const
3090 resultSet.init(out_indices, out_distances);
3091 findNeighbors(resultSet, query_point, searchParams);
3092 return resultSet.size();
3097 const ElementType* query_point,
const DistanceType& radius,
3102 findNeighbors(resultSet, query_point, searchParams);
3103 return resultSet.size();
3107 template <
class SEARCH_CALLBACK>
3109 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
3112 findNeighbors(resultSet, query_point, searchParams);
3113 return resultSet.size();
3118 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
3119 DistanceType* out_distances,
const DistanceType& radius)
const
3122 resultSet.init(out_indices, out_distances);
3124 return resultSet.size();
3128 template <
typename RESULTSET>
3129 NANOFLANN_NODISCARD Size
findWithinBox(RESULTSET& result,
const BoundingBox& bbox)
const
3131 if (iroot_) findWithinBoxRec(result, iroot_, bbox);
3132 return result.size();
3169 const uint32_t hdr_version =
static_cast<uint32_t
>(NANOFLANN_VERSION);
3170 const uint8_t hdr_sz_st =
static_cast<uint8_t
>(
sizeof(size_t));
3171 const uint8_t hdr_sz_idx =
static_cast<uint8_t
>(
sizeof(IndexType));
3172 const uint8_t hdr_sz_elem =
static_cast<uint8_t
>(
sizeof(ElementType));
3173 const uint8_t hdr_sz_dist =
static_cast<uint8_t
>(
sizeof(DistanceType));
3174 save_value(stream, hdr_magic);
3175 save_value(stream, hdr_version);
3176 save_value(stream, hdr_sz_st);
3177 save_value(stream, hdr_sz_idx);
3178 save_value(stream, hdr_sz_elem);
3179 save_value(stream, hdr_sz_dist);
3181 const Dimension dims =
static_cast<Dimension
>(this->
veclen(*
this));
3182 save_value(stream, dims);
3184 const uint8_t hasRoot = iroot_ ? 1 : 0;
3185 save_value(stream, hasRoot);
3186 if (iroot_) saveNode(stream, iroot_);
3205 load_value(stream, magic);
3208 throw std::runtime_error(
3209 "KDTreeSingleIndexIncrementalAdaptor::loadIndex: invalid file (wrong magic "
3210 "number). The stream was not written by this class' saveIndex(), or was written "
3211 "by the static KDTreeSingleIndexAdaptor instead.");
3214 uint32_t file_version = 0;
3215 load_value(stream, file_version);
3216 if (file_version !=
static_cast<uint32_t
>(NANOFLANN_VERSION))
3221 "KDTreeSingleIndexIncrementalAdaptor::loadIndex: version mismatch "
3222 "(file=0x%03X, library=0x%03X). Rebuild the index.",
3223 file_version,
static_cast<unsigned>(NANOFLANN_VERSION));
3224 throw std::runtime_error(msg);
3227 uint8_t sz_size_t = 0;
3229 uint8_t sz_elem = 0;
3230 uint8_t sz_dist = 0;
3231 load_value(stream, sz_size_t);
3232 load_value(stream, sz_idx);
3233 load_value(stream, sz_elem);
3234 load_value(stream, sz_dist);
3235 if (sz_size_t !=
static_cast<uint8_t
>(
sizeof(
size_t)) ||
3236 sz_idx !=
static_cast<uint8_t
>(
sizeof(IndexType)) ||
3237 sz_elem !=
static_cast<uint8_t
>(
sizeof(ElementType)) ||
3238 sz_dist !=
static_cast<uint8_t
>(
sizeof(DistanceType)))
3240 throw std::runtime_error(
3241 "KDTreeSingleIndexIncrementalAdaptor::loadIndex: type-size mismatch between "
3242 "saved index and current template instantiation (sizeof size_t / IndexType / "
3243 "ElementType / DistanceType differ). Rebuild the index.");
3247 load_value(stream, dims);
3248 if (dims !=
static_cast<Dimension
>(this->
veclen(*
this)))
3250 throw std::runtime_error(
3251 "KDTreeSingleIndexIncrementalAdaptor::loadIndex: dimensionality mismatch "
3252 "between the saved index and this object's dataset.");
3255 uint8_t hasRoot = 0;
3256 load_value(stream, hasRoot);
3257 iroot_ = hasRoot ? loadNode(stream,
nullptr) :
nullptr;
3261 throw std::runtime_error(
3262 "KDTreeSingleIndexIncrementalAdaptor::loadIndex: unexpected end of stream or "
3266 totalCount_ = iroot_ ? iroot_->subtree_size : 0;
3267 liveCount_ = iroot_ ? iroot_->subtree_size - iroot_->invalid_count : 0;
3281 INode* n = freeList_;
3282 freeList_ = n->child1;
3285 INode* n = Base::pool_.template allocate<INode>();
3287 ::new (
static_cast<void*
>(n)) INode();
3288 resize(n->box,
static_cast<Dimension
>(this->veclen(*
this)));
3289 if (kCacheCoords) resize(n->pcoord,
static_cast<Dimension
>(this->veclen(*
this)));
3294 void cacheCoords(INode* n)
3296 if (!kCacheCoords)
return;
3297 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3298 for (Dimension i = 0; i < dims; ++i) n->pcoord[i] = pt(n->ptIdx, i);
3302 ElementType nodeCoord(
const INode* n, Dimension d)
const
3304 return kCacheCoords ? n->pcoord[d] : pt(n->ptIdx, d);
3308 bool nodeInBox(
const INode* n,
const BoundingBox& b)
const
3310 if (!kCacheCoords)
return pointInBox(n->ptIdx, b);
3311 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3312 for (Dimension i = 0; i < dims; ++i)
3313 if (n->pcoord[i] < b[i].low || n->pcoord[i] > b[i].high)
return false;
3317 void recycleNode(INode* n)
3319 n->child1 = freeList_;
3325 void destroyNodeObjects()
3327 if (std::is_trivially_destructible<INode>::value)
return;
3328 destroySubtree(iroot_);
3332 INode* n = freeList_;
3333 freeList_ = n->child1;
3338 void destroySubtree(INode* n)
3341 destroySubtree(n->child1);
3342 destroySubtree(n->child2);
3349 ElementType pt(IndexType idx, Dimension d)
const {
return dataset_.kdtree_get_pt(idx, d); }
3351 void ensureNodeMap(IndexType idx)
3360 if (idx == (std::numeric_limits<IndexType>::max)())
3362 throw std::invalid_argument(
3363 "[nanoflann] KDTreeSingleIndexIncrementalAdaptor: point index equal to the "
3364 "maximum IndexType value; this is almost certainly an underflowed 'size - 1' "
3365 "on an empty dataset.");
3367 if (idx >= nodeOfPoint_.size()) nodeOfPoint_.resize(
static_cast<size_t>(idx) + 1,
nullptr);
3372 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3374 for (Dimension i = 0; i < dims; ++i) Base::root_bbox_[i] = iroot_->box[i];
3376 for (Dimension i = 0; i < dims; ++i) Base::root_bbox_[i] = Interval{0, 0};
3379 void initBoxToPoint(INode* n)
3381 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3382 for (Dimension i = 0; i < dims; ++i)
3384 const ElementType v = pt(n->ptIdx, i);
3385 n->box[i].low = n->box[i].high = v;
3389 void expandBoxToPoint(INode* n, IndexType idx)
3391 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3392 for (Dimension i = 0; i < dims; ++i)
3394 const ElementType v = pt(idx, i);
3395 if (v < n->box[i].low) n->box[i].low = v;
3396 if (v > n->box[i].high) n->box[i].high = v;
3400 void unionBox(INode* n,
const INode* c)
3403 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3404 for (Dimension i = 0; i < dims; ++i)
3406 if (c->box[i].low < n->box[i].low) n->box[i].low = c->box[i].low;
3407 if (c->box[i].high > n->box[i].high) n->box[i].high = c->box[i].high;
3411 bool pointInBox(IndexType idx,
const BoundingBox& b)
const
3413 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3414 for (Dimension i = 0; i < dims; ++i)
3416 const ElementType v = pt(idx, i);
3417 if (v < b[i].low || v > b[i].high)
return false;
3422 bool boxFullyInside(
const BoundingBox& inner,
const BoundingBox& outer)
const
3424 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3425 for (Dimension i = 0; i < dims; ++i)
3426 if (inner[i].low < outer[i].low || inner[i].high > outer[i].high)
return false;
3430 bool boxDisjoint(
const BoundingBox& a,
const BoundingBox& b)
const
3432 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3433 for (Dimension i = 0; i < dims; ++i)
3434 if (a[i].high < b[i].low || a[i].low > b[i].high)
return true;
3441 INode* makeLeaf(IndexType idx, Dimension depth, INode* parent)
3443 INode* n = allocNode();
3444 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3446 n->divfeat =
static_cast<Dimension
>(depth % dims);
3448 n->treeDeleted =
false;
3449 n->child1 = n->child2 =
nullptr;
3451 n->subtree_size = 1;
3452 n->invalid_count = 0;
3455 nodeOfPoint_[idx] = n;
3461 void insertOne(IndexType idx)
3463 pendingRebuild_ =
nullptr;
3464 iroot_ = insertRec(iroot_, idx, 0,
nullptr);
3467 if (pendingRebuild_ && inlineRebuild_) rebuildAt(pendingRebuild_);
3470 INode* insertRec(INode* node, IndexType idx, Dimension depth, INode* parent)
3472 if (!node)
return makeLeaf(idx, depth, parent);
3473 if (node->treeDeleted) pushDownDelete(node);
3475 ++node->subtree_size;
3476 expandBoxToPoint(node, idx);
3478 const Dimension axis = node->divfeat;
3479 if (pt(idx, axis) < nodeCoord(node, axis))
3480 node->child1 = insertRec(node->child1, idx,
static_cast<Dimension
>(depth + 1), node);
3482 node->child2 = insertRec(node->child2, idx,
static_cast<Dimension
>(depth + 1), node);
3487 if (isBalanceScapegoat(node)) pendingRebuild_ = node;
3493 void pushDownDelete(INode* node)
3495 node->deleted =
true;
3498 node->child1->treeDeleted =
true;
3499 node->child1->invalid_count = node->child1->subtree_size;
3503 node->child2->treeDeleted =
true;
3504 node->child2->invalid_count = node->child2->subtree_size;
3506 node->treeDeleted =
false;
3509 Size maxChildSize(
const INode* node)
const
3511 const Size l = node->child1 ? node->child1->subtree_size : 0;
3512 const Size r = node->child2 ? node->child2->subtree_size : 0;
3513 return l > r ? l : r;
3516 bool isBalanceScapegoat(
const INode* node)
const
3518 if (node->subtree_size < kMinBalanceRebuild)
return false;
3519 return static_cast<float>(maxChildSize(node)) >
3520 alphaBal_ *
static_cast<float>(node->subtree_size);
3527 void killSubtree(INode* node)
3529 node->treeDeleted =
true;
3530 node->invalid_count = node->subtree_size;
3534 Size removeOutsideBoxRec(INode* node,
const BoundingBox& keep)
3536 if (!node)
return 0;
3537 if (node->invalid_count == node->subtree_size)
return 0;
3538 if (boxFullyInside(node->box, keep))
return 0;
3539 if (boxDisjoint(node->box, keep))
3541 const Size newly = node->subtree_size - node->invalid_count;
3543 liveCount_ -= newly;
3547 if (!node->deleted && !nodeInBox(node, keep))
3549 node->deleted =
true;
3553 newly += removeOutsideBoxRec(node->child1, keep);
3554 newly += removeOutsideBoxRec(node->child2, keep);
3555 node->invalid_count += newly;
3560 Size removeBoxRec(INode* node,
const BoundingBox& box)
3562 if (!node)
return 0;
3563 if (node->invalid_count == node->subtree_size)
return 0;
3564 if (boxDisjoint(node->box, box))
return 0;
3565 if (boxFullyInside(node->box, box))
3567 const Size newly = node->subtree_size - node->invalid_count;
3569 liveCount_ -= newly;
3573 if (!node->deleted && nodeInBox(node, box))
3575 node->deleted =
true;
3579 newly += removeBoxRec(node->child1, box);
3580 newly += removeBoxRec(node->child2, box);
3581 node->invalid_count += newly;
3585 bool isDeletionScapegoat(
const INode* node)
const
3587 if (node->subtree_size == 0)
return false;
3588 return static_cast<float>(node->invalid_count) >
3589 alphaDel_ *
static_cast<float>(node->subtree_size);
3592 INode* findDeletionScapegoat(INode* node)
const
3594 if (!node)
return nullptr;
3595 if (isDeletionScapegoat(node))
return node;
3596 if (INode* l = findDeletionScapegoat(node->child1))
return l;
3597 return findDeletionScapegoat(node->child2);
3600 void maybeRebuildForDeletion()
3602 if (!iroot_ || !inlineRebuild_)
return;
3603 if (INode* sg = findDeletionScapegoat(iroot_)) rebuildAt(sg);
3609 void rebuildAt(INode* node)
3611 INode* par = node->parent;
3612 INode** link = par ? (par->child1 == node ? &par->child1 : &par->child2) : &iroot_;
3614 const Size oldSize = node->subtree_size;
3615 const Size oldInvalid = node->invalid_count;
3618 collectLiveAndFree(node, buildBuf_);
3620 INode* nb = buildBalanced(buildBuf_, 0, buildBuf_.size(), 0, par);
3623 const Size newSize = nb ? nb->subtree_size : 0;
3625 for (INode* p = par; p; p = p->parent)
3627 p->subtree_size = p->subtree_size - oldSize + newSize;
3628 p->invalid_count = p->invalid_count - oldInvalid;
3630 totalCount_ = totalCount_ - oldSize + newSize;
3636 void collectLiveAndFree(INode* node, std::vector<IndexType>& out)
3639 if (node->treeDeleted)
3641 freeDeadSubtree(node);
3645 out.push_back(node->ptIdx);
3647 dropDeadPoint(node->ptIdx);
3648 collectLiveAndFree(node->child1, out);
3649 collectLiveAndFree(node->child2, out);
3653 void freeDeadSubtree(INode* node)
3656 dropDeadPoint(node->ptIdx);
3657 freeDeadSubtree(node->child1);
3658 freeDeadSubtree(node->child2);
3662 void dropDeadPoint(IndexType idx)
3664 if (idx < nodeOfPoint_.size()) nodeOfPoint_[idx] =
nullptr;
3665 if (collectRemoved_) removedSink_.push_back(idx);
3669 void snapshotRec(
const INode* node, std::vector<IndexType>& out)
const
3672 if (node->invalid_count == node->subtree_size)
return;
3673 if (!node->deleted) out.push_back(node->ptIdx);
3674 snapshotRec(node->child1, out);
3675 snapshotRec(node->child2, out);
3679 void collectAllRec(
const INode* node, std::vector<IndexType>& out)
const
3682 out.push_back(node->ptIdx);
3683 collectAllRec(node->child1, out);
3684 collectAllRec(node->child2, out);
3692 void saveNode(std::ostream& stream,
const INode* n)
const
3694 save_value(stream, n->ptIdx);
3695 save_value(stream, n->divfeat);
3696 save_value(stream, n->deleted);
3697 save_value(stream, n->treeDeleted);
3699 const uint8_t hasChild1 = n->child1 ? 1 : 0;
3700 save_value(stream, hasChild1);
3701 if (n->child1) saveNode(stream, n->child1);
3703 const uint8_t hasChild2 = n->child2 ? 1 : 0;
3704 save_value(stream, hasChild2);
3705 if (n->child2) saveNode(stream, n->child2);
3718 INode* loadNode(std::istream& stream, INode* parent)
3720 INode* n = allocNode();
3721 load_value(stream, n->ptIdx);
3722 load_value(stream, n->divfeat);
3723 load_value(stream, n->deleted);
3724 load_value(stream, n->treeDeleted);
3727 uint8_t hasChild1 = 0;
3728 load_value(stream, hasChild1);
3729 n->child1 = hasChild1 ? loadNode(stream, n) : nullptr;
3731 uint8_t hasChild2 = 0;
3732 load_value(stream, hasChild2);
3733 n->child2 = hasChild2 ? loadNode(stream, n) : nullptr;
3735 n->subtree_size = 1 + (n->child1 ? n->child1->subtree_size : 0) +
3736 (n->child2 ? n->child2->subtree_size : 0);
3737 n->invalid_count = n->treeDeleted ? n->subtree_size
3738 :
static_cast<Size
>(n->deleted ? 1 : 0) +
3739 (n->child1 ? n->child1->invalid_count : 0) +
3740 (n->child2 ? n->child2->invalid_count : 0);
3743 unionBox(n, n->child1);
3744 unionBox(n, n->child2);
3747 ensureNodeMap(n->ptIdx);
3748 nodeOfPoint_[n->ptIdx] = n;
3754 INode* buildBalanced(
3755 std::vector<IndexType>& buf,
size_t lo,
size_t hi, Dimension depth, INode* parent)
3757 if (lo >= hi)
return nullptr;
3758 const Dimension dims =
static_cast<Dimension
>(this->veclen(*
this));
3761 Dimension axis =
static_cast<Dimension
>(depth % dims);
3762 ElementType bestSpan = -1;
3763 for (Dimension d = 0; d < dims; ++d)
3765 ElementType mn = pt(buf[lo], d), mx = mn;
3766 for (
size_t k = lo + 1; k < hi; ++k)
3768 const ElementType v = pt(buf[k], d);
3772 const ElementType span = mx - mn;
3773 if (span > bestSpan)
3780 const size_t mid = lo + (hi - lo) / 2;
3782 buf.begin() + lo, buf.begin() + mid, buf.begin() + hi,
3783 [
this, axis](IndexType a, IndexType b) { return pt(a, axis) < pt(b, axis); });
3785 INode* node = allocNode();
3786 node->ptIdx = buf[mid];
3787 node->divfeat = axis;
3788 node->deleted =
false;
3789 node->treeDeleted =
false;
3790 node->parent = parent;
3792 nodeOfPoint_[buf[mid]] = node;
3794 node->child1 = buildBalanced(buf, lo, mid,
static_cast<Dimension
>(depth + 1), node);
3795 node->child2 = buildBalanced(buf, mid + 1, hi,
static_cast<Dimension
>(depth + 1), node);
3797 node->subtree_size = hi - lo;
3798 node->invalid_count = 0;
3799 initBoxToPoint(node);
3800 unionBox(node, node->child1);
3801 unionBox(node, node->child2);
3808 template <
class RESULTSET>
3809 void searchLevelInc(
3810 RESULTSET& rs,
const ElementType* vec,
const INode* node, DistanceType mindist,
3811 distance_vector_t& dists,
const DistanceType epsError,
const Size dim)
const
3814 if (node->invalid_count == node->subtree_size)
return;
3818#if defined(NANOFLANN_INCREMENTAL_INNODE_DISTANCE)
3824 DistanceType d = DistanceType();
3826 for (Size i = 0; i < dim; ++i)
3827 d += distance_.accum_dist(
3828 vec[i], node->pcoord[
static_cast<Dimension
>(i)],
static_cast<Dimension
>(i));
3830 d = distance_.evalMetric(vec, node->ptIdx, dim);
3832 const DistanceType d = distance_.evalMetric(vec, node->ptIdx, dim);
3834 if (d < rs.worstDist())
3836 static_cast<typename RESULTSET::DistanceType
>(d),
3837 static_cast<typename RESULTSET::IndexType
>(node->ptIdx));
3840 const Dimension axis = node->divfeat;
3841 const ElementType splitval = nodeCoord(node, axis);
3842 const ElementType val = vec[axis];
3843 const DistanceType cut = distance_.accum_dist(val, splitval, axis);
3845 const INode* nearChild;
3846 const INode* farChild;
3849 nearChild = node->child1;
3850 farChild = node->child2;
3854 nearChild = node->child2;
3855 farChild = node->child1;
3858 searchLevelInc(rs, vec, nearChild, mindist, dists, epsError, dim);
3860 const DistanceType dst = dists[axis];
3861 const DistanceType newmin = mindist + cut - dst;
3863 if (newmin * epsError <= rs.worstDist())
3864 searchLevelInc(rs, vec, farChild, newmin, dists, epsError, dim);
3868 template <
typename RESULTSET>
3869 void findWithinBoxRec(RESULTSET& result,
const INode* node,
const BoundingBox& bbox)
const
3872 if (node->invalid_count == node->subtree_size)
return;
3873 if (boxDisjoint(node->box, bbox))
return;
3874 if (!node->deleted && nodeInBox(node, bbox)) result.addPoint(0, node->ptIdx);
3875 findWithinBoxRec(result, node->child1, bbox);
3876 findWithinBoxRec(result, node->child2, bbox);
3880#ifndef NANOFLANN_NO_THREADS
3915template <
typename Distance,
class DatasetAdaptor, int32_t DIM = -1,
typename IndexType = uint32_t>
3920 using ElementType =
typename Inner::ElementType;
3921 using DistanceType =
typename Inner::DistanceType;
3922 using Size =
typename Inner::Size;
3923 using Dimension =
typename Inner::Dimension;
3924 using BoundingBox =
typename Inner::BoundingBox;
3932 const Dimension dimensionality,
const DatasetAdaptor& inputData,
3934 Size min_rebuild_size = 10000)
3935 : dataset_(inputData),
3936 dim_(dimensionality),
3938 rebuildGrowth_(rebuild_growth),
3939 minRebuildSize_(min_rebuild_size)
3941 active_.reset(
new Inner(dimensionality, inputData, params));
3942 active_->setInlineRebuild(
false);
3945 KDTreeSingleIndexIncrementalAdaptorMT(
const KDTreeSingleIndexIncrementalAdaptorMT&) =
delete;
3946 KDTreeSingleIndexIncrementalAdaptorMT& operator=(
const KDTreeSingleIndexIncrementalAdaptorMT&) =
3949 ~KDTreeSingleIndexIncrementalAdaptorMT()
3957 void addPoints(IndexType start, IndexType end)
3960 active_->addPoints(start, end);
3961 if (building_) log_.push_back({OpKind::Add, start, end, {}});
3962 maybeTriggerRebuild();
3964 void addPoint(IndexType idx) { addPoints(idx, idx); }
3966 void removePoint(IndexType idx)
3969 active_->removePoint(idx);
3970 if (building_) log_.push_back({OpKind::Remove, idx, idx, {}});
3971 maybeTriggerRebuild();
3973 void removeBox(
const BoundingBox& box)
3976 active_->removeBox(box);
3977 if (building_) log_.push_back({OpKind::RemoveBox, 0, 0, box});
3978 maybeTriggerRebuild();
3980 void removeOutsideBox(
const BoundingBox& keep)
3983 active_->removeOutsideBox(keep);
3984 if (building_) log_.push_back({OpKind::RemoveOutsideBox, 0, 0, keep});
3985 maybeTriggerRebuild();
3990 template <
typename RESULTSET>
3992 RESULTSET& result,
const ElementType* vec,
const SearchParameters& sp = {})
const
3994 return active_->findNeighbors(result, vec, sp);
3997 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
3998 DistanceType* out_distances,
const SearchParameters& sp = {})
const
4000 return active_->knnSearch(query_point, num_closest, out_indices, out_distances, sp);
4003 const ElementType* query_point,
const DistanceType& radius,
4004 std::vector<ResultItem<IndexType, DistanceType>>& IndicesDists,
4005 const SearchParameters& sp = {})
const
4007 return active_->radiusSearch(query_point, radius, IndicesDists, sp);
4010 const ElementType* query_point,
const Size num_closest, IndexType* out_indices,
4011 DistanceType* out_distances,
const DistanceType& radius)
const
4013 return active_->rknnSearch(query_point, num_closest, out_indices, out_distances, radius);
4015 template <
typename RESULTSET>
4016 Size findWithinBox(RESULTSET& result,
const BoundingBox& bbox)
const
4018 return active_->findWithinBox(result, bbox);
4023 Size size() const noexcept {
return active_->size(); }
4024 bool empty() const noexcept {
return active_->empty(); }
4025 Size physicalSize() const noexcept {
return active_->physicalSize(); }
4026 bool isRebuilding() const noexcept {
return building_; }
4029 NANOFLANN_NODISCARD BoundingBox
boundingBox()
const {
return active_->boundingBox(); }
4034 active_->snapshotLiveIndices(out);
4045 std::unique_lock<std::mutex> lk(workerMtx_);
4046 workerCvDone_.wait(lk, [
this] {
return resultReady_; });
4063 active_->saveIndex(stream);
4073 active_->loadIndex(stream);
4074 lastBuildLive_ = active_->size();
4094 collectRemoved_ = enable;
4095 if (!enable) std::vector<IndexType>().swap(removedSink_);
4103 std::vector<IndexType> out;
4104 out.swap(removedSink_);
4124 void maybeTriggerRebuild()
4126 if (building_)
return;
4127 const Size phys = active_->physicalSize();
4128 if (phys < minRebuildSize_)
return;
4129 const Size base = lastBuildLive_ ? lastBuildLive_ : Size(1);
4130 if (
static_cast<double>(phys) < rebuildGrowth_ *
static_cast<double>(base))
return;
4134 auto snapshot = std::make_shared<std::vector<IndexType>>();
4135 active_->snapshotLiveIndices(*snapshot);
4139 if (!workerThread_.joinable())
4141 workerThread_ = std::thread(&KDTreeSingleIndexIncrementalAdaptorMT::workerLoop,
this);
4145 std::lock_guard<std::mutex> lk(workerMtx_);
4146 pendingJob_ = std::move(snapshot);
4149 pendingCallback_ = rebuildCallback_;
4151 buildError_ =
nullptr;
4152 resultReady_ =
false;
4154 workerCvJob_.notify_one();
4166 std::shared_ptr<std::vector<IndexType>> job;
4167 std::function<void(Inner&)> cb;
4169 std::unique_lock<std::mutex> lk(workerMtx_);
4170 workerCvJob_.wait(lk, [
this] {
return workerStop_ || pendingJob_ !=
nullptr; });
4174 if (workerStop_ && !pendingJob_)
return;
4175 job = std::move(pendingJob_);
4176 cb = std::move(pendingCallback_);
4181 std::unique_ptr<Inner> t;
4182 std::exception_ptr err;
4185 t.reset(
new Inner(dim_, dataset_, params_));
4186 t->setInlineRebuild(
false);
4187 t->buildFromIndices(*job);
4194 err = std::current_exception();
4199 std::lock_guard<std::mutex> lk(workerMtx_);
4200 builtTree_ = std::move(t);
4202 resultReady_ =
true;
4204 workerCvDone_.notify_all();
4211 if (!workerThread_.joinable())
return;
4213 std::lock_guard<std::mutex> lk(workerMtx_);
4216 workerCvJob_.notify_all();
4217 workerThread_.join();
4220 void integrateIfReady()
4222 if (!building_)
return;
4224 std::unique_ptr<Inner> fresh;
4225 std::exception_ptr err;
4227 std::lock_guard<std::mutex> lk(workerMtx_);
4228 if (!resultReady_)
return;
4229 resultReady_ =
false;
4230 fresh = std::move(builtTree_);
4232 buildError_ =
nullptr;
4244 KDTreeSingleIndexIncrementalAdaptorMT& self;
4248 self.building_ =
false;
4250 } endOfRebuild{*
this};
4254 if (err) std::rethrow_exception(err);
4256 fresh->setInlineRebuild(
false);
4258 for (
const auto& op : log_)
4263 fresh->addPoints(op.a, op.b);
4265 case OpKind::Remove:
4266 fresh->removePoint(op.a);
4268 case OpKind::RemoveBox:
4269 fresh->removeBox(op.box);
4271 case OpKind::RemoveOutsideBox:
4272 fresh->removeOutsideBox(op.box);
4278 if (collectRemoved_)
4280 std::vector<IndexType> oldPhysical;
4281 active_->collectPhysicalIndices(oldPhysical);
4282 for (IndexType idx : oldPhysical)
4283 if (!fresh->referencesIndex(idx)) removedSink_.push_back(idx);
4285 active_ = std::move(fresh);
4286 lastBuildLive_ = active_->size();
4289 const DatasetAdaptor& dataset_;
4291 KDTreeIncrementalIndexParams params_;
4292 double rebuildGrowth_;
4293 Size minRebuildSize_;
4295 std::unique_ptr<Inner> active_;
4298 bool building_ =
false;
4299 Size lastBuildLive_ = 0;
4300 std::vector<LoggedOp> log_;
4308 std::thread workerThread_;
4309 std::mutex workerMtx_;
4310 std::condition_variable workerCvJob_;
4311 std::condition_variable workerCvDone_;
4312 std::shared_ptr<std::vector<IndexType>> pendingJob_;
4313 std::function<void(Inner&)> pendingCallback_;
4314 std::unique_ptr<Inner> builtTree_;
4315 std::exception_ptr buildError_;
4316 bool resultReady_ =
false;
4317 bool workerStop_ =
false;
4320 bool collectRemoved_ =
false;
4321 std::vector<IndexType> removedSink_;
4322 std::function<void(Inner&)> rebuildCallback_;
4352 class MatrixType, int32_t DIM = -1,
class Distance = nanoflann::metric_L2,
4353 bool row_major =
true>
4357 using num_t =
typename MatrixType::Scalar;
4358 using IndexType =
typename MatrixType::Index;
4359 using metric_t =
typename Distance::template traits<num_t, self_t, IndexType>::distance_t;
4362 metric_t, self_t, row_major ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime,
4369 using Size =
typename index_t::Size;
4370 using Dimension =
typename index_t::Dimension;
4374 const Dimension dimensionality,
const std::reference_wrapper<const MatrixType>& mat,
4375 const int leaf_max_size = 10,
const unsigned int n_thread_build = 1)
4376 : m_data_matrix(mat)
4378 const auto dims = row_major ? mat.get().cols() : mat.get().rows();
4379 if (
static_cast<Dimension
>(dims) != dimensionality)
4380 throw std::runtime_error(
4381 "Error: 'dimensionality' must match column count in data "
4383 if (DIM > 0 &&
static_cast<int32_t
>(dims) != DIM)
4384 throw std::runtime_error(
4385 "Data set dimensionality does not match the 'DIM' template "
4387 index_ =
new index_t(
4388 static_cast<Dimension
>(dims), *
this ,
4390 leaf_max_size, nanoflann::KDTreeSingleIndexAdaptorFlags::None, n_thread_build));
4396 self_t& operator=(
const self_t&) =
delete;
4403 self_t& operator=(self_t&&) =
delete;
4407 const std::reference_wrapper<const MatrixType> m_data_matrix;
4418 const num_t* query_point,
const Size num_closest, IndexType* out_indices,
4419 num_t* out_distances)
const
4422 resultSet.init(out_indices, out_distances);
4423 index_->findNeighbors(resultSet, query_point);
4429 inline const self_t& derived() const noexcept {
return *
this; }
4430 inline self_t& derived() noexcept {
return *
this; }
4433 inline Size kdtree_get_point_count()
const
4436 return m_data_matrix.get().rows();
4438 return m_data_matrix.get().cols();
4442 inline num_t kdtree_get_pt(
const IndexType idx,
size_t dim)
const
4445 return m_data_matrix.get().coeff(idx, IndexType(dim));
4447 return m_data_matrix.get().coeff(IndexType(dim), idx);
4455 template <
class BBOX>
4456 inline bool kdtree_get_bbox(BBOX& )
const
4469#undef NANOFLANN_RESTRICT
bool addPoint(DistanceType, IndexType index)
Definition nanoflann.hpp:491
Definition nanoflann.hpp:1052
NANOFLANN_NODISCARD bool isActive(IndexType) const
Definition nanoflann.hpp:1210
void freeIndex(Derived &obj)
Definition nanoflann.hpp:1056
NANOFLANN_NODISCARD Size veclen(const Derived &obj) const noexcept
Definition nanoflann.hpp:1157
void computeMinMax(const Derived &obj, Offset ind, Size count, Dimension element, ElementType &min_elem, ElementType &max_elem) const
Definition nanoflann.hpp:1193
BoundingBox root_bbox_
Definition nanoflann.hpp:1139
void saveIndex(const Derived &obj, std::ostream &stream) const
Definition nanoflann.hpp:1671
void computeBoundingBox(BoundingBox &bbox)
Definition nanoflann.hpp:1215
NANOFLANN_NODISCARD Size usedMemory(const Derived &obj) const
Definition nanoflann.hpp:1183
Dimension dim_
Dimensionality of each data point.
Definition nanoflann.hpp:1128
typename array_or_vector< DIM, DistanceType >::type distance_vector_t
Definition nanoflann.hpp:1136
void planeSplit(const Derived &obj, const Offset ind, const Size count, const Dimension cutfeat, const DistanceType &cutval, Offset &lim1, Offset &lim2)
Definition nanoflann.hpp:1565
Size n_thread_build_
Number of thread for concurrent tree build.
Definition nanoflann.hpp:1123
NANOFLANN_NODISCARD Size size(const Derived &obj) const noexcept
Definition nanoflann.hpp:1151
std::vector< IndexType > vAcc_
Definition nanoflann.hpp:1070
bool makeNode(Derived &obj, NodePtr node, const Offset left, const Offset right, BoundingBox &bbox, Offset &idx, Dimension &cutfeat, DistanceType &cutval)
Definition nanoflann.hpp:1328
bool searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindist, distance_vector_t &dists, const DistanceType epsError) const
Definition nanoflann.hpp:1245
Size size_at_index_build_
Number of points in the dataset when the index was built.
Definition nanoflann.hpp:1127
NodePtr divideTreeConcurrent(Derived &obj, const Offset left, const Offset right, BoundingBox &bbox, std::atomic< unsigned int > &thread_count, std::mutex &mutex)
Definition nanoflann.hpp:1422
Size size_
Number of current points in the dataset.
Definition nanoflann.hpp:1125
void finalizeSplitNode(Derived &obj, NodePtr node, const Dimension cutfeat, const BoundingBox &left_bbox, const BoundingBox &right_bbox, BoundingBox &bbox)
Definition nanoflann.hpp:1370
void loadIndex(Derived &obj, std::istream &stream)
Definition nanoflann.hpp:1717
PooledAllocator pool_
Definition nanoflann.hpp:1148
ElementType dataset_get(const Derived &obj, IndexType element, Dimension component) const
Helper accessor to the dataset points:
Definition nanoflann.hpp:1174
typename array_or_vector< DIM, Interval >::type BoundingBox
Definition nanoflann.hpp:1132
static constexpr uint32_t SAVE_MAGIC
Definition nanoflann.hpp:1651
Definition nanoflann.hpp:1838
void saveIndex(std::ostream &stream) const
Definition nanoflann.hpp:2199
NANOFLANN_NODISCARD Size findWithinBox(RESULTSET &result, const BoundingBox &bbox) const
Definition nanoflann.hpp:2030
void init_vind()
Definition nanoflann.hpp:2174
void buildIndex()
Definition nanoflann.hpp:1943
NANOFLANN_NODISCARD Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2120
NANOFLANN_NODISCARD Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2136
NANOFLANN_NODISCARD Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances) const
Definition nanoflann.hpp:2091
const self_t & dataset_
Definition nanoflann.hpp:1845
KDTreeSingleIndexAdaptor(const KDTreeSingleIndexAdaptor< Distance, DatasetAdaptor, DIM, index_t > &)=delete
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:1990
NANOFLANN_NODISCARD Size rknnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const DistanceType &radius) const
Definition nanoflann.hpp:2159
typename Base::distance_vector_t distance_vector_t
Definition nanoflann.hpp:1874
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:2206
typename Base::BoundingBox BoundingBox
Definition nanoflann.hpp:1870
KDTreeSingleIndexAdaptor(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams ¶ms, Args &&... args)
Definition nanoflann.hpp:1897
Definition nanoflann.hpp:2252
KDTreeSingleIndexDynamicAdaptor_(const Dimension dimensionality, const DatasetAdaptor &inputData, std::vector< int > &treeIndex, const KDTreeSingleIndexAdaptorParams ¶ms=KDTreeSingleIndexAdaptorParams())
Definition nanoflann.hpp:2306
typename Base::BoundingBox BoundingBox
Definition nanoflann.hpp:2282
const DatasetAdaptor & dataset_
Definition nanoflann.hpp:2257
NANOFLANN_NODISCARD Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2434
KDTreeSingleIndexDynamicAdaptor_(const KDTreeSingleIndexDynamicAdaptor_ &rhs)=default
void buildIndex()
Definition nanoflann.hpp:2351
void saveIndex(std::ostream &stream)
Definition nanoflann.hpp:2496
NANOFLANN_NODISCARD bool isActive(IndexType idx) const
Definition nanoflann.hpp:2289
NANOFLANN_NODISCARD Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2479
typename Base::distance_vector_t distance_vector_t
Definition nanoflann.hpp:2286
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:2503
KDTreeSingleIndexDynamicAdaptor_ & operator=(const KDTreeSingleIndexDynamicAdaptor_ &rhs)
Definition nanoflann.hpp:2332
NANOFLANN_NODISCARD Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2463
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2400
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2705
const DatasetAdaptor & dataset_
The source of our data.
Definition nanoflann.hpp:2540
void removePoint(size_t idx)
Definition nanoflann.hpp:2678
std::unordered_map< IndexType, int > removedPoints_
Definition nanoflann.hpp:2548
void addPoints(IndexType start, IndexType end)
Definition nanoflann.hpp:2629
KDTreeSingleIndexDynamicAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams ¶ms=KDTreeSingleIndexAdaptorParams(), const size_t maximumPointCount=1000000000U)
Definition nanoflann.hpp:2604
std::vector< int > treeIndex_
Definition nanoflann.hpp:2544
const std::vector< index_container_t > & getAllIndices() const
Definition nanoflann.hpp:2561
Dimension dim_
Dimensionality of each data point.
Definition nanoflann.hpp:2552
KDTreeSingleIndexDynamicAdaptor(const KDTreeSingleIndexDynamicAdaptor< Distance, DatasetAdaptor, DIM, IndexType > &)=delete
void snapshotLiveIndices(std::vector< IndexType > &out) const
Definition nanoflann.hpp:4032
KDTreeSingleIndexIncrementalAdaptorMT(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeIncrementalIndexParams ¶ms={}, double rebuild_growth=1.3, Size min_rebuild_size=10000)
Definition nanoflann.hpp:3931
void setCollectRemovedPoints(bool enable)
Definition nanoflann.hpp:4092
void sync()
Definition nanoflann.hpp:4041
const Inner & activeIndex() const
Definition nanoflann.hpp:4052
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:4070
void reserve(Size n)
Definition nanoflann.hpp:4038
std::vector< IndexType > acquireRemovedPoints()
Definition nanoflann.hpp:4101
void setRebuildCallback(std::function< void(Inner &)> cb)
Definition nanoflann.hpp:4085
NANOFLANN_NODISCARD BoundingBox boundingBox() const
Definition nanoflann.hpp:4029
void saveIndex(std::ostream &stream)
Definition nanoflann.hpp:4060
Definition nanoflann.hpp:2778
NANOFLANN_NODISCARD Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3096
NANOFLANN_NODISCARD Size rknnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const DistanceType &radius) const
Definition nanoflann.hpp:3117
void removeBox(const BoundingBox &box)
Definition nanoflann.hpp:2953
void setCollectRemovedPoints(bool enable)
Definition nanoflann.hpp:2971
void saveIndex(std::ostream &stream) const
Definition nanoflann.hpp:3166
NANOFLANN_NODISCARD Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3108
void addPoint(IndexType idx)
Definition nanoflann.hpp:2897
NANOFLANN_NODISCARD BoundingBox boundingBox() const
Definition nanoflann.hpp:3052
void setInlineRebuild(bool enable)
Definition nanoflann.hpp:2989
KDTreeSingleIndexIncrementalAdaptor(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeIncrementalIndexParams ¶ms={})
Definition nanoflann.hpp:2874
void snapshotLiveIndices(std::vector< IndexType > &out) const
Definition nanoflann.hpp:2993
NANOFLANN_NODISCARD Size usedMemory() const
Definition nanoflann.hpp:3043
void removePoint(IndexType idx)
Definition nanoflann.hpp:2935
static constexpr uint32_t INCREMENTAL_SAVE_MAGIC
Definition nanoflann.hpp:3145
NANOFLANN_NODISCARD Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3085
const DatasetAdaptor & dataset_
Definition nanoflann.hpp:2796
void reserve(Size n)
Definition nanoflann.hpp:3056
NANOFLANN_NODISCARD Size size() const noexcept
Definition nanoflann.hpp:3036
NANOFLANN_NODISCARD Size physicalSize() const noexcept
Definition nanoflann.hpp:3040
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:3069
void collectPhysicalIndices(std::vector< IndexType > &out) const
Definition nanoflann.hpp:2998
KDTreeSingleIndexIncrementalAdaptor(const KDTreeSingleIndexIncrementalAdaptor &)=delete
static constexpr bool kCacheCoords
Definition nanoflann.hpp:2828
void removeOutsideBox(const BoundingBox &keep)
Definition nanoflann.hpp:2962
NANOFLANN_NODISCARD Size findWithinBox(RESULTSET &result, const BoundingBox &bbox) const
Definition nanoflann.hpp:3129
void addPoints(IndexType start, IndexType end)
Definition nanoflann.hpp:2912
void buildFromIndices(const std::vector< IndexType > &idxs)
Definition nanoflann.hpp:3009
NANOFLANN_NODISCARD bool referencesIndex(IndexType idx) const
Definition nanoflann.hpp:3002
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:3202
std::vector< IndexType > acquireRemovedPoints()
Definition nanoflann.hpp:2979
Definition nanoflann.hpp:292
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:326
NANOFLANN_NODISCARD DistanceType worstDist() const noexcept
Returns the worst distance among found solutions if the search result is full, or the maximum possibl...
Definition nanoflann.hpp:333
Definition nanoflann.hpp:902
~PooledAllocator()
Definition nanoflann.hpp:938
void free_all()
Definition nanoflann.hpp:941
void * allocateBytes(const size_t req_size)
Definition nanoflann.hpp:957
T * allocate(const size_t count=1)
Definition nanoflann.hpp:1006
PooledAllocator()
Definition nanoflann.hpp:933
Definition nanoflann.hpp:348
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:388
NANOFLANN_NODISCARD DistanceType worstDist() const noexcept
Returns the worst distance among found solutions if the search result is full, or the maximum possibl...
Definition nanoflann.hpp:395
Definition nanoflann.hpp:411
ResultItem< IndexType, DistanceType > worst_item() const
Definition nanoflann.hpp:452
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:440
std::enable_if< has_assign< Container >::value, void >::type assign(Container &c, const size_t nElements, const T &value)
Definition nanoflann.hpp:199
std::enable_if< has_resize< Container >::value, void >::type resize(Container &c, const size_t nElements)
Definition nanoflann.hpp:178
constexpr T pi_const()
Definition nanoflann.hpp:145
bool has_flag(KDTreeSingleIndexAdaptorFlags f, KDTreeSingleIndexAdaptorFlags flag)
Definition nanoflann.hpp:852
Definition nanoflann.hpp:217
bool operator()(const PairType &p1, const PairType &p2) const
Definition nanoflann.hpp:220
Definition nanoflann.hpp:1114
Definition nanoflann.hpp:1089
Offset right
Indices of points in leaf node.
Definition nanoflann.hpp:1096
Dimension divfeat
Dimension used for subdivision. The values used for subdivision.
Definition nanoflann.hpp:1100
Node * child1
Definition nanoflann.hpp:1107
union nanoflann::KDTreeBaseClass::Node::@327270127162340211203002370327206303122355110302 node_type
void query(const num_t *query_point, const Size num_closest, IndexType *out_indices, num_t *out_distances) const
Definition nanoflann.hpp:4417
KDTreeEigenMatrixAdaptor(const self_t &)=delete
KDTreeEigenMatrixAdaptor(self_t &&)=delete
typename index_t::Offset Offset
Definition nanoflann.hpp:4368
KDTreeEigenMatrixAdaptor(const Dimension dimensionality, const std::reference_wrapper< const MatrixType > &mat, const int leaf_max_size=10, const unsigned int n_thread_build=1)
Constructor: takes a const ref to the matrix object with the data points.
Definition nanoflann.hpp:4373
Definition nanoflann.hpp:2729
Definition nanoflann.hpp:859
Definition nanoflann.hpp:2803
Size invalid_count
number of tombstoned nodes in subtree
Definition nanoflann.hpp:2812
Dimension divfeat
splitting axis at this node
Definition nanoflann.hpp:2805
bool treeDeleted
whole subtree lazily tombstoned
Definition nanoflann.hpp:2807
IndexType ptIdx
index of the stored data point
Definition nanoflann.hpp:2804
INode * parent
parent (nullptr at the root)
Definition nanoflann.hpp:2810
Size subtree_size
number of nodes in this subtree
Definition nanoflann.hpp:2811
INode * child1
"< split" child (also free-list link)
Definition nanoflann.hpp:2808
INode * child2
">= split" child
Definition nanoflann.hpp:2809
BoundingBox box
AABB of all points (live+dead) in this subtree Cache of this node's own point coordinates,...
Definition nanoflann.hpp:2813
bool deleted
this node's point is tombstoned
Definition nanoflann.hpp:2806
Definition nanoflann.hpp:553
Definition nanoflann.hpp:615
Definition nanoflann.hpp:682
Definition nanoflann.hpp:538
Definition nanoflann.hpp:236
DistanceType second
Distance from sample to query point.
Definition nanoflann.hpp:243
IndexType first
Index of the sample in the dataset.
Definition nanoflann.hpp:242
Definition nanoflann.hpp:721
DistanceType accum_dist(const U a, const V b, const size_t) const
Definition nanoflann.hpp:740
Definition nanoflann.hpp:764
Definition nanoflann.hpp:875
bool sorted
only for radius search, require neighbors sorted by distance (default: true)
Definition nanoflann.hpp:879
float eps
search for eps-approximate neighbors (default: 0)
Definition nanoflann.hpp:878
Definition nanoflann.hpp:1022
Definition nanoflann.hpp:166
Definition nanoflann.hpp:156
Definition nanoflann.hpp:789
Definition nanoflann.hpp:786
Definition nanoflann.hpp:799
Definition nanoflann.hpp:809
Definition nanoflann.hpp:806
Definition nanoflann.hpp:796
Definition nanoflann.hpp:818
Definition nanoflann.hpp:815
Definition nanoflann.hpp:827
Definition nanoflann.hpp:824