nanoflann
C++ header-only ANN library
Loading...
Searching...
No Matches
nanoflann.hpp
1/***********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
5 * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
6 * Copyright 2011-2025 Jose Luis Blanco (joseluisblancoc@gmail.com).
7 * All rights reserved.
8 *
9 * THE BSD LICENSE
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *************************************************************************/
32
50
51#pragma once
52
53#include <algorithm>
54#include <array>
55#include <atomic>
56#include <cassert>
57#include <cmath> // for abs()
58#include <cstdint>
59#include <cstdlib> // for abs()
60#include <functional> // std::reference_wrapper
61#include <future>
62#include <istream>
63#include <limits> // std::numeric_limits
64#include <ostream>
65#include <stack>
66#include <stdexcept>
67#include <unordered_set>
68#include <vector>
69
71#define NANOFLANN_VERSION 0x190
72
73// Avoid conflicting declaration of min/max macros in Windows headers
74#if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64))
75#define NOMINMAX
76#ifdef max
77#undef max
78#undef min
79#endif
80#endif
81// Avoid conflicts with X11 headers
82#ifdef None
83#undef None
84#endif
85
86// Handle restricted pointers
87#if defined(__GNUC__) || defined(__clang__)
88#define NANOFLANN_RESTRICT __restrict__
89#elif defined(_MSC_VER)
90#define NANOFLANN_RESTRICT __restrict
91#else
92#define NANOFLANN_RESTRICT
93#endif
94
95// Memory alignment of KD-tree nodes:
96#ifndef NANOFLANN_NODE_ALIGNMENT
97#define NANOFLANN_NODE_ALIGNMENT 16
98#endif
99
100namespace nanoflann
101{
104
106template <typename T>
107constexpr T pi_const()
108{
109 return static_cast<T>(3.14159265358979323846);
110}
111
116template <typename T, typename = int>
117struct has_resize : std::false_type
118{
119};
120
121template <typename T>
122struct has_resize<T, decltype((void)std::declval<T>().resize(1), 0)> : std::true_type
123{
124};
125
126template <typename T, typename = int>
127struct has_assign : std::false_type
128{
129};
130
131template <typename T>
132struct has_assign<T, decltype((void)std::declval<T>().assign(1, 0), 0)> : std::true_type
133{
134};
135
139template <typename Container>
140inline typename std::enable_if<has_resize<Container>::value, void>::type resize(
141 Container& c, const size_t nElements)
142{
143 c.resize(nElements);
144}
145
150template <typename Container>
151inline typename std::enable_if<!has_resize<Container>::value, void>::type resize(
152 Container& c, const size_t nElements)
153{
154 if (nElements != c.size()) throw std::logic_error("Attempt to resize a fixed size container.");
155}
156
160template <typename Container, typename T>
161inline typename std::enable_if<has_assign<Container>::value, void>::type assign(
162 Container& c, const size_t nElements, const T& value)
163{
164 c.assign(nElements, value);
165}
166
170template <typename Container, typename T>
171inline typename std::enable_if<!has_assign<Container>::value, void>::type assign(
172 Container& c, const size_t nElements, const T& value)
173{
174 for (size_t i = 0; i < nElements; i++) c[i] = value;
175}
176
179{
181 template <typename PairType>
182 bool operator()(const PairType& p1, const PairType& p2) const
183 {
184 return p1.second < p2.second;
185 }
186};
187
196template <typename IndexType = size_t, typename DistanceType = double>
197struct ResultItem
198{
199 ResultItem() = default;
200 ResultItem(const IndexType index, const DistanceType distance) : first(index), second(distance)
201 {
202 }
203
204 IndexType first;
205 DistanceType second;
206};
207
210
212template <typename _DistanceType, typename _IndexType = size_t, typename _CountType = size_t>
213class KNNResultSet
214{
215 public:
216 using DistanceType = _DistanceType;
217 using IndexType = _IndexType;
218 using CountType = _CountType;
219
220 private:
221 IndexType* indices;
222 DistanceType* dists;
223 CountType capacity;
224 CountType count;
225
226 public:
227 explicit KNNResultSet(CountType capacity_)
228 : indices(nullptr), dists(nullptr), capacity(capacity_), count(0)
229 {
230 }
231
232 void init(IndexType* indices_, DistanceType* dists_)
233 {
234 indices = indices_;
235 dists = dists_;
236 count = 0;
237 }
238
239 CountType size() const noexcept { return count; }
240 bool empty() const noexcept { return count == 0; }
241 bool full() const noexcept { return count == capacity; }
242
248 bool addPoint(DistanceType dist, IndexType index)
249 {
250 CountType i;
251 for (i = count; i > 0; --i)
252 {
255#ifdef NANOFLANN_FIRST_MATCH
256 if ((dists[i - 1] > dist) || ((dist == dists[i - 1]) && (indices[i - 1] > index)))
257 {
258#else
259 if (dists[i - 1] > dist)
260 {
261#endif
262 if (i < capacity)
263 {
264 dists[i] = dists[i - 1];
265 indices[i] = indices[i - 1];
266 }
267 }
268 else
269 break;
270 }
271 if (i < capacity)
272 {
273 dists[i] = dist;
274 indices[i] = index;
275 }
276 if (count < capacity) count++;
277
278 // tell caller that the search shall continue
279 return true;
280 }
281
284 DistanceType worstDist() const noexcept
285 {
286 return (count < capacity || !count) ? std::numeric_limits<DistanceType>::max()
287 : dists[count - 1];
288 }
289
290 void sort()
291 {
292 // already sorted
293 }
294};
295
297template <typename _DistanceType, typename _IndexType = size_t, typename _CountType = size_t>
298class RKNNResultSet
299{
300 public:
301 using DistanceType = _DistanceType;
302 using IndexType = _IndexType;
303 using CountType = _CountType;
304
305 private:
306 IndexType* indices;
307 DistanceType* dists;
308 CountType capacity;
309 CountType count;
310 DistanceType maximumSearchDistanceSquared;
311
312 public:
313 explicit RKNNResultSet(CountType capacity_, DistanceType maximumSearchDistanceSquared_)
314 : indices(nullptr),
315 dists(nullptr),
316 capacity(capacity_),
317 count(0),
318 maximumSearchDistanceSquared(maximumSearchDistanceSquared_)
319 {
320 }
321
322 void init(IndexType* indices_, DistanceType* dists_)
323 {
324 indices = indices_;
325 dists = dists_;
326 count = 0;
327 if (capacity) dists[capacity - 1] = maximumSearchDistanceSquared;
328 }
329
330 CountType size() const noexcept { return count; }
331 bool empty() const noexcept { return count == 0; }
332 bool full() const noexcept { return count == capacity; }
333
339 bool addPoint(DistanceType dist, IndexType index)
340 {
341 CountType i;
342 for (i = count; i > 0; --i)
343 {
346#ifdef NANOFLANN_FIRST_MATCH
347 if ((dists[i - 1] > dist) || ((dist == dists[i - 1]) && (indices[i - 1] > index)))
348 {
349#else
350 if (dists[i - 1] > dist)
351 {
352#endif
353 if (i < capacity)
354 {
355 dists[i] = dists[i - 1];
356 indices[i] = indices[i - 1];
357 }
358 }
359 else
360 break;
361 }
362 if (i < capacity)
363 {
364 dists[i] = dist;
365 indices[i] = index;
366 }
367 if (count < capacity) count++;
368
369 // tell caller that the search shall continue
370 return true;
371 }
372
375 DistanceType worstDist() const noexcept
376 {
377 return (count < capacity || !count) ? maximumSearchDistanceSquared : dists[count - 1];
378 }
379
380 void sort()
381 {
382 // already sorted
383 }
384};
385
389template <typename _DistanceType, typename _IndexType = size_t>
390class RadiusResultSet
391{
392 public:
393 using DistanceType = _DistanceType;
394 using IndexType = _IndexType;
395
396 public:
397 const DistanceType radius;
398
399 std::vector<ResultItem<IndexType, DistanceType>>& m_indices_dists;
400
401 explicit RadiusResultSet(
402 DistanceType radius_, std::vector<ResultItem<IndexType, DistanceType>>& indices_dists)
403 : radius(radius_), m_indices_dists(indices_dists)
404 {
405 init();
406 }
407
408 void init() { clear(); }
409 void clear() { m_indices_dists.clear(); }
410
411 size_t size() const noexcept { return m_indices_dists.size(); }
412 bool empty() const noexcept { return m_indices_dists.empty(); }
413 bool full() const noexcept { return true; }
414
420 bool addPoint(DistanceType dist, IndexType index)
421 {
422 if (dist < radius) m_indices_dists.emplace_back(index, dist);
423 return true;
424 }
425
426 DistanceType worstDist() const noexcept { return radius; }
427
433 {
434 if (m_indices_dists.empty())
435 throw std::runtime_error(
436 "Cannot invoke RadiusResultSet::worst_item() on "
437 "an empty list of results.");
438 auto it =
439 std::max_element(m_indices_dists.begin(), m_indices_dists.end(), IndexDist_Sorter());
440 return *it;
441 }
442
443 void sort() { std::sort(m_indices_dists.begin(), m_indices_dists.end(), IndexDist_Sorter()); }
444};
445
447
450template <typename T>
451void save_value(std::ostream& stream, const T& value)
452{
453 stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
454}
455
456template <typename T>
457void save_value(std::ostream& stream, const std::vector<T>& value)
458{
459 size_t size = value.size();
460 stream.write(reinterpret_cast<const char*>(&size), sizeof(size_t));
461 stream.write(reinterpret_cast<const char*>(value.data()), sizeof(T) * size);
462}
463
464template <typename T>
465void load_value(std::istream& stream, T& value)
466{
467 stream.read(reinterpret_cast<char*>(&value), sizeof(T));
468}
469
470template <typename T>
471void load_value(std::istream& stream, std::vector<T>& value)
472{
473 size_t size;
474 stream.read(reinterpret_cast<char*>(&size), sizeof(size_t));
475 value.resize(size);
476 stream.read(reinterpret_cast<char*>(value.data()), sizeof(T) * size);
477}
479
482
483struct Metric
484{
485};
486
497template <class T, class DataSource, typename _DistanceType = T, typename IndexType = size_t>
498struct L1_Adaptor
499{
500 using ElementType = T;
501 using DistanceType = _DistanceType;
502
503 const DataSource& data_source;
504
505 L1_Adaptor(const DataSource& _data_source) : data_source(_data_source) {}
506
507 inline DistanceType evalMetric(
508 const T* NANOFLANN_RESTRICT a, const IndexType b_idx, size_t size,
509 DistanceType worst_dist = -1) const
510 {
511 DistanceType result = DistanceType();
512 const size_t multof4 = (size >> 2) << 2; // largest multiple of 4, i.e. 1 << 2
513 size_t d;
514
515 /* Process 4 items with each loop for efficiency. */
516 if (worst_dist <= 0)
517 {
518 /* No checks with worst_dist. */
519 for (d = 0; d < multof4; d += 4)
520 {
521 const DistanceType diff0 =
522 std::abs(a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0));
523 const DistanceType diff1 =
524 std::abs(a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1));
525 const DistanceType diff2 =
526 std::abs(a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2));
527 const DistanceType diff3 =
528 std::abs(a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3));
529 /* Parentheses break dependency chain: */
530 result += (diff0 + diff1) + (diff2 + diff3);
531 }
532 }
533 else
534 {
535 /* Check with worst_dist. */
536 for (d = 0; d < multof4; d += 4)
537 {
538 const DistanceType diff0 =
539 std::abs(a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0));
540 const DistanceType diff1 =
541 std::abs(a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1));
542 const DistanceType diff2 =
543 std::abs(a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2));
544 const DistanceType diff3 =
545 std::abs(a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3));
546 /* Parentheses break dependency chain: */
547 result += (diff0 + diff1) + (diff2 + diff3);
548 if (result > worst_dist)
549 {
550 return result;
551 }
552 }
553 }
554 /* Process last 0-3 components. Unrolled loop with fall-through switch.
555 */
556 switch (size - multof4)
557 {
558 case 3:
559 result += std::abs(a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2));
560 case 2:
561 result += std::abs(a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1));
562 case 1:
563 result += std::abs(a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0));
564 case 0:
565 break;
566 }
567 return result;
568 }
569
570 template <typename U, typename V>
571 inline DistanceType accum_dist(const U a, const V b, const size_t) const
572 {
573 return std::abs(a - b);
574 }
575};
576
587template <class T, class DataSource, typename _DistanceType = T, typename IndexType = size_t>
588struct L2_Adaptor
589{
590 using ElementType = T;
591 using DistanceType = _DistanceType;
592
593 const DataSource& data_source;
594
595 L2_Adaptor(const DataSource& _data_source) : data_source(_data_source) {}
596
597 inline DistanceType evalMetric(
598 const T* NANOFLANN_RESTRICT a, const IndexType b_idx, size_t size,
599 DistanceType worst_dist = -1) const
600 {
601 DistanceType result = DistanceType();
602 const size_t multof4 = (size >> 2) << 2; // largest multiple of 4, i.e. 1 << 2
603 size_t d;
604
605 /* Process 4 items with each loop for efficiency. */
606 if (worst_dist <= 0)
607 {
608 /* No checks with worst_dist. */
609 for (d = 0; d < multof4; d += 4)
610 {
611 const DistanceType diff0 = a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0);
612 const DistanceType diff1 = a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1);
613 const DistanceType diff2 = a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2);
614 const DistanceType diff3 = a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3);
615 /* Parentheses break dependency chain: */
616 result += (diff0 * diff0 + diff1 * diff1) + (diff2 * diff2 + diff3 * diff3);
617 }
618 }
619 else
620 {
621 /* Check with worst_dist. */
622 for (d = 0; d < multof4; d += 4)
623 {
624 const DistanceType diff0 = a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0);
625 const DistanceType diff1 = a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1);
626 const DistanceType diff2 = a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2);
627 const DistanceType diff3 = a[d + 3] - data_source.kdtree_get_pt(b_idx, d + 3);
628 /* Parentheses break dependency chain: */
629 result += (diff0 * diff0 + diff1 * diff1) + (diff2 * diff2 + diff3 * diff3);
630 if (result > worst_dist)
631 {
632 return result;
633 }
634 }
635 }
636 /* Process last 0-3 components. Unrolled loop with fall-through switch.
637 */
638 DistanceType diff;
639 switch (size - multof4)
640 {
641 case 3:
642 diff = a[d + 2] - data_source.kdtree_get_pt(b_idx, d + 2);
643 result += diff * diff;
644 case 2:
645 diff = a[d + 1] - data_source.kdtree_get_pt(b_idx, d + 1);
646 result += diff * diff;
647 case 1:
648 diff = a[d + 0] - data_source.kdtree_get_pt(b_idx, d + 0);
649 result += diff * diff;
650 case 0:
651 break;
652 }
653 return result;
654 }
655
656 template <typename U, typename V>
657 inline DistanceType accum_dist(const U a, const V b, const size_t) const
658 {
659 auto diff = a - b;
660 return diff * diff;
661 }
662};
663
674template <class T, class DataSource, typename _DistanceType = T, typename IndexType = size_t>
675struct L2_Simple_Adaptor
676{
677 using ElementType = T;
678 using DistanceType = _DistanceType;
679
680 const DataSource& data_source;
681
682 L2_Simple_Adaptor(const DataSource& _data_source) : data_source(_data_source) {}
683
684 inline DistanceType evalMetric(const T* a, const IndexType b_idx, size_t size) const
685 {
686 DistanceType result = DistanceType();
687 for (size_t i = 0; i < size; ++i)
688 {
689 const DistanceType diff = a[i] - data_source.kdtree_get_pt(b_idx, i);
690 result += diff * diff;
691 }
692 return result;
693 }
694
695 template <typename U, typename V>
696 inline DistanceType accum_dist(const U a, const V b, const size_t) const
697 {
698 auto diff = a - b;
699 return diff * diff;
700 }
701};
702
713template <class T, class DataSource, typename _DistanceType = T, typename IndexType = size_t>
714struct SO2_Adaptor
715{
716 using ElementType = T;
717 using DistanceType = _DistanceType;
718
719 const DataSource& data_source;
720
721 SO2_Adaptor(const DataSource& _data_source) : data_source(_data_source) {}
722
723 inline DistanceType evalMetric(const T* a, const IndexType b_idx, size_t size) const
724 {
725 return accum_dist(a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1), size - 1);
726 }
727
730 template <typename U, typename V>
731 inline DistanceType accum_dist(const U a, const V b, const size_t) const
732 {
733 DistanceType result = DistanceType();
734 DistanceType PI = pi_const<DistanceType>();
735 result = b - a;
736 if (result > PI)
737 result -= 2 * PI;
738 else if (result < -PI)
739 result += 2 * PI;
740 return result;
741 }
742};
743
754template <class T, class DataSource, typename _DistanceType = T, typename IndexType = size_t>
755struct SO3_Adaptor
756{
757 using ElementType = T;
758 using DistanceType = _DistanceType;
759
761
762 SO3_Adaptor(const DataSource& _data_source) : distance_L2_Simple(_data_source) {}
763
764 inline DistanceType evalMetric(const T* a, const IndexType b_idx, size_t size) const
765 {
766 return distance_L2_Simple.evalMetric(a, b_idx, size);
767 }
768
769 template <typename U, typename V>
770 inline DistanceType accum_dist(const U a, const V b, const size_t idx) const
771 {
772 return distance_L2_Simple.accum_dist(a, b, idx);
773 }
774};
775
777struct metric_L1 : public Metric
778{
779 template <class T, class DataSource, typename IndexType = size_t>
780 struct traits
781 {
783 };
784};
785
787struct metric_L2 : public Metric
788{
789 template <class T, class DataSource, typename IndexType = size_t>
790 struct traits
791 {
793 };
794};
795
798{
799 template <class T, class DataSource, typename IndexType = size_t>
800 struct traits
801 {
803 };
804};
805
806struct metric_SO2 : public Metric
807{
808 template <class T, class DataSource, typename IndexType = size_t>
809 struct traits
810 {
812 };
813};
814
815struct metric_SO3 : public Metric
816{
817 template <class T, class DataSource, typename IndexType = size_t>
818 struct traits
819 {
821 };
822};
823
825
828
829enum class KDTreeSingleIndexAdaptorFlags
830{
831 None = 0,
832 SkipInitialBuildIndex = 1
833};
834
835inline std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type operator&(
836 KDTreeSingleIndexAdaptorFlags lhs, KDTreeSingleIndexAdaptorFlags rhs)
837{
838 using underlying = typename std::underlying_type<KDTreeSingleIndexAdaptorFlags>::type;
839 return static_cast<underlying>(lhs) & static_cast<underlying>(rhs);
840}
841
843struct KDTreeSingleIndexAdaptorParams
844{
845 KDTreeSingleIndexAdaptorParams(
846 size_t _leaf_max_size = 10,
847 KDTreeSingleIndexAdaptorFlags _flags = KDTreeSingleIndexAdaptorFlags::None,
848 unsigned int _n_thread_build = 1)
849 : leaf_max_size(_leaf_max_size), flags(_flags), n_thread_build(_n_thread_build)
850 {
851 }
852
853 size_t leaf_max_size;
854 KDTreeSingleIndexAdaptorFlags flags;
855 unsigned int n_thread_build;
856};
857
859struct SearchParameters
860{
861 SearchParameters(float eps_ = 0, bool sorted_ = true) : eps(eps_), sorted(sorted_) {}
862
863 float eps;
864 bool sorted;
866};
867
868
871
887{
888 static constexpr size_t WORDSIZE = 16; // WORDSIZE must >= 8
889 static constexpr size_t BLOCKSIZE = 8192;
890
891 /* We maintain memory alignment to word boundaries by requiring that all
892 allocations be in multiples of the machine wordsize. */
893 /* Size of machine word in bytes. Must be power of 2. */
894 /* Minimum number of bytes requested at a time from the system. Must be
895 * multiple of WORDSIZE. */
896
897 using Size = size_t;
898
899 Size remaining_ = 0;
900 void* base_ = nullptr;
901 void* loc_ = nullptr;
902
903 void internal_init()
904 {
905 remaining_ = 0;
906 base_ = nullptr;
907 usedMemory = 0;
908 wastedMemory = 0;
909 }
910
911 public:
912 Size usedMemory = 0;
913 Size wastedMemory = 0;
914
918 PooledAllocator() { internal_init(); }
919
924
926 void free_all()
927 {
928 while (base_ != nullptr)
929 {
930 // Get pointer to prev block
931 void* prev = *(static_cast<void**>(base_));
932 ::free(base_);
933 base_ = prev;
934 }
935 internal_init();
936 }
937
942 void* malloc(const size_t req_size)
943 {
944 /* Round size up to a multiple of wordsize. The following expression
945 only works for WORDSIZE that is a power of 2, by masking last bits
946 of incremented size to zero.
947 */
948 const Size size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
949
950 /* Check whether a new block must be allocated. Note that the first
951 word of a block is reserved for a pointer to the previous block.
952 */
953 if (size > remaining_)
954 {
955 wastedMemory += remaining_;
956
957 /* Allocate new storage. */
958 const Size blocksize = size > BLOCKSIZE ? size + WORDSIZE : BLOCKSIZE + WORDSIZE;
959
960 // use the standard C malloc to allocate memory
961 void* m = ::malloc(blocksize);
962 if (!m)
963 {
964 throw std::bad_alloc();
965 }
966
967 /* Fill first word of new block with pointer to previous block. */
968 static_cast<void**>(m)[0] = base_;
969 base_ = m;
970
971 remaining_ = blocksize - WORDSIZE;
972 loc_ = static_cast<char*>(m) + WORDSIZE;
973 }
974 void* rloc = loc_;
975 loc_ = static_cast<char*>(loc_) + size;
976 remaining_ -= size;
977
978 usedMemory += size;
979
980 return rloc;
981 }
982
990 template <typename T>
991 T* allocate(const size_t count = 1)
992 {
993 T* mem = static_cast<T*>(this->malloc(sizeof(T) * count));
994 return mem;
995 }
996};
997
998
1001
1005template <int32_t DIM, typename T>
1007{
1008 using type = std::array<T, DIM>;
1009};
1010
1011template <typename T>
1012struct array_or_vector<-1, T>
1013{
1014 using type = std::vector<T>;
1015};
1016
1018
1033template <
1034 class Derived, typename Distance, class DatasetAdaptor, int32_t DIM = -1,
1035 typename index_t = uint32_t>
1037{
1038 public:
1041 void freeIndex(Derived& obj)
1042 {
1043 obj.pool_.free_all();
1044 obj.root_node_ = nullptr;
1045 obj.size_at_index_build_ = 0;
1046 }
1047
1048 using ElementType = typename Distance::ElementType;
1049 using DistanceType = typename Distance::DistanceType;
1050 using IndexType = index_t;
1051
1055 std::vector<IndexType> vAcc_;
1056
1057 using Offset = typename decltype(vAcc_)::size_type;
1058 using Size = typename decltype(vAcc_)::size_type;
1059 using Dimension = int32_t;
1060
1061 /*-------------------------------------------------------------------
1062 * Internal Data Structures
1063 *
1064 * "Node" below can be declared with alignas(N) to improve
1065 * cache friendliness and SIMD load/store performance.
1066 *
1067 * The optimal N depends on the underlying hardware:
1068 * + Intel x86-64: 16 for SSE, 32 for AVX/AVX2 and 64 for AVX-512
1069 * + NVIDIA Jetson: 16 for ARM + NEON and CUDA float4/
1070 * To avoid unnecessary padding, the smallest alignment
1071 * compatible with a platform's vector width should be chosen.
1072 * ------------------------------------------------------------------*/
1073 struct alignas(NANOFLANN_NODE_ALIGNMENT) Node
1074 {
1077 union
1078 {
1079 struct leaf
1080 {
1081 Offset left, right;
1082 } lr;
1083 struct nonleaf
1084 {
1085 Dimension divfeat;
1087 DistanceType divlow, divhigh;
1088 } sub;
1089 } node_type;
1090
1092 Node *child1 = nullptr, *child2 = nullptr;
1093 };
1094
1095 using NodePtr = Node*;
1096 using NodeConstPtr = const Node*;
1097
1099 {
1100 ElementType low, high;
1101 };
1102
1103 NodePtr root_node_ = nullptr;
1104
1105 Size leaf_max_size_ = 0;
1106
1110 Size size_ = 0;
1113 Dimension dim_ = 0;
1114
1117 using BoundingBox = typename array_or_vector<DIM, Interval>::type;
1118
1121 using distance_vector_t = typename array_or_vector<DIM, DistanceType>::type;
1122
1125
1134
1136 Size size(const Derived& obj) const { return obj.size_; }
1137
1139 Size veclen(const Derived& obj) const { return DIM > 0 ? DIM : obj.dim_; }
1140
1142 ElementType dataset_get(const Derived& obj, IndexType element, Dimension component) const
1143 {
1144 return obj.dataset_.kdtree_get_pt(element, component);
1145 }
1146
1151 Size usedMemory(const Derived& obj) const
1152 {
1153 return obj.pool_.usedMemory + obj.pool_.wastedMemory +
1154 obj.dataset_.kdtree_get_point_count() *
1155 sizeof(IndexType); // pool memory and vind array memory
1156 }
1157
1162 const Derived& obj, Offset ind, Size count, Dimension element, ElementType& min_elem,
1163 ElementType& max_elem) const
1164 {
1165 min_elem = dataset_get(obj, vAcc_[ind], element);
1166 max_elem = min_elem;
1167 for (Offset i = 1; i < count; ++i)
1168 {
1169 ElementType val = dataset_get(obj, vAcc_[ind + i], element);
1170 if (val < min_elem) min_elem = val;
1171 if (val > max_elem) max_elem = val;
1172 }
1173 }
1174
1184 NodePtr divideTree(Derived& obj, const Offset left, const Offset right, BoundingBox& bbox)
1185 {
1186 assert(left < obj.dataset_.kdtree_get_point_count());
1187
1188 NodePtr node = obj.pool_.template allocate<Node>(); // allocate memory
1189 const auto dims = (DIM > 0 ? DIM : obj.dim_);
1190
1191 /* If too few exemplars remain, then make this a leaf node. */
1192 if ((right - left) <= static_cast<Offset>(obj.leaf_max_size_))
1193 {
1194 node->child1 = node->child2 = nullptr; /* Mark as leaf node. */
1195 node->node_type.lr.left = left;
1196 node->node_type.lr.right = right;
1197
1198 // compute bounding-box of leaf points
1199 for (Dimension i = 0; i < dims; ++i)
1200 {
1201 bbox[i].low = dataset_get(obj, obj.vAcc_[left], i);
1202 bbox[i].high = dataset_get(obj, obj.vAcc_[left], i);
1203 }
1204 for (Offset k = left + 1; k < right; ++k)
1205 {
1206 for (Dimension i = 0; i < dims; ++i)
1207 {
1208 const auto val = dataset_get(obj, obj.vAcc_[k], i);
1209 if (bbox[i].low > val) bbox[i].low = val;
1210 if (bbox[i].high < val) bbox[i].high = val;
1211 }
1212 }
1213 }
1214 else
1215 {
1216 /* Determine the index, dimension and value for split plane */
1217 Offset idx;
1218 Dimension cutfeat;
1219 DistanceType cutval;
1220 middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox);
1221
1222 node->node_type.sub.divfeat = cutfeat;
1223
1224 /* Recurse on left */
1225 BoundingBox left_bbox(bbox);
1226 left_bbox[cutfeat].high = cutval;
1227 node->child1 = this->divideTree(obj, left, left + idx, left_bbox);
1228
1229 /* Recurse on right */
1230 BoundingBox right_bbox(bbox);
1231 right_bbox[cutfeat].low = cutval;
1232 node->child2 = this->divideTree(obj, left + idx, right, right_bbox);
1233
1234 node->node_type.sub.divlow = left_bbox[cutfeat].high;
1235 node->node_type.sub.divhigh = right_bbox[cutfeat].low;
1236
1237 for (Dimension i = 0; i < dims; ++i)
1238 {
1239 bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
1240 bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
1241 }
1242 }
1243
1244 return node;
1245 }
1246
1260 Derived& obj, const Offset left, const Offset right, BoundingBox& bbox,
1261 std::atomic<unsigned int>& thread_count, std::mutex& mutex)
1262 {
1263 std::unique_lock<std::mutex> lock(mutex);
1264 NodePtr node = obj.pool_.template allocate<Node>(); // allocate memory
1265 lock.unlock();
1266
1267 const auto dims = (DIM > 0 ? DIM : obj.dim_);
1268
1269 /* If too few exemplars remain, then make this a leaf node. */
1270 if ((right - left) <= static_cast<Offset>(obj.leaf_max_size_))
1271 {
1272 node->child1 = node->child2 = nullptr; /* Mark as leaf node. */
1273 node->node_type.lr.left = left;
1274 node->node_type.lr.right = right;
1275
1276 // compute bounding-box of leaf points
1277 for (Dimension i = 0; i < dims; ++i)
1278 {
1279 bbox[i].low = dataset_get(obj, obj.vAcc_[left], i);
1280 bbox[i].high = dataset_get(obj, obj.vAcc_[left], i);
1281 }
1282 for (Offset k = left + 1; k < right; ++k)
1283 {
1284 for (Dimension i = 0; i < dims; ++i)
1285 {
1286 const auto val = dataset_get(obj, obj.vAcc_[k], i);
1287 if (bbox[i].low > val) bbox[i].low = val;
1288 if (bbox[i].high < val) bbox[i].high = val;
1289 }
1290 }
1291 }
1292 else
1293 {
1294 /* Determine the index, dimension and value for split plane */
1295 Offset idx;
1296 Dimension cutfeat;
1297 DistanceType cutval;
1298 middleSplit_(obj, left, right - left, idx, cutfeat, cutval, bbox);
1299
1300 node->node_type.sub.divfeat = cutfeat;
1301
1302 std::future<NodePtr> right_future;
1303
1304 /* Recurse on right concurrently, if possible */
1305
1306 BoundingBox right_bbox(bbox);
1307 right_bbox[cutfeat].low = cutval;
1308 if (++thread_count < n_thread_build_)
1309 {
1310 /* Concurrent thread for right recursion */
1311
1312 right_future = std::async(
1313 std::launch::async, &KDTreeBaseClass::divideTreeConcurrent, this, std::ref(obj),
1314 left + idx, right, std::ref(right_bbox), std::ref(thread_count),
1315 std::ref(mutex));
1316 }
1317 else
1318 {
1319 --thread_count;
1320 }
1321
1322 /* Recurse on left in this thread */
1323
1324 BoundingBox left_bbox(bbox);
1325 left_bbox[cutfeat].high = cutval;
1326 node->child1 =
1327 this->divideTreeConcurrent(obj, left, left + idx, left_bbox, thread_count, mutex);
1328
1329 if (right_future.valid())
1330 {
1331 /* Block and wait for concurrent right from above */
1332
1333 node->child2 = right_future.get();
1334 --thread_count;
1335 }
1336 else
1337 {
1338 /* Otherwise, recurse on right in this thread */
1339
1340 node->child2 = this->divideTreeConcurrent(
1341 obj, left + idx, right, right_bbox, thread_count, mutex);
1342 }
1343
1344 node->node_type.sub.divlow = left_bbox[cutfeat].high;
1345 node->node_type.sub.divhigh = right_bbox[cutfeat].low;
1346
1347 for (Dimension i = 0; i < dims; ++i)
1348 {
1349 bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
1350 bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
1351 }
1352 }
1353
1354 return node;
1355 }
1356
1357 void middleSplit_(
1358 const Derived& obj, const Offset ind, const Size count, Offset& index, Dimension& cutfeat,
1359 DistanceType& cutval, const BoundingBox& bbox)
1360 {
1361 const auto dims = (DIM > 0 ? DIM : obj.dim_);
1362 const auto EPS = static_cast<DistanceType>(0.00001);
1363
1364 // Pre-compute max_span once
1365 ElementType max_span = bbox[0].high - bbox[0].low;
1366 for (Dimension i = 1; i < dims; ++i)
1367 {
1368 ElementType span = bbox[i].high - bbox[i].low;
1369 if (span > max_span) max_span = span;
1370 }
1371
1372 // Single-pass min/max computation for candidate dimensions
1373 cutfeat = 0;
1374 ElementType max_spread = -1;
1375 ElementType min_elem = 0, max_elem = 0;
1376
1377 // Only check dimensions within (1-EPS) of max_span
1378 std::vector<Dimension> candidates;
1379 candidates.reserve(dims);
1380 for (Dimension i = 0; i < dims; ++i)
1381 {
1382 if (bbox[i].high - bbox[i].low >= (1 - EPS) * max_span)
1383 {
1384 candidates.push_back(i);
1385 }
1386 }
1387
1388 // Vectorized min/max for candidates
1389 for (Dimension dim : candidates)
1390 {
1391 ElementType local_min = dataset_get(obj, vAcc_[ind], dim);
1392 ElementType local_max = local_min;
1393
1394 // Unrolled loop for better performance
1395 constexpr size_t UNROLL = 4;
1396 Offset k = 1;
1397 for (; k + UNROLL <= count; k += UNROLL)
1398 {
1399 ElementType v0 = dataset_get(obj, vAcc_[ind + k], dim);
1400 ElementType v1 = dataset_get(obj, vAcc_[ind + k + 1], dim);
1401 ElementType v2 = dataset_get(obj, vAcc_[ind + k + 2], dim);
1402 ElementType v3 = dataset_get(obj, vAcc_[ind + k + 3], dim);
1403
1404 local_min = std::min({local_min, v0, v1, v2, v3});
1405 local_max = std::max({local_max, v0, v1, v2, v3});
1406 }
1407
1408 // Handle remainder
1409 for (; k < count; ++k)
1410 {
1411 ElementType val = dataset_get(obj, vAcc_[ind + k], dim);
1412 local_min = std::min(local_min, val);
1413 local_max = std::max(local_max, val);
1414 }
1415
1416 ElementType spread = local_max - local_min;
1417 if (spread > max_spread)
1418 {
1419 cutfeat = dim;
1420 max_spread = spread;
1421 min_elem = local_min;
1422 max_elem = local_max;
1423 }
1424 }
1425
1426 // Median-of-three for better balance
1427 DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2;
1428 if (split_val < min_elem) split_val = min_elem;
1429 if (split_val > max_elem) split_val = max_elem;
1430
1431 cutval = split_val;
1432
1433 // Optimized partitioning
1434 Offset lim1, lim2;
1435 planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2);
1436
1437 index = (lim1 > count / 2) ? lim1 : (lim2 < count / 2) ? lim2 : count / 2;
1438 }
1439
1450 const Derived& obj, const Offset ind, const Size count, const Dimension cutfeat,
1451 const DistanceType& cutval, Offset& lim1, Offset& lim2)
1452 {
1453 // Dutch National Flag algorithm for three-way partitioning
1454 Offset left = 0;
1455 Offset mid = 0;
1456 Offset right = count - 1;
1457
1458 while (mid <= right)
1459 {
1460 ElementType val = dataset_get(obj, vAcc_[ind + mid], cutfeat);
1461
1462 if (val < cutval)
1463 {
1464 std::swap(vAcc_[ind + left], vAcc_[ind + mid]);
1465 left++;
1466 mid++;
1467 }
1468 else if (val > cutval)
1469 {
1470 std::swap(vAcc_[ind + mid], vAcc_[ind + right]);
1471 right--;
1472 }
1473 else
1474 {
1475 mid++;
1476 }
1477 }
1478
1479 lim1 = left;
1480 lim2 = mid;
1481 }
1482
1483 DistanceType computeInitialDistances(
1484 const Derived& obj, const ElementType* vec, distance_vector_t& dists) const
1485 {
1486 assert(vec);
1487 DistanceType dist = DistanceType();
1488
1489 for (Dimension i = 0; i < (DIM > 0 ? DIM : obj.dim_); ++i)
1490 {
1491 if (vec[i] < obj.root_bbox_[i].low)
1492 {
1493 dists[i] = obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].low, i);
1494 dist += dists[i];
1495 }
1496 if (vec[i] > obj.root_bbox_[i].high)
1497 {
1498 dists[i] = obj.distance_.accum_dist(vec[i], obj.root_bbox_[i].high, i);
1499 dist += dists[i];
1500 }
1501 }
1502 return dist;
1503 }
1504
1505 static void save_tree(const Derived& obj, std::ostream& stream, const NodeConstPtr tree)
1506 {
1507 save_value(stream, *tree);
1508 if (tree->child1 != nullptr)
1509 {
1510 save_tree(obj, stream, tree->child1);
1511 }
1512 if (tree->child2 != nullptr)
1513 {
1514 save_tree(obj, stream, tree->child2);
1515 }
1516 }
1517
1518 static void load_tree(Derived& obj, std::istream& stream, NodePtr& tree)
1519 {
1520 tree = obj.pool_.template allocate<Node>();
1521 load_value(stream, *tree);
1522 if (tree->child1 != nullptr)
1523 {
1524 load_tree(obj, stream, tree->child1);
1525 }
1526 if (tree->child2 != nullptr)
1527 {
1528 load_tree(obj, stream, tree->child2);
1529 }
1530 }
1531
1537 void saveIndex(const Derived& obj, std::ostream& stream) const
1538 {
1539 save_value(stream, obj.size_);
1540 save_value(stream, obj.dim_);
1541 save_value(stream, obj.root_bbox_);
1542 save_value(stream, obj.leaf_max_size_);
1543 save_value(stream, obj.vAcc_);
1544 if (obj.root_node_) save_tree(obj, stream, obj.root_node_);
1545 }
1546
1552 void loadIndex(Derived& obj, std::istream& stream)
1553 {
1554 load_value(stream, obj.size_);
1555 load_value(stream, obj.dim_);
1556 load_value(stream, obj.root_bbox_);
1557 load_value(stream, obj.leaf_max_size_);
1558 load_value(stream, obj.vAcc_);
1559 load_tree(obj, stream, obj.root_node_);
1560 }
1561};
1562
1565
1604template <typename Distance, class DatasetAdaptor, int32_t DIM = -1, typename index_t = uint32_t>
1606 : public KDTreeBaseClass<
1607 KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, index_t>, Distance,
1608 DatasetAdaptor, DIM, index_t>
1609{
1610 public:
1614
1616 const DatasetAdaptor& dataset_;
1617
1618 const KDTreeSingleIndexAdaptorParams indexParams;
1619
1620 Distance distance_;
1621
1622 using Base = typename nanoflann::KDTreeBaseClass<
1624 DatasetAdaptor, DIM, index_t>;
1625
1626 using Offset = typename Base::Offset;
1627 using Size = typename Base::Size;
1628 using Dimension = typename Base::Dimension;
1629
1630 using ElementType = typename Base::ElementType;
1631 using DistanceType = typename Base::DistanceType;
1632 using IndexType = typename Base::IndexType;
1633
1634 using Node = typename Base::Node;
1635 using NodePtr = Node*;
1636
1637 using Interval = typename Base::Interval;
1638
1641 using BoundingBox = typename Base::BoundingBox;
1642
1645 using distance_vector_t = typename Base::distance_vector_t;
1646
1667 template <class... Args>
1669 const Dimension dimensionality, const DatasetAdaptor& inputData,
1670 const KDTreeSingleIndexAdaptorParams& params, Args&&... args)
1671 : dataset_(inputData),
1672 indexParams(params),
1673 distance_(inputData, std::forward<Args>(args)...)
1674 {
1675 init(dimensionality, params);
1676 }
1677
1678 explicit KDTreeSingleIndexAdaptor(
1679 const Dimension dimensionality, const DatasetAdaptor& inputData,
1680 const KDTreeSingleIndexAdaptorParams& params = {})
1681 : dataset_(inputData), indexParams(params), distance_(inputData)
1682 {
1683 init(dimensionality, params);
1684 }
1685
1686 private:
1687 void init(const Dimension dimensionality, const KDTreeSingleIndexAdaptorParams& params)
1688 {
1689 Base::size_ = dataset_.kdtree_get_point_count();
1690 Base::size_at_index_build_ = Base::size_;
1691 Base::dim_ = dimensionality;
1692 if (DIM > 0) Base::dim_ = DIM;
1693 Base::leaf_max_size_ = params.leaf_max_size;
1694 if (params.n_thread_build > 0)
1695 {
1696 Base::n_thread_build_ = params.n_thread_build;
1697 }
1698 else
1699 {
1700 Base::n_thread_build_ = std::max(std::thread::hardware_concurrency(), 1u);
1701 }
1702
1703 if (!(params.flags & KDTreeSingleIndexAdaptorFlags::SkipInitialBuildIndex))
1704 {
1705 // Build KD-tree:
1706 buildIndex();
1707 }
1708 }
1709
1710 public:
1715 {
1716 Base::size_ = dataset_.kdtree_get_point_count();
1717 Base::size_at_index_build_ = Base::size_;
1718 init_vind();
1719 this->freeIndex(*this);
1720 Base::size_at_index_build_ = Base::size_;
1721 if (Base::size_ == 0) return;
1722 computeBoundingBox(Base::root_bbox_);
1723 // construct the tree
1724 if (Base::n_thread_build_ == 1)
1725 {
1726 Base::root_node_ = this->divideTree(*this, 0, Base::size_, Base::root_bbox_);
1727 }
1728 else
1729 {
1730#ifndef NANOFLANN_NO_THREADS
1731 std::atomic<unsigned int> thread_count(0u);
1732 std::mutex mutex;
1733 Base::root_node_ = this->divideTreeConcurrent(
1734 *this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
1735#else /* NANOFLANN_NO_THREADS */
1736 throw std::runtime_error("Multithreading is disabled");
1737#endif /* NANOFLANN_NO_THREADS */
1738 }
1739 }
1740
1743
1760 template <typename RESULTSET>
1762 RESULTSET& result, const ElementType* vec, const SearchParameters& searchParams = {}) const
1763 {
1764 assert(vec);
1765 if (this->size(*this) == 0) return false;
1766 if (!Base::root_node_)
1767 throw std::runtime_error(
1768 "[nanoflann] findNeighbors() called before building the "
1769 "index.");
1770 float epsError = 1 + searchParams.eps;
1771
1772 // fixed or variable-sized container (depending on DIM)
1773 distance_vector_t dists;
1774 // Fill it with zeros.
1775 auto zero = static_cast<typename RESULTSET::DistanceType>(0);
1776 assign(dists, (DIM > 0 ? DIM : Base::dim_), zero);
1777 DistanceType dist = this->computeInitialDistances(*this, vec, dists);
1778 searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
1779
1780 if (searchParams.sorted) result.sort();
1781
1782 return result.full();
1783 }
1784
1800 template <typename RESULTSET>
1801 Size findWithinBox(RESULTSET& result, const BoundingBox& bbox) const
1802 {
1803 if (this->size(*this) == 0) return 0;
1804 if (!Base::root_node_)
1805 throw std::runtime_error(
1806 "[nanoflann] findWithinBox() called before building the "
1807 "index.");
1808
1809 std::stack<NodePtr> stack;
1810 stack.push(Base::root_node_);
1811
1812 while (!stack.empty())
1813 {
1814 const NodePtr node = stack.top();
1815 stack.pop();
1816
1817 // If this is a leaf node, then do check and return.
1818 if (!node->child1) // (if one node is nullptr, both are)
1819 {
1820 for (Offset i = node->node_type.lr.left; i < node->node_type.lr.right; ++i)
1821 {
1822 if (contains(bbox, Base::vAcc_[i]))
1823 {
1824 if (!result.addPoint(0, Base::vAcc_[i]))
1825 {
1826 // the resultset doesn't want to receive any more
1827 // points, we're done searching!
1828 return result.size();
1829 }
1830 }
1831 }
1832 }
1833 else
1834 {
1835 const int idx = node->node_type.sub.divfeat;
1836 const auto low_bound = node->node_type.sub.divlow;
1837 const auto high_bound = node->node_type.sub.divhigh;
1838
1839 if (bbox[idx].low <= low_bound) stack.push(node->child1);
1840 if (bbox[idx].high >= high_bound) stack.push(node->child2);
1841 }
1842 }
1843
1844 return result.size();
1845 }
1846
1863 const ElementType* query_point, const Size num_closest, IndexType* out_indices,
1864 DistanceType* out_distances) const
1865 {
1867 resultSet.init(out_indices, out_distances);
1868 findNeighbors(resultSet, query_point);
1869 return resultSet.size();
1870 }
1871
1892 const ElementType* query_point, const DistanceType& radius,
1893 std::vector<ResultItem<IndexType, DistanceType>>& IndicesDists,
1894 const SearchParameters& searchParams = {}) const
1895 {
1896 RadiusResultSet<DistanceType, IndexType> resultSet(radius, IndicesDists);
1897 const Size nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);
1898 return nFound;
1899 }
1900
1906 template <class SEARCH_CALLBACK>
1908 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
1909 const SearchParameters& searchParams = {}) const
1910 {
1911 findNeighbors(resultSet, query_point, searchParams);
1912 return resultSet.size();
1913 }
1914
1932 const ElementType* query_point, const Size num_closest, IndexType* out_indices,
1933 DistanceType* out_distances, const DistanceType& radius) const
1934 {
1935 nanoflann::RKNNResultSet<DistanceType, IndexType> resultSet(num_closest, radius);
1936 resultSet.init(out_indices, out_distances);
1937 findNeighbors(resultSet, query_point);
1938 return resultSet.size();
1939 }
1940
1942
1943 public:
1947 {
1948 // Create a permutable array of indices to the input vectors.
1949 Base::size_ = dataset_.kdtree_get_point_count();
1950 if (Base::vAcc_.size() != Base::size_) Base::vAcc_.resize(Base::size_);
1951 for (IndexType i = 0; i < static_cast<IndexType>(Base::size_); i++) Base::vAcc_[i] = i;
1952 }
1953
1954 void computeBoundingBox(BoundingBox& bbox)
1955 {
1956 const auto dims = (DIM > 0 ? DIM : Base::dim_);
1957 resize(bbox, dims);
1958 if (dataset_.kdtree_get_bbox(bbox))
1959 {
1960 // Done! It was implemented in derived class
1961 }
1962 else
1963 {
1964 const Size N = dataset_.kdtree_get_point_count();
1965 if (!N)
1966 throw std::runtime_error(
1967 "[nanoflann] computeBoundingBox() called but "
1968 "no data points found.");
1969 for (Dimension i = 0; i < dims; ++i)
1970 {
1971 bbox[i].low = bbox[i].high = this->dataset_get(*this, Base::vAcc_[0], i);
1972 }
1973 for (Offset k = 1; k < N; ++k)
1974 {
1975 for (Dimension i = 0; i < dims; ++i)
1976 {
1977 const auto val = this->dataset_get(*this, Base::vAcc_[k], i);
1978 if (val < bbox[i].low) bbox[i].low = val;
1979 if (val > bbox[i].high) bbox[i].high = val;
1980 }
1981 }
1982 }
1983 }
1984
1985 bool contains(const BoundingBox& bbox, IndexType idx) const
1986 {
1987 const auto dims = (DIM > 0 ? DIM : Base::dim_);
1988 for (Dimension i = 0; i < dims; ++i)
1989 {
1990 const auto point = this->dataset_.kdtree_get_pt(idx, i);
1991 if (point < bbox[i].low || point > bbox[i].high) return false;
1992 }
1993 return true;
1994 }
1995
2002 template <class RESULTSET>
2004 RESULTSET& result_set, const ElementType* vec, const NodePtr node, DistanceType mindist,
2005 distance_vector_t& dists, const float epsError) const
2006 {
2007 // If this is a leaf node, then do check and return.
2008 if (!node->child1) // (if one node is nullptr, both are)
2009 {
2010 for (Offset i = node->node_type.lr.left; i < node->node_type.lr.right; ++i)
2011 {
2012 const IndexType accessor = Base::vAcc_[i]; // reorder... : i;
2013 DistanceType dist =
2014 distance_.evalMetric(vec, accessor, (DIM > 0 ? DIM : Base::dim_));
2015 if (dist < result_set.worstDist())
2016 {
2017 if (!result_set.addPoint(dist, Base::vAcc_[i]))
2018 {
2019 // the resultset doesn't want to receive any more
2020 // points, we're done searching!
2021 return false;
2022 }
2023 }
2024 }
2025 return true;
2026 }
2027
2028 /* Which child branch should be taken first? */
2029 Dimension idx = node->node_type.sub.divfeat;
2030 ElementType val = vec[idx];
2031 DistanceType diff1 = val - node->node_type.sub.divlow;
2032 DistanceType diff2 = val - node->node_type.sub.divhigh;
2033
2034 NodePtr bestChild;
2035 NodePtr otherChild;
2036 DistanceType cut_dist;
2037 if ((diff1 + diff2) < 0)
2038 {
2039 bestChild = node->child1;
2040 otherChild = node->child2;
2041 cut_dist = distance_.accum_dist(val, node->node_type.sub.divhigh, idx);
2042 }
2043 else
2044 {
2045 bestChild = node->child2;
2046 otherChild = node->child1;
2047 cut_dist = distance_.accum_dist(val, node->node_type.sub.divlow, idx);
2048 }
2049
2050 /* Call recursively to search next level down. */
2051 if (!searchLevel(result_set, vec, bestChild, mindist, dists, epsError))
2052 {
2053 // the resultset doesn't want to receive any more points, we're done
2054 // searching!
2055 return false;
2056 }
2057
2058 DistanceType dst = dists[idx];
2059 mindist = mindist + cut_dist - dst;
2060 dists[idx] = cut_dist;
2061 if (mindist * epsError <= result_set.worstDist())
2062 {
2063 if (!searchLevel(result_set, vec, otherChild, mindist, dists, epsError))
2064 {
2065 // the resultset doesn't want to receive any more points, we're
2066 // done searching!
2067 return false;
2068 }
2069 }
2070 dists[idx] = dst;
2071 return true;
2072 }
2073
2074 public:
2080 void saveIndex(std::ostream& stream) const { Base::saveIndex(*this, stream); }
2081
2087 void loadIndex(std::istream& stream) { Base::loadIndex(*this, stream); }
2088
2089}; // class KDTree
2090
2128template <typename Distance, class DatasetAdaptor, int32_t DIM = -1, typename IndexType = uint32_t>
2130 : public KDTreeBaseClass<
2131 KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>, Distance,
2132 DatasetAdaptor, DIM, IndexType>
2133{
2134 public:
2138 const DatasetAdaptor& dataset_;
2139
2140 KDTreeSingleIndexAdaptorParams index_params_;
2141
2142 std::vector<int>& treeIndex_;
2143
2144 Distance distance_;
2145
2146 using Base = typename nanoflann::KDTreeBaseClass<
2148 Distance, DatasetAdaptor, DIM, IndexType>;
2149
2150 using ElementType = typename Base::ElementType;
2151 using DistanceType = typename Base::DistanceType;
2152
2153 using Offset = typename Base::Offset;
2154 using Size = typename Base::Size;
2155 using Dimension = typename Base::Dimension;
2156
2157 using Node = typename Base::Node;
2158 using NodePtr = Node*;
2159
2160 using Interval = typename Base::Interval;
2163 using BoundingBox = typename Base::BoundingBox;
2164
2167 using distance_vector_t = typename Base::distance_vector_t;
2168
2185 const Dimension dimensionality, const DatasetAdaptor& inputData,
2186 std::vector<int>& treeIndex,
2188 : dataset_(inputData), index_params_(params), treeIndex_(treeIndex), distance_(inputData)
2189 {
2190 Base::size_ = 0;
2191 Base::size_at_index_build_ = 0;
2192 for (auto& v : Base::root_bbox_) v = {};
2193 Base::dim_ = dimensionality;
2194 if (DIM > 0) Base::dim_ = DIM;
2195 Base::leaf_max_size_ = params.leaf_max_size;
2196 if (params.n_thread_build > 0)
2197 {
2198 Base::n_thread_build_ = params.n_thread_build;
2199 }
2200 else
2201 {
2202 Base::n_thread_build_ = std::max(std::thread::hardware_concurrency(), 1u);
2203 }
2204 }
2205
2208
2211 {
2213 std::swap(Base::vAcc_, tmp.Base::vAcc_);
2214 std::swap(Base::leaf_max_size_, tmp.Base::leaf_max_size_);
2215 std::swap(index_params_, tmp.index_params_);
2216 std::swap(treeIndex_, tmp.treeIndex_);
2217 std::swap(Base::size_, tmp.Base::size_);
2218 std::swap(Base::size_at_index_build_, tmp.Base::size_at_index_build_);
2219 std::swap(Base::root_node_, tmp.Base::root_node_);
2220 std::swap(Base::root_bbox_, tmp.Base::root_bbox_);
2221 std::swap(Base::pool_, tmp.Base::pool_);
2222 return *this;
2223 }
2224
2229 {
2230 Base::size_ = Base::vAcc_.size();
2231 this->freeIndex(*this);
2232 Base::size_at_index_build_ = Base::size_;
2233 if (Base::size_ == 0) return;
2234 computeBoundingBox(Base::root_bbox_);
2235 // construct the tree
2236 if (Base::n_thread_build_ == 1)
2237 {
2238 Base::root_node_ = this->divideTree(*this, 0, Base::size_, Base::root_bbox_);
2239 }
2240 else
2241 {
2242#ifndef NANOFLANN_NO_THREADS
2243 std::atomic<unsigned int> thread_count(0u);
2244 std::mutex mutex;
2245 Base::root_node_ = this->divideTreeConcurrent(
2246 *this, 0, Base::size_, Base::root_bbox_, thread_count, mutex);
2247#else /* NANOFLANN_NO_THREADS */
2248 throw std::runtime_error("Multithreading is disabled");
2249#endif /* NANOFLANN_NO_THREADS */
2250 }
2251 }
2252
2255
2276 template <typename RESULTSET>
2278 RESULTSET& result, const ElementType* vec, const SearchParameters& searchParams = {}) const
2279 {
2280 assert(vec);
2281 if (this->size(*this) == 0) return false;
2282 if (!Base::root_node_) return false;
2283 float epsError = 1 + searchParams.eps;
2284
2285 // fixed or variable-sized container (depending on DIM)
2286 distance_vector_t dists;
2287 // Fill it with zeros.
2288 assign(
2289 dists, (DIM > 0 ? DIM : Base::dim_),
2290 static_cast<typename distance_vector_t::value_type>(0));
2291 DistanceType dist = this->computeInitialDistances(*this, vec, dists);
2292 searchLevel(result, vec, Base::root_node_, dist, dists, epsError);
2293
2294 if (searchParams.sorted) result.sort();
2295
2296 return result.full();
2297 }
2298
2314 const ElementType* query_point, const Size num_closest, IndexType* out_indices,
2315 DistanceType* out_distances, const SearchParameters& searchParams = {}) const
2316 {
2318 resultSet.init(out_indices, out_distances);
2319 findNeighbors(resultSet, query_point, searchParams);
2320 return resultSet.size();
2321 }
2322
2343 const ElementType* query_point, const DistanceType& radius,
2344 std::vector<ResultItem<IndexType, DistanceType>>& IndicesDists,
2345 const SearchParameters& searchParams = {}) const
2346 {
2347 RadiusResultSet<DistanceType, IndexType> resultSet(radius, IndicesDists);
2348 const size_t nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);
2349 return nFound;
2350 }
2351
2357 template <class SEARCH_CALLBACK>
2359 const ElementType* query_point, SEARCH_CALLBACK& resultSet,
2360 const SearchParameters& searchParams = {}) const
2361 {
2362 findNeighbors(resultSet, query_point, searchParams);
2363 return resultSet.size();
2364 }
2365
2367
2368 public:
2369 void computeBoundingBox(BoundingBox& bbox)
2370 {
2371 const auto dims = (DIM > 0 ? DIM : Base::dim_);
2372 resize(bbox, dims);
2373
2374 if (dataset_.kdtree_get_bbox(bbox))
2375 {
2376 // Done! It was implemented in derived class
2377 }
2378 else
2379 {
2380 const Size N = Base::size_;
2381 if (!N)
2382 throw std::runtime_error(
2383 "[nanoflann] computeBoundingBox() called but "
2384 "no data points found.");
2385 for (Dimension i = 0; i < dims; ++i)
2386 {
2387 bbox[i].low = bbox[i].high = this->dataset_get(*this, Base::vAcc_[0], i);
2388 }
2389 for (Offset k = 1; k < N; ++k)
2390 {
2391 for (Dimension i = 0; i < dims; ++i)
2392 {
2393 const auto val = this->dataset_get(*this, Base::vAcc_[k], i);
2394 if (val < bbox[i].low) bbox[i].low = val;
2395 if (val > bbox[i].high) bbox[i].high = val;
2396 }
2397 }
2398 }
2399 }
2400
2405 template <class RESULTSET>
2407 RESULTSET& result_set, const ElementType* vec, const NodePtr node, DistanceType mindist,
2408 distance_vector_t& dists, const float epsError) const
2409 {
2410 // If this is a leaf node, then do check and return.
2411 if (!node->child1) // (if one node is nullptr, both are)
2412 {
2413 for (Offset i = node->node_type.lr.left; i < node->node_type.lr.right; ++i)
2414 {
2415 const IndexType index = Base::vAcc_[i]; // reorder... : i;
2416 if (treeIndex_[index] == -1) continue;
2417 DistanceType dist = distance_.evalMetric(vec, index, (DIM > 0 ? DIM : Base::dim_));
2418 if (dist < result_set.worstDist())
2419 {
2420 if (!result_set.addPoint(
2421 static_cast<typename RESULTSET::DistanceType>(dist),
2422 static_cast<typename RESULTSET::IndexType>(Base::vAcc_[i])))
2423 {
2424 // the resultset doesn't want to receive any more
2425 // points, we're done searching!
2426 return; // false;
2427 }
2428 }
2429 }
2430 return;
2431 }
2432
2433 /* Which child branch should be taken first? */
2434 Dimension idx = node->node_type.sub.divfeat;
2435 ElementType val = vec[idx];
2436 DistanceType diff1 = val - node->node_type.sub.divlow;
2437 DistanceType diff2 = val - node->node_type.sub.divhigh;
2438
2439 NodePtr bestChild;
2440 NodePtr otherChild;
2441 DistanceType cut_dist;
2442 if ((diff1 + diff2) < 0)
2443 {
2444 bestChild = node->child1;
2445 otherChild = node->child2;
2446 cut_dist = distance_.accum_dist(val, node->node_type.sub.divhigh, idx);
2447 }
2448 else
2449 {
2450 bestChild = node->child2;
2451 otherChild = node->child1;
2452 cut_dist = distance_.accum_dist(val, node->node_type.sub.divlow, idx);
2453 }
2454
2455 /* Call recursively to search next level down. */
2456 searchLevel(result_set, vec, bestChild, mindist, dists, epsError);
2457
2458 DistanceType dst = dists[idx];
2459 mindist = mindist + cut_dist - dst;
2460 dists[idx] = cut_dist;
2461 if (mindist * epsError <= result_set.worstDist())
2462 {
2463 searchLevel(result_set, vec, otherChild, mindist, dists, epsError);
2464 }
2465 dists[idx] = dst;
2466 }
2467
2468 public:
2474 void saveIndex(std::ostream& stream) { saveIndex(*this, stream); }
2475
2481 void loadIndex(std::istream& stream) { loadIndex(*this, stream); }
2482};
2483
2498template <typename Distance, class DatasetAdaptor, int32_t DIM = -1, typename IndexType = uint32_t>
2500{
2501 public:
2502 using ElementType = typename Distance::ElementType;
2503 using DistanceType = typename Distance::DistanceType;
2504
2505 using Offset = typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Offset;
2506 using Size = typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Size;
2507 using Dimension =
2508 typename KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>::Dimension;
2509
2510 protected:
2511 Size leaf_max_size_;
2512 Size treeCount_;
2513 Size pointCount_;
2514
2518 const DatasetAdaptor& dataset_;
2519
2522 std::vector<int> treeIndex_;
2523 std::unordered_set<int> removedPoints_;
2524
2525 KDTreeSingleIndexAdaptorParams index_params_;
2526
2527 Dimension dim_;
2528
2529 using index_container_t =
2531 std::vector<index_container_t> index_;
2532
2533 public:
2536 const std::vector<index_container_t>& getAllIndices() const { return index_; }
2537
2538 private:
2540 int First0Bit(IndexType num)
2541 {
2542 int pos = 0;
2543 while (num & 1)
2544 {
2545 num = num >> 1;
2546 pos++;
2547 }
2548 return pos;
2549 }
2550
2552 void init()
2553 {
2554 using my_kd_tree_t =
2555 KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>;
2556 std::vector<my_kd_tree_t> index(
2557 treeCount_, my_kd_tree_t(dim_ /*dim*/, dataset_, treeIndex_, index_params_));
2558 index_ = index;
2559 }
2560
2561 public:
2562 Distance distance_;
2563
2580 const int dimensionality, const DatasetAdaptor& inputData,
2582 const size_t maximumPointCount = 1000000000U)
2583 : dataset_(inputData), index_params_(params), distance_(inputData)
2584 {
2585 treeCount_ = static_cast<size_t>(std::log2(maximumPointCount)) + 1;
2586 pointCount_ = 0U;
2587 dim_ = dimensionality;
2588 treeIndex_.clear();
2589 if (DIM > 0) dim_ = DIM;
2590 leaf_max_size_ = params.leaf_max_size;
2591 init();
2592 const size_t num_initial_points = dataset_.kdtree_get_point_count();
2593 if (num_initial_points > 0)
2594 {
2595 addPoints(0, num_initial_points - 1);
2596 }
2597 }
2598
2602
2604 void addPoints(IndexType start, IndexType end)
2605 {
2606 const Size count = end - start + 1;
2607 int maxIndex = 0;
2608 treeIndex_.resize(treeIndex_.size() + count);
2609 for (IndexType idx = start; idx <= end; idx++)
2610 {
2611 const int pos = First0Bit(pointCount_);
2612 maxIndex = std::max(pos, maxIndex);
2613 treeIndex_[pointCount_] = pos;
2614
2615 const auto it = removedPoints_.find(idx);
2616 if (it != removedPoints_.end())
2617 {
2618 removedPoints_.erase(it);
2619 treeIndex_[idx] = pos;
2620 }
2621
2622 for (int i = 0; i < pos; i++)
2623 {
2624 for (int j = 0; j < static_cast<int>(index_[i].vAcc_.size()); j++)
2625 {
2626 index_[pos].vAcc_.push_back(index_[i].vAcc_[j]);
2627 if (treeIndex_[index_[i].vAcc_[j]] != -1) treeIndex_[index_[i].vAcc_[j]] = pos;
2628 }
2629 index_[i].vAcc_.clear();
2630 }
2631 index_[pos].vAcc_.push_back(idx);
2632 pointCount_++;
2633 }
2634
2635 for (int i = 0; i <= maxIndex; ++i)
2636 {
2637 index_[i].freeIndex(index_[i]);
2638 if (!index_[i].vAcc_.empty()) index_[i].buildIndex();
2639 }
2640 }
2641
2643 void removePoint(size_t idx)
2644 {
2645 if (idx >= pointCount_) return;
2646 removedPoints_.insert(idx);
2647 treeIndex_[idx] = -1;
2648 }
2649
2666 template <typename RESULTSET>
2668 RESULTSET& result, const ElementType* vec, const SearchParameters& searchParams = {}) const
2669 {
2670 for (size_t i = 0; i < treeCount_; i++)
2671 {
2672 index_[i].findNeighbors(result, &vec[0], searchParams);
2673 }
2674 return result.full();
2675 }
2676};
2677
2703template <
2704 class MatrixType, int32_t DIM = -1, class Distance = nanoflann::metric_L2,
2705 bool row_major = true>
2707{
2709 using num_t = typename MatrixType::Scalar;
2710 using IndexType = typename MatrixType::Index;
2711 using metric_t = typename Distance::template traits<num_t, self_t, IndexType>::distance_t;
2712
2713 using index_t = KDTreeSingleIndexAdaptor<
2714 metric_t, self_t, row_major ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime,
2715 IndexType>;
2716
2717 index_t* index_;
2719
2720 using Offset = typename index_t::Offset;
2721 using Size = typename index_t::Size;
2722 using Dimension = typename index_t::Dimension;
2723
2726 const Dimension dimensionality, const std::reference_wrapper<const MatrixType>& mat,
2727 const int leaf_max_size = 10, const unsigned int n_thread_build = 1)
2728 : m_data_matrix(mat)
2729 {
2730 const auto dims = row_major ? mat.get().cols() : mat.get().rows();
2731 if (static_cast<Dimension>(dims) != dimensionality)
2732 throw std::runtime_error(
2733 "Error: 'dimensionality' must match column count in data "
2734 "matrix");
2735 if (DIM > 0 && static_cast<int32_t>(dims) != DIM)
2736 throw std::runtime_error(
2737 "Data set dimensionality does not match the 'DIM' template "
2738 "argument");
2739 index_ = new index_t(
2740 dims, *this /* adaptor */,
2742 leaf_max_size, nanoflann::KDTreeSingleIndexAdaptorFlags::None, n_thread_build));
2743 }
2744
2745 public:
2747 KDTreeEigenMatrixAdaptor(const self_t&) = delete;
2748
2749 ~KDTreeEigenMatrixAdaptor() { delete index_; }
2750
2751 const std::reference_wrapper<const MatrixType> m_data_matrix;
2752
2761 void query(
2762 const num_t* query_point, const Size num_closest, IndexType* out_indices,
2763 num_t* out_distances) const
2764 {
2765 nanoflann::KNNResultSet<num_t, IndexType> resultSet(num_closest);
2766 resultSet.init(out_indices, out_distances);
2767 index_->findNeighbors(resultSet, query_point);
2768 }
2769
2772
2773 inline const self_t& derived() const noexcept { return *this; }
2774 inline self_t& derived() noexcept { return *this; }
2775
2776 // Must return the number of data points
2777 inline Size kdtree_get_point_count() const
2778 {
2779 if (row_major)
2780 return m_data_matrix.get().rows();
2781 else
2782 return m_data_matrix.get().cols();
2783 }
2784
2785 // Returns the dim'th component of the idx'th point in the class:
2786 inline num_t kdtree_get_pt(const IndexType idx, size_t dim) const
2787 {
2788 if (row_major)
2789 return m_data_matrix.get().coeff(idx, IndexType(dim));
2790 else
2791 return m_data_matrix.get().coeff(IndexType(dim), idx);
2792 }
2793
2794 // Optional bounding-box computation: return false to default to a standard
2795 // bbox computation loop.
2796 // Return true if the BBOX was already computed by the class and returned
2797 // in "bb" so it can be avoided to redo it again. Look at bb.size() to
2798 // find out the expected dimensionality (e.g. 2 or 3 for point clouds)
2799 template <class BBOX>
2800 inline bool kdtree_get_bbox(BBOX& /*bb*/) const
2801 {
2802 return false;
2803 }
2804
2806
2807}; // end of KDTreeEigenMatrixAdaptor
2808
2809 // end of grouping
2811} // namespace nanoflann
2812
2813#undef NANOFLANN_RESTRICT
Definition nanoflann.hpp:1037
void freeIndex(Derived &obj)
Definition nanoflann.hpp:1041
Size veclen(const Derived &obj) const
Definition nanoflann.hpp:1139
void computeMinMax(const Derived &obj, Offset ind, Size count, Dimension element, ElementType &min_elem, ElementType &max_elem) const
Definition nanoflann.hpp:1161
BoundingBox root_bbox_
Definition nanoflann.hpp:1124
void saveIndex(const Derived &obj, std::ostream &stream) const
Definition nanoflann.hpp:1537
Dimension dim_
Dimensionality of each data point.
Definition nanoflann.hpp:1113
typename array_or_vector< DIM, DistanceType >::type distance_vector_t
Definition nanoflann.hpp:1121
void planeSplit(const Derived &obj, const Offset ind, const Size count, const Dimension cutfeat, const DistanceType &cutval, Offset &lim1, Offset &lim2)
Definition nanoflann.hpp:1449
Size n_thread_build_
Number of thread for concurrent tree build.
Definition nanoflann.hpp:1108
NodePtr divideTree(Derived &obj, const Offset left, const Offset right, BoundingBox &bbox)
Definition nanoflann.hpp:1184
std::vector< IndexType > vAcc_
Definition nanoflann.hpp:1055
Size size(const Derived &obj) const
Definition nanoflann.hpp:1136
Size size_at_index_build_
Number of points in the dataset when the index was built.
Definition nanoflann.hpp:1112
NodePtr divideTreeConcurrent(Derived &obj, const Offset left, const Offset right, BoundingBox &bbox, std::atomic< unsigned int > &thread_count, std::mutex &mutex)
Definition nanoflann.hpp:1259
Size size_
Number of current points in the dataset.
Definition nanoflann.hpp:1110
Size usedMemory(const Derived &obj) const
Definition nanoflann.hpp:1151
void loadIndex(Derived &obj, std::istream &stream)
Definition nanoflann.hpp:1552
PooledAllocator pool_
Definition nanoflann.hpp:1133
ElementType dataset_get(const Derived &obj, IndexType element, Dimension component) const
Helper accessor to the dataset points:
Definition nanoflann.hpp:1142
typename array_or_vector< DIM, Interval >::type BoundingBox
Definition nanoflann.hpp:1117
Definition nanoflann.hpp:1609
bool searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindist, distance_vector_t &dists, const float epsError) const
Definition nanoflann.hpp:2003
void saveIndex(std::ostream &stream) const
Definition nanoflann.hpp:2080
Size findWithinBox(RESULTSET &result, const BoundingBox &bbox) const
Definition nanoflann.hpp:1801
Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:1891
void buildIndex()
Definition nanoflann.hpp:1714
KDTreeSingleIndexAdaptor(const KDTreeSingleIndexAdaptor< Distance, DatasetAdaptor, DIM, index_t > &)=delete
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:1761
Size rknnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const DistanceType &radius) const
Definition nanoflann.hpp:1931
Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:1907
typename Base::distance_vector_t distance_vector_t
Definition nanoflann.hpp:1645
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:2087
typename Base::BoundingBox BoundingBox
Definition nanoflann.hpp:1641
KDTreeSingleIndexAdaptor(const Dimension dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params, Args &&... args)
Definition nanoflann.hpp:1668
Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances) const
Definition nanoflann.hpp:1862
Definition nanoflann.hpp:2133
Size radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector< ResultItem< IndexType, DistanceType > > &IndicesDists, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2342
KDTreeSingleIndexDynamicAdaptor_(const Dimension dimensionality, const DatasetAdaptor &inputData, std::vector< int > &treeIndex, const KDTreeSingleIndexAdaptorParams &params=KDTreeSingleIndexAdaptorParams())
Definition nanoflann.hpp:2184
typename Base::BoundingBox BoundingBox
Definition nanoflann.hpp:2163
Size radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2358
KDTreeSingleIndexDynamicAdaptor_(const KDTreeSingleIndexDynamicAdaptor_ &rhs)=default
void buildIndex()
Definition nanoflann.hpp:2228
void saveIndex(std::ostream &stream)
Definition nanoflann.hpp:2474
typename Base::distance_vector_t distance_vector_t
Definition nanoflann.hpp:2167
void loadIndex(std::istream &stream)
Definition nanoflann.hpp:2481
Size knnSearch(const ElementType *query_point, const Size num_closest, IndexType *out_indices, DistanceType *out_distances, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2313
void searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindist, distance_vector_t &dists, const float epsError) const
Definition nanoflann.hpp:2406
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2277
KDTreeSingleIndexDynamicAdaptor_ operator=(const KDTreeSingleIndexDynamicAdaptor_ &rhs)
Definition nanoflann.hpp:2210
bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParameters &searchParams={}) const
Definition nanoflann.hpp:2667
const DatasetAdaptor & dataset_
The source of our data.
Definition nanoflann.hpp:2518
void removePoint(size_t idx)
Definition nanoflann.hpp:2643
void addPoints(IndexType start, IndexType end)
Definition nanoflann.hpp:2604
KDTreeSingleIndexDynamicAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params=KDTreeSingleIndexAdaptorParams(), const size_t maximumPointCount=1000000000U)
Definition nanoflann.hpp:2579
std::vector< int > treeIndex_
Definition nanoflann.hpp:2522
const std::vector< index_container_t > & getAllIndices() const
Definition nanoflann.hpp:2536
Dimension dim_
Dimensionality of each data point.
Definition nanoflann.hpp:2527
KDTreeSingleIndexDynamicAdaptor(const KDTreeSingleIndexDynamicAdaptor< Distance, DatasetAdaptor, DIM, IndexType > &)=delete
Definition nanoflann.hpp:214
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:248
DistanceType worstDist() const noexcept
Returns the worst distance among found solutions if the search result is full, or the maximum possibl...
Definition nanoflann.hpp:284
Definition nanoflann.hpp:887
~PooledAllocator()
Definition nanoflann.hpp:923
void free_all()
Definition nanoflann.hpp:926
void * malloc(const size_t req_size)
Definition nanoflann.hpp:942
T * allocate(const size_t count=1)
Definition nanoflann.hpp:991
PooledAllocator()
Definition nanoflann.hpp:918
Definition nanoflann.hpp:299
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:339
DistanceType worstDist() const noexcept
Returns the worst distance among found solutions if the search result is full, or the maximum possibl...
Definition nanoflann.hpp:375
Definition nanoflann.hpp:391
ResultItem< IndexType, DistanceType > worst_item() const
Definition nanoflann.hpp:432
bool addPoint(DistanceType dist, IndexType index)
Definition nanoflann.hpp:420
std::enable_if< has_assign< Container >::value, void >::type assign(Container &c, const size_t nElements, const T &value)
Definition nanoflann.hpp:161
std::enable_if< has_resize< Container >::value, void >::type resize(Container &c, const size_t nElements)
Definition nanoflann.hpp:140
constexpr T pi_const()
Definition nanoflann.hpp:107
Definition nanoflann.hpp:179
bool operator()(const PairType &p1, const PairType &p2) const
Definition nanoflann.hpp:182
Definition nanoflann.hpp:1099
Definition nanoflann.hpp:1074
Offset right
Indices of points in leaf node.
Definition nanoflann.hpp:1081
Dimension divfeat
Dimension used for subdivision. The values used for subdivision.
Definition nanoflann.hpp:1085
Node * child1
Definition nanoflann.hpp:1092
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:2761
KDTreeEigenMatrixAdaptor(const self_t &)=delete
typename index_t::Offset Offset
Definition nanoflann.hpp:2720
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:2725
Definition nanoflann.hpp:844
Definition nanoflann.hpp:499
Definition nanoflann.hpp:589
Definition nanoflann.hpp:676
Definition nanoflann.hpp:484
Definition nanoflann.hpp:198
DistanceType second
Distance from sample to query point.
Definition nanoflann.hpp:205
IndexType first
Index of the sample in the dataset.
Definition nanoflann.hpp:204
Definition nanoflann.hpp:715
DistanceType accum_dist(const U a, const V b, const size_t) const
Definition nanoflann.hpp:731
Definition nanoflann.hpp:756
Definition nanoflann.hpp:860
bool sorted
only for radius search, require neighbours sorted by distance (default: true)
Definition nanoflann.hpp:864
float eps
search for eps-approximate neighbours (default: 0)
Definition nanoflann.hpp:863
Definition nanoflann.hpp:1007
Definition nanoflann.hpp:128
Definition nanoflann.hpp:118
Definition nanoflann.hpp:781
Definition nanoflann.hpp:778
Definition nanoflann.hpp:791
Definition nanoflann.hpp:801
Definition nanoflann.hpp:798
Definition nanoflann.hpp:788
Definition nanoflann.hpp:810
Definition nanoflann.hpp:807
Definition nanoflann.hpp:819
Definition nanoflann.hpp:816