12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057 |
- /************************************************************
- *
- * Copyright (c) 2021, University of California, Los Angeles
- *
- * Authors: Kenny J. Chen, Brett T. Lopez
- * Contact: kennyjchen@ucla.edu, btlopez@ucla.edu
- *
- ***********************************************************/
- /***********************************************************************
- * Software License Agreement (BSD License)
- *
- * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
- * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
- * Copyright 2011-2021 Jose Luis Blanco (joseluisblancoc@gmail.com).
- * All rights reserved.
- *
- * THE BSD LICENSE
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *************************************************************************/
- /** \mainpage nanoflann C++ API documentation
- * nanoflann is a C++ header-only library for building KD-Trees, mostly
- * optimized for 2D or 3D point clouds.
- *
- * nanoflann does not require compiling or installing, just an
- * #include <nanoflann.hpp> in your code.
- *
- * See:
- * - <a href="modules.html" >C++ API organized by modules</a>
- * - <a href="https://github.com/jlblancoc/nanoflann" >Online README</a>
- * - <a href="http://jlblancoc.github.io/nanoflann/" >Doxygen
- * documentation</a>
- */
- #ifndef NANOFLANN_HPP_
- #define NANOFLANN_HPP_
- #include <algorithm>
- #include <array>
- #include <cassert>
- #include <cmath> // for abs()
- #include <cstdio> // for fwrite()
- #include <cstdlib> // for abs()
- #include <functional>
- #include <limits> // std::reference_wrapper
- #include <stdexcept>
- #include <vector>
- /** Library version: 0xMmP (M=Major,m=minor,P=patch) */
- #define NANOFLANN_VERSION 0x132
- // Avoid conflicting declaration of min/max macros in windows headers
- #if !defined(NOMINMAX) && \
- (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64))
- #define NOMINMAX
- #ifdef max
- #undef max
- #undef min
- #endif
- #endif
- namespace nanoflann {
- /** @addtogroup nanoflann_grp nanoflann C++ library for ANN
- * @{ */
- /** the PI constant (required to avoid MSVC missing symbols) */
- template <typename T> T pi_const() {
- return static_cast<T>(3.14159265358979323846);
- }
- /**
- * Traits if object is resizable and assignable (typically has a resize | assign
- * method)
- */
- template <typename T, typename = int> struct has_resize : std::false_type {};
- template <typename T>
- struct has_resize<T, decltype((void)std::declval<T>().resize(1), 0)>
- : std::true_type {};
- template <typename T, typename = int> struct has_assign : std::false_type {};
- template <typename T>
- struct has_assign<T, decltype((void)std::declval<T>().assign(1, 0), 0)>
- : std::true_type {};
- /**
- * Free function to resize a resizable object
- */
- template <typename Container>
- inline typename std::enable_if<has_resize<Container>::value, void>::type
- resize(Container &c, const size_t nElements) {
- c.resize(nElements);
- }
- /**
- * Free function that has no effects on non resizable containers (e.g.
- * std::array) It raises an exception if the expected size does not match
- */
- template <typename Container>
- inline typename std::enable_if<!has_resize<Container>::value, void>::type
- resize(Container &c, const size_t nElements) {
- if (nElements != c.size())
- throw std::logic_error("Try to change the size of a std::array.");
- }
- /**
- * Free function to assign to a container
- */
- template <typename Container, typename T>
- inline typename std::enable_if<has_assign<Container>::value, void>::type
- assign(Container &c, const size_t nElements, const T &value) {
- c.assign(nElements, value);
- }
- /**
- * Free function to assign to a std::array
- */
- template <typename Container, typename T>
- inline typename std::enable_if<!has_assign<Container>::value, void>::type
- assign(Container &c, const size_t nElements, const T &value) {
- for (size_t i = 0; i < nElements; i++)
- c[i] = value;
- }
- /** @addtogroup result_sets_grp Result set classes
- * @{ */
- template <typename _DistanceType, typename _IndexType = size_t,
- typename _CountType = size_t>
- class KNNResultSet {
- public:
- typedef _DistanceType DistanceType;
- typedef _IndexType IndexType;
- typedef _CountType CountType;
- private:
- IndexType *indices;
- DistanceType *dists;
- CountType capacity;
- CountType count;
- public:
- inline KNNResultSet(CountType capacity_)
- : indices(0), dists(0), capacity(capacity_), count(0) {}
- inline void init(IndexType *indices_, DistanceType *dists_) {
- indices = indices_;
- dists = dists_;
- count = 0;
- if (capacity)
- dists[capacity - 1] = (std::numeric_limits<DistanceType>::max)();
- }
- inline CountType size() const { return count; }
- inline bool full() const { return count == capacity; }
- /**
- * Called during search to add an element matching the criteria.
- * @return true if the search should be continued, false if the results are
- * sufficient
- */
- inline bool addPoint(DistanceType dist, IndexType index) {
- CountType i;
- for (i = count; i > 0; --i) {
- #ifdef NANOFLANN_FIRST_MATCH // If defined and two points have the same
- // distance, the one with the lowest-index will be
- // returned first.
- if ((dists[i - 1] > dist) ||
- ((dist == dists[i - 1]) && (indices[i - 1] > index))) {
- #else
- if (dists[i - 1] > dist) {
- #endif
- if (i < capacity) {
- dists[i] = dists[i - 1];
- indices[i] = indices[i - 1];
- }
- } else
- break;
- }
- if (i < capacity) {
- dists[i] = dist;
- indices[i] = index;
- }
- if (count < capacity)
- count++;
- // tell caller that the search shall continue
- return true;
- }
- inline DistanceType worstDist() const { return dists[capacity - 1]; }
- };
- /** operator "<" for std::sort() */
- struct IndexDist_Sorter {
- /** PairType will be typically: std::pair<IndexType,DistanceType> */
- template <typename PairType>
- inline bool operator()(const PairType &p1, const PairType &p2) const {
- return p1.second < p2.second;
- }
- };
- /**
- * A result-set class used when performing a radius based search.
- */
- template <typename _DistanceType, typename _IndexType = size_t>
- class RadiusResultSet {
- public:
- typedef _DistanceType DistanceType;
- typedef _IndexType IndexType;
- public:
- const DistanceType radius;
- std::vector<std::pair<IndexType, DistanceType>> &m_indices_dists;
- inline RadiusResultSet(
- DistanceType radius_,
- std::vector<std::pair<IndexType, DistanceType>> &indices_dists)
- : radius(radius_), m_indices_dists(indices_dists) {
- init();
- }
- inline void init() { clear(); }
- inline void clear() { m_indices_dists.clear(); }
- inline size_t size() const { return m_indices_dists.size(); }
- inline bool full() const { return true; }
- /**
- * Called during search to add an element matching the criteria.
- * @return true if the search should be continued, false if the results are
- * sufficient
- */
- inline bool addPoint(DistanceType dist, IndexType index) {
- if (dist < radius)
- m_indices_dists.push_back(std::make_pair(index, dist));
- return true;
- }
- inline DistanceType worstDist() const { return radius; }
- /**
- * Find the worst result (furtherest neighbor) without copying or sorting
- * Pre-conditions: size() > 0
- */
- std::pair<IndexType, DistanceType> worst_item() const {
- if (m_indices_dists.empty())
- throw std::runtime_error("Cannot invoke RadiusResultSet::worst_item() on "
- "an empty list of results.");
- typedef
- typename std::vector<std::pair<IndexType, DistanceType>>::const_iterator
- DistIt;
- DistIt it = std::max_element(m_indices_dists.begin(), m_indices_dists.end(),
- IndexDist_Sorter());
- return *it;
- }
- };
- /** @} */
- /** @addtogroup loadsave_grp Load/save auxiliary functions
- * @{ */
- template <typename T>
- void save_value(FILE *stream, const T &value, size_t count = 1) {
- fwrite(&value, sizeof(value), count, stream);
- }
- template <typename T>
- void save_value(FILE *stream, const std::vector<T> &value) {
- size_t size = value.size();
- fwrite(&size, sizeof(size_t), 1, stream);
- fwrite(&value[0], sizeof(T), size, stream);
- }
- template <typename T>
- void load_value(FILE *stream, T &value, size_t count = 1) {
- size_t read_cnt = fread(&value, sizeof(value), count, stream);
- if (read_cnt != count) {
- throw std::runtime_error("Cannot read from file");
- }
- }
- template <typename T> void load_value(FILE *stream, std::vector<T> &value) {
- size_t size;
- size_t read_cnt = fread(&size, sizeof(size_t), 1, stream);
- if (read_cnt != 1) {
- throw std::runtime_error("Cannot read from file");
- }
- value.resize(size);
- read_cnt = fread(&value[0], sizeof(T), size, stream);
- if (read_cnt != size) {
- throw std::runtime_error("Cannot read from file");
- }
- }
- /** @} */
- /** @addtogroup metric_grp Metric (distance) classes
- * @{ */
- struct Metric {};
- /** Manhattan distance functor (generic version, optimized for
- * high-dimensionality data sets). Corresponding distance traits:
- * nanoflann::metric_L1 \tparam T Type of the elements (e.g. double, float,
- * uint8_t) \tparam _DistanceType Type of distance variables (must be signed)
- * (e.g. float, double, int64_t)
- */
- template <class T, class DataSource, typename _DistanceType = T>
- struct L1_Adaptor {
- typedef T ElementType;
- typedef _DistanceType DistanceType;
- const DataSource &data_source;
- L1_Adaptor(const DataSource &_data_source) : data_source(_data_source) {}
- inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size,
- DistanceType worst_dist = -1) const {
- DistanceType result = DistanceType();
- const T *last = a + size;
- const T *lastgroup = last - 3;
- size_t d = 0;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- const DistanceType diff0 =
- std::abs(a[0] - data_source.kdtree_get_pt(b_idx, d++));
- const DistanceType diff1 =
- std::abs(a[1] - data_source.kdtree_get_pt(b_idx, d++));
- const DistanceType diff2 =
- std::abs(a[2] - data_source.kdtree_get_pt(b_idx, d++));
- const DistanceType diff3 =
- std::abs(a[3] - data_source.kdtree_get_pt(b_idx, d++));
- result += diff0 + diff1 + diff2 + diff3;
- a += 4;
- if ((worst_dist > 0) && (result > worst_dist)) {
- return result;
- }
- }
- /* Process last 0-3 components. Not needed for standard vector lengths. */
- while (a < last) {
- result += std::abs(*a++ - data_source.kdtree_get_pt(b_idx, d++));
- }
- return result;
- }
- template <typename U, typename V>
- inline DistanceType accum_dist(const U a, const V b, const size_t) const {
- return std::abs(a - b);
- }
- };
- /** Squared Euclidean distance functor (generic version, optimized for
- * high-dimensionality data sets). Corresponding distance traits:
- * nanoflann::metric_L2 \tparam T Type of the elements (e.g. double, float,
- * uint8_t) \tparam _DistanceType Type of distance variables (must be signed)
- * (e.g. float, double, int64_t)
- */
- template <class T, class DataSource, typename _DistanceType = T>
- struct L2_Adaptor {
- typedef T ElementType;
- typedef _DistanceType DistanceType;
- const DataSource &data_source;
- L2_Adaptor(const DataSource &_data_source) : data_source(_data_source) {}
- inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size,
- DistanceType worst_dist = -1) const {
- DistanceType result = DistanceType();
- const T *last = a + size;
- const T *lastgroup = last - 3;
- size_t d = 0;
- /* Process 4 items with each loop for efficiency. */
- while (a < lastgroup) {
- const DistanceType diff0 = a[0] - data_source.kdtree_get_pt(b_idx, d++);
- const DistanceType diff1 = a[1] - data_source.kdtree_get_pt(b_idx, d++);
- const DistanceType diff2 = a[2] - data_source.kdtree_get_pt(b_idx, d++);
- const DistanceType diff3 = a[3] - data_source.kdtree_get_pt(b_idx, d++);
- result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
- a += 4;
- if ((worst_dist > 0) && (result > worst_dist)) {
- return result;
- }
- }
- /* Process last 0-3 components. Not needed for standard vector lengths. */
- while (a < last) {
- const DistanceType diff0 = *a++ - data_source.kdtree_get_pt(b_idx, d++);
- result += diff0 * diff0;
- }
- return result;
- }
- template <typename U, typename V>
- inline DistanceType accum_dist(const U a, const V b, const size_t) const {
- return (a - b) * (a - b);
- }
- };
- /** Squared Euclidean (L2) distance functor (suitable for low-dimensionality
- * datasets, like 2D or 3D point clouds) Corresponding distance traits:
- * nanoflann::metric_L2_Simple \tparam T Type of the elements (e.g. double,
- * float, uint8_t) \tparam _DistanceType Type of distance variables (must be
- * signed) (e.g. float, double, int64_t)
- */
- template <class T, class DataSource, typename _DistanceType = T>
- struct L2_Simple_Adaptor {
- typedef T ElementType;
- typedef _DistanceType DistanceType;
- const DataSource &data_source;
- L2_Simple_Adaptor(const DataSource &_data_source)
- : data_source(_data_source) {}
- inline DistanceType evalMetric(const T *a, const size_t b_idx,
- size_t size) const {
- DistanceType result = DistanceType();
- for (size_t i = 0; i < size; ++i) {
- const DistanceType diff = a[i] - data_source.kdtree_get_pt(b_idx, i);
- result += diff * diff;
- }
- return result;
- }
- template <typename U, typename V>
- inline DistanceType accum_dist(const U a, const V b, const size_t) const {
- return (a - b) * (a - b);
- }
- };
- /** SO2 distance functor
- * Corresponding distance traits: nanoflann::metric_SO2
- * \tparam T Type of the elements (e.g. double, float)
- * \tparam _DistanceType Type of distance variables (must be signed) (e.g.
- * float, double) orientation is constrained to be in [-pi, pi]
- */
- template <class T, class DataSource, typename _DistanceType = T>
- struct SO2_Adaptor {
- typedef T ElementType;
- typedef _DistanceType DistanceType;
- const DataSource &data_source;
- SO2_Adaptor(const DataSource &_data_source) : data_source(_data_source) {}
- inline DistanceType evalMetric(const T *a, const size_t b_idx,
- size_t size) const {
- return accum_dist(a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1),
- size - 1);
- }
- /** Note: this assumes that input angles are already in the range [-pi,pi] */
- template <typename U, typename V>
- inline DistanceType accum_dist(const U a, const V b, const size_t) const {
- DistanceType result = DistanceType();
- DistanceType PI = pi_const<DistanceType>();
- result = b - a;
- if (result > PI)
- result -= 2 * PI;
- else if (result < -PI)
- result += 2 * PI;
- return result;
- }
- };
- /** SO3 distance functor (Uses L2_Simple)
- * Corresponding distance traits: nanoflann::metric_SO3
- * \tparam T Type of the elements (e.g. double, float)
- * \tparam _DistanceType Type of distance variables (must be signed) (e.g.
- * float, double)
- */
- template <class T, class DataSource, typename _DistanceType = T>
- struct SO3_Adaptor {
- typedef T ElementType;
- typedef _DistanceType DistanceType;
- L2_Simple_Adaptor<T, DataSource> distance_L2_Simple;
- SO3_Adaptor(const DataSource &_data_source)
- : distance_L2_Simple(_data_source) {}
- inline DistanceType evalMetric(const T *a, const size_t b_idx,
- size_t size) const {
- return distance_L2_Simple.evalMetric(a, b_idx, size);
- }
- template <typename U, typename V>
- inline DistanceType accum_dist(const U a, const V b, const size_t idx) const {
- return distance_L2_Simple.accum_dist(a, b, idx);
- }
- };
- /** Metaprogramming helper traits class for the L1 (Manhattan) metric */
- struct metric_L1 : public Metric {
- template <class T, class DataSource> struct traits {
- typedef L1_Adaptor<T, DataSource> distance_t;
- };
- };
- /** Metaprogramming helper traits class for the L2 (Euclidean) metric */
- struct metric_L2 : public Metric {
- template <class T, class DataSource> struct traits {
- typedef L2_Adaptor<T, DataSource> distance_t;
- };
- };
- /** Metaprogramming helper traits class for the L2_simple (Euclidean) metric */
- struct metric_L2_Simple : public Metric {
- template <class T, class DataSource> struct traits {
- typedef L2_Simple_Adaptor<T, DataSource> distance_t;
- };
- };
- /** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */
- struct metric_SO2 : public Metric {
- template <class T, class DataSource> struct traits {
- typedef SO2_Adaptor<T, DataSource> distance_t;
- };
- };
- /** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */
- struct metric_SO3 : public Metric {
- template <class T, class DataSource> struct traits {
- typedef SO3_Adaptor<T, DataSource> distance_t;
- };
- };
- /** @} */
- /** @addtogroup param_grp Parameter structs
- * @{ */
- /** Parameters (see README.md) */
- struct KDTreeSingleIndexAdaptorParams {
- KDTreeSingleIndexAdaptorParams(size_t _leaf_max_size = 10)
- : leaf_max_size(_leaf_max_size) {}
- size_t leaf_max_size;
- };
- /** Search options for KDTreeSingleIndexAdaptor::findNeighbors() */
- struct SearchParams {
- /** Note: The first argument (checks_IGNORED_) is ignored, but kept for
- * compatibility with the FLANN interface */
- SearchParams(int checks_IGNORED_ = 32, float eps_ = 0, bool sorted_ = true)
- : checks(checks_IGNORED_), eps(eps_), sorted(sorted_) {}
- int checks; //!< Ignored parameter (Kept for compatibility with the FLANN
- //!< interface).
- float eps; //!< search for eps-approximate neighbours (default: 0)
- bool sorted; //!< only for radius search, require neighbours sorted by
- //!< distance (default: true)
- };
- /** @} */
- /** @addtogroup memalloc_grp Memory allocation
- * @{ */
- /**
- * Allocates (using C's malloc) a generic type T.
- *
- * Params:
- * count = number of instances to allocate.
- * Returns: pointer (of type T*) to memory buffer
- */
- template <typename T> inline T *allocate(size_t count = 1) {
- T *mem = static_cast<T *>(::malloc(sizeof(T) * count));
- return mem;
- }
- /**
- * Pooled storage allocator
- *
- * The following routines allow for the efficient allocation of storage in
- * small chunks from a specified pool. Rather than allowing each structure
- * to be freed individually, an entire pool of storage is freed at once.
- * This method has two advantages over just using malloc() and free(). First,
- * it is far more efficient for allocating small objects, as there is
- * no overhead for remembering all the information needed to free each
- * object or consolidating fragmented memory. Second, the decision about
- * how long to keep an object is made at the time of allocation, and there
- * is no need to track down all the objects to free them.
- *
- */
- const size_t WORDSIZE = 16;
- const size_t BLOCKSIZE = 8192;
- class PooledAllocator {
- /* We maintain memory alignment to word boundaries by requiring that all
- allocations be in multiples of the machine wordsize. */
- /* Size of machine word in bytes. Must be power of 2. */
- /* Minimum number of bytes requested at a time from the system. Must be
- * multiple of WORDSIZE. */
- size_t remaining; /* Number of bytes left in current block of storage. */
- void *base; /* Pointer to base of current block of storage. */
- void *loc; /* Current location in block to next allocate memory. */
- void internal_init() {
- remaining = 0;
- base = NULL;
- usedMemory = 0;
- wastedMemory = 0;
- }
- public:
- size_t usedMemory;
- size_t wastedMemory;
- /**
- Default constructor. Initializes a new pool.
- */
- PooledAllocator() { internal_init(); }
- /**
- * Destructor. Frees all the memory allocated in this pool.
- */
- ~PooledAllocator() { free_all(); }
- /** Frees all allocated memory chunks */
- void free_all() {
- while (base != NULL) {
- void *prev =
- *(static_cast<void **>(base)); /* Get pointer to prev block. */
- ::free(base);
- base = prev;
- }
- internal_init();
- }
- /**
- * Returns a pointer to a piece of new memory of the given size in bytes
- * allocated from the pool.
- */
- void *malloc(const size_t req_size) {
- /* Round size up to a multiple of wordsize. The following expression
- only works for WORDSIZE that is a power of 2, by masking last bits of
- incremented size to zero.
- */
- const size_t size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
- /* Check whether a new block must be allocated. Note that the first word
- of a block is reserved for a pointer to the previous block.
- */
- if (size > remaining) {
- wastedMemory += remaining;
- /* Allocate new storage. */
- const size_t blocksize =
- (size + sizeof(void *) + (WORDSIZE - 1) > BLOCKSIZE)
- ? size + sizeof(void *) + (WORDSIZE - 1)
- : BLOCKSIZE;
- // use the standard C malloc to allocate memory
- void *m = ::malloc(blocksize);
- if (!m) {
- fprintf(stderr, "Failed to allocate memory.\n");
- throw std::bad_alloc();
- }
- /* Fill first word of new block with pointer to previous block. */
- static_cast<void **>(m)[0] = base;
- base = m;
- size_t shift = 0;
- // int size_t = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) &
- // (WORDSIZE-1))) & (WORDSIZE-1);
- remaining = blocksize - sizeof(void *) - shift;
- loc = (static_cast<char *>(m) + sizeof(void *) + shift);
- }
- void *rloc = loc;
- loc = static_cast<char *>(loc) + size;
- remaining -= size;
- usedMemory += size;
- return rloc;
- }
- /**
- * Allocates (using this pool) a generic type T.
- *
- * Params:
- * count = number of instances to allocate.
- * Returns: pointer (of type T*) to memory buffer
- */
- template <typename T> T *allocate(const size_t count = 1) {
- T *mem = static_cast<T *>(this->malloc(sizeof(T) * count));
- return mem;
- }
- };
- /** @} */
- /** @addtogroup nanoflann_metaprog_grp Auxiliary metaprogramming stuff
- * @{ */
- /** Used to declare fixed-size arrays when DIM>0, dynamically-allocated vectors
- * when DIM=-1. Fixed size version for a generic DIM:
- */
- template <int DIM, typename T> struct array_or_vector_selector {
- typedef std::array<T, DIM> container_t;
- };
- /** Dynamic size version */
- template <typename T> struct array_or_vector_selector<-1, T> {
- typedef std::vector<T> container_t;
- };
- /** @} */
- /** kd-tree base-class
- *
- * Contains the member functions common to the classes KDTreeSingleIndexAdaptor
- * and KDTreeSingleIndexDynamicAdaptor_.
- *
- * \tparam Derived The name of the class which inherits this class.
- * \tparam DatasetAdaptor The user-provided adaptor (see comments above).
- * \tparam Distance The distance metric to use, these are all classes derived
- * from nanoflann::Metric \tparam DIM Dimensionality of data points (e.g. 3 for
- * 3D points) \tparam IndexType Will be typically size_t or int
- */
- template <class Derived, typename Distance, class DatasetAdaptor, int DIM = -1,
- typename IndexType = size_t>
- class KDTreeBaseClass {
- public:
- /** Frees the previously-built index. Automatically called within
- * buildIndex(). */
- void freeIndex(Derived &obj) {
- obj.pool.free_all();
- obj.root_node = NULL;
- obj.m_size_at_index_build = 0;
- }
- typedef typename Distance::ElementType ElementType;
- typedef typename Distance::DistanceType DistanceType;
- /*--------------------- Internal Data Structures --------------------------*/
- struct Node {
- /** Union used because a node can be either a LEAF node or a non-leaf node,
- * so both data fields are never used simultaneously */
- union {
- struct leaf {
- IndexType left, right; //!< Indices of points in leaf node
- } lr;
- struct nonleaf {
- int divfeat; //!< Dimension used for subdivision.
- DistanceType divlow, divhigh; //!< The values used for subdivision.
- } sub;
- } node_type;
- Node *child1, *child2; //!< Child nodes (both=NULL mean its a leaf node)
- };
- typedef Node *NodePtr;
- struct Interval {
- ElementType low, high;
- };
- /**
- * Array of indices to vectors in the dataset.
- */
- std::vector<IndexType> vind;
- NodePtr root_node;
- size_t m_leaf_max_size;
- size_t m_size; //!< Number of current points in the dataset
- size_t m_size_at_index_build; //!< Number of points in the dataset when the
- //!< index was built
- int dim; //!< Dimensionality of each data point
- /** Define "BoundingBox" as a fixed-size or variable-size container depending
- * on "DIM" */
- typedef
- typename array_or_vector_selector<DIM, Interval>::container_t BoundingBox;
- /** Define "distance_vector_t" as a fixed-size or variable-size container
- * depending on "DIM" */
- typedef typename array_or_vector_selector<DIM, DistanceType>::container_t
- distance_vector_t;
- /** The KD-tree used to find neighbours */
- BoundingBox root_bbox;
- /**
- * Pooled memory allocator.
- *
- * Using a pooled memory allocator is more efficient
- * than allocating memory directly when there is a large
- * number small of memory allocations.
- */
- PooledAllocator pool;
- /** Returns number of points in dataset */
- size_t size(const Derived &obj) const { return obj.m_size; }
- /** Returns the length of each point in the dataset */
- size_t veclen(const Derived &obj) {
- return static_cast<size_t>(DIM > 0 ? DIM : obj.dim);
- }
- /// Helper accessor to the dataset points:
- inline ElementType dataset_get(const Derived &obj, size_t idx,
- int component) const {
- return obj.dataset.kdtree_get_pt(idx, component);
- }
- /**
- * Computes the inde memory usage
- * Returns: memory used by the index
- */
- size_t usedMemory(Derived &obj) {
- return obj.pool.usedMemory + obj.pool.wastedMemory +
- obj.dataset.kdtree_get_point_count() *
- sizeof(IndexType); // pool memory and vind array memory
- }
- void computeMinMax(const Derived &obj, IndexType *ind, IndexType count,
- int element, ElementType &min_elem,
- ElementType &max_elem) {
- min_elem = dataset_get(obj, ind[0], element);
- max_elem = dataset_get(obj, ind[0], element);
- for (IndexType i = 1; i < count; ++i) {
- ElementType val = dataset_get(obj, ind[i], element);
- if (val < min_elem)
- min_elem = val;
- if (val > max_elem)
- max_elem = val;
- }
- }
- /**
- * Create a tree node that subdivides the list of vecs from vind[first]
- * to vind[last]. The routine is called recursively on each sublist.
- *
- * @param left index of the first vector
- * @param right index of the last vector
- */
- NodePtr divideTree(Derived &obj, const IndexType left, const IndexType right,
- BoundingBox &bbox) {
- NodePtr node = obj.pool.template allocate<Node>(); // allocate memory
- /* If too few exemplars remain, then make this a leaf node. */
- if ((right - left) <= static_cast<IndexType>(obj.m_leaf_max_size)) {
- node->child1 = node->child2 = NULL; /* Mark as leaf node. */
- node->node_type.lr.left = left;
- node->node_type.lr.right = right;
- // compute bounding-box of leaf points
- for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {
- bbox[i].low = dataset_get(obj, obj.vind[left], i);
- bbox[i].high = dataset_get(obj, obj.vind[left], i);
- }
- for (IndexType k = left + 1; k < right; ++k) {
- for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {
- if (bbox[i].low > dataset_get(obj, obj.vind[k], i))
- bbox[i].low = dataset_get(obj, obj.vind[k], i);
- if (bbox[i].high < dataset_get(obj, obj.vind[k], i))
- bbox[i].high = dataset_get(obj, obj.vind[k], i);
- }
- }
- } else {
- IndexType idx;
- int cutfeat;
- DistanceType cutval;
- middleSplit_(obj, &obj.vind[0] + left, right - left, idx, cutfeat, cutval,
- bbox);
- node->node_type.sub.divfeat = cutfeat;
- BoundingBox left_bbox(bbox);
- left_bbox[cutfeat].high = cutval;
- node->child1 = divideTree(obj, left, left + idx, left_bbox);
- BoundingBox right_bbox(bbox);
- right_bbox[cutfeat].low = cutval;
- node->child2 = divideTree(obj, left + idx, right, right_bbox);
- node->node_type.sub.divlow = left_bbox[cutfeat].high;
- node->node_type.sub.divhigh = right_bbox[cutfeat].low;
- for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {
- bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
- bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
- }
- }
- return node;
- }
- void middleSplit_(Derived &obj, IndexType *ind, IndexType count,
- IndexType &index, int &cutfeat, DistanceType &cutval,
- const BoundingBox &bbox) {
- const DistanceType EPS = static_cast<DistanceType>(0.00001);
- ElementType max_span = bbox[0].high - bbox[0].low;
- for (int i = 1; i < (DIM > 0 ? DIM : obj.dim); ++i) {
- ElementType span = bbox[i].high - bbox[i].low;
- if (span > max_span) {
- max_span = span;
- }
- }
- ElementType max_spread = -1;
- cutfeat = 0;
- for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {
- ElementType span = bbox[i].high - bbox[i].low;
- if (span > (1 - EPS) * max_span) {
- ElementType min_elem, max_elem;
- computeMinMax(obj, ind, count, i, min_elem, max_elem);
- ElementType spread = max_elem - min_elem;
- if (spread > max_spread) {
- cutfeat = i;
- max_spread = spread;
- }
- }
- }
- // split in the middle
- DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2;
- ElementType min_elem, max_elem;
- computeMinMax(obj, ind, count, cutfeat, min_elem, max_elem);
- if (split_val < min_elem)
- cutval = min_elem;
- else if (split_val > max_elem)
- cutval = max_elem;
- else
- cutval = split_val;
- IndexType lim1, lim2;
- planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2);
- if (lim1 > count / 2)
- index = lim1;
- else if (lim2 < count / 2)
- index = lim2;
- else
- index = count / 2;
- }
- /**
- * Subdivide the list of points by a plane perpendicular on axe corresponding
- * to the 'cutfeat' dimension at 'cutval' position.
- *
- * On return:
- * dataset[ind[0..lim1-1]][cutfeat]<cutval
- * dataset[ind[lim1..lim2-1]][cutfeat]==cutval
- * dataset[ind[lim2..count]][cutfeat]>cutval
- */
- void planeSplit(Derived &obj, IndexType *ind, const IndexType count,
- int cutfeat, DistanceType &cutval, IndexType &lim1,
- IndexType &lim2) {
- /* Move vector indices for left subtree to front of list. */
- IndexType left = 0;
- IndexType right = count - 1;
- for (;;) {
- while (left <= right && dataset_get(obj, ind[left], cutfeat) < cutval)
- ++left;
- while (right && left <= right &&
- dataset_get(obj, ind[right], cutfeat) >= cutval)
- --right;
- if (left > right || !right)
- break; // "!right" was added to support unsigned Index types
- std::swap(ind[left], ind[right]);
- ++left;
- --right;
- }
- /* If either list is empty, it means that all remaining features
- * are identical. Split in the middle to maintain a balanced tree.
- */
- lim1 = left;
- right = count - 1;
- for (;;) {
- while (left <= right && dataset_get(obj, ind[left], cutfeat) <= cutval)
- ++left;
- while (right && left <= right &&
- dataset_get(obj, ind[right], cutfeat) > cutval)
- --right;
- if (left > right || !right)
- break; // "!right" was added to support unsigned Index types
- std::swap(ind[left], ind[right]);
- ++left;
- --right;
- }
- lim2 = left;
- }
- DistanceType computeInitialDistances(const Derived &obj,
- const ElementType *vec,
- distance_vector_t &dists) const {
- assert(vec);
- DistanceType distsq = DistanceType();
- for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {
- if (vec[i] < obj.root_bbox[i].low) {
- dists[i] = obj.distance.accum_dist(vec[i], obj.root_bbox[i].low, i);
- distsq += dists[i];
- }
- if (vec[i] > obj.root_bbox[i].high) {
- dists[i] = obj.distance.accum_dist(vec[i], obj.root_bbox[i].high, i);
- distsq += dists[i];
- }
- }
- return distsq;
- }
- void save_tree(Derived &obj, FILE *stream, NodePtr tree) {
- save_value(stream, *tree);
- if (tree->child1 != NULL) {
- save_tree(obj, stream, tree->child1);
- }
- if (tree->child2 != NULL) {
- save_tree(obj, stream, tree->child2);
- }
- }
- void load_tree(Derived &obj, FILE *stream, NodePtr &tree) {
- tree = obj.pool.template allocate<Node>();
- load_value(stream, *tree);
- if (tree->child1 != NULL) {
- load_tree(obj, stream, tree->child1);
- }
- if (tree->child2 != NULL) {
- load_tree(obj, stream, tree->child2);
- }
- }
- /** Stores the index in a binary file.
- * IMPORTANT NOTE: The set of data points is NOT stored in the file, so when
- * loading the index object it must be constructed associated to the same
- * source of data points used while building it. See the example:
- * examples/saveload_example.cpp \sa loadIndex */
- void saveIndex_(Derived &obj, FILE *stream) {
- save_value(stream, obj.m_size);
- save_value(stream, obj.dim);
- save_value(stream, obj.root_bbox);
- save_value(stream, obj.m_leaf_max_size);
- save_value(stream, obj.vind);
- save_tree(obj, stream, obj.root_node);
- }
- /** Loads a previous index from a binary file.
- * IMPORTANT NOTE: The set of data points is NOT stored in the file, so the
- * index object must be constructed associated to the same source of data
- * points used while building the index. See the example:
- * examples/saveload_example.cpp \sa loadIndex */
- void loadIndex_(Derived &obj, FILE *stream) {
- load_value(stream, obj.m_size);
- load_value(stream, obj.dim);
- load_value(stream, obj.root_bbox);
- load_value(stream, obj.m_leaf_max_size);
- load_value(stream, obj.vind);
- load_tree(obj, stream, obj.root_node);
- }
- };
- /** @addtogroup kdtrees_grp KD-tree classes and adaptors
- * @{ */
- /** kd-tree static index
- *
- * Contains the k-d trees and other information for indexing a set of points
- * for nearest-neighbor matching.
- *
- * The class "DatasetAdaptor" must provide the following interface (can be
- * non-virtual, inlined methods):
- *
- * \code
- * // Must return the number of data poins
- * inline size_t kdtree_get_point_count() const { ... }
- *
- *
- * // Must return the dim'th component of the idx'th point in the class:
- * inline T kdtree_get_pt(const size_t idx, const size_t dim) const { ... }
- *
- * // Optional bounding-box computation: return false to default to a standard
- * bbox computation loop.
- * // Return true if the BBOX was already computed by the class and returned
- * in "bb" so it can be avoided to redo it again.
- * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3
- * for point clouds) template <class BBOX> bool kdtree_get_bbox(BBOX &bb) const
- * {
- * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits
- * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits
- * ...
- * return true;
- * }
- *
- * \endcode
- *
- * \tparam DatasetAdaptor The user-provided adaptor (see comments above).
- * \tparam Distance The distance metric to use: nanoflann::metric_L1,
- * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. \tparam DIM
- * Dimensionality of data points (e.g. 3 for 3D points) \tparam IndexType Will
- * be typically size_t or int
- */
- template <typename Distance, class DatasetAdaptor, int DIM = -1,
- typename IndexType = size_t>
- class KDTreeSingleIndexAdaptor
- : public KDTreeBaseClass<
- KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, IndexType>,
- Distance, DatasetAdaptor, DIM, IndexType> {
- public:
- /** Deleted copy constructor*/
- KDTreeSingleIndexAdaptor(
- const KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, IndexType>
- &) = delete;
- /**
- * The dataset used by this index
- */
- const DatasetAdaptor &dataset; //!< The source of our data
- const KDTreeSingleIndexAdaptorParams index_params;
- Distance distance;
- typedef typename nanoflann::KDTreeBaseClass<
- nanoflann::KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM,
- IndexType>,
- Distance, DatasetAdaptor, DIM, IndexType>
- BaseClassRef;
- typedef typename BaseClassRef::ElementType ElementType;
- typedef typename BaseClassRef::DistanceType DistanceType;
- typedef typename BaseClassRef::Node Node;
- typedef Node *NodePtr;
- typedef typename BaseClassRef::Interval Interval;
- /** Define "BoundingBox" as a fixed-size or variable-size container depending
- * on "DIM" */
- typedef typename BaseClassRef::BoundingBox BoundingBox;
- /** Define "distance_vector_t" as a fixed-size or variable-size container
- * depending on "DIM" */
- typedef typename BaseClassRef::distance_vector_t distance_vector_t;
- /**
- * KDTree constructor
- *
- * Refer to docs in README.md or online in
- * https://github.com/jlblancoc/nanoflann
- *
- * The KD-Tree point dimension (the length of each point in the datase, e.g. 3
- * for 3D points) is determined by means of:
- * - The \a DIM template parameter if >0 (highest priority)
- * - Otherwise, the \a dimensionality parameter of this constructor.
- *
- * @param inputData Dataset with the input features
- * @param params Basically, the maximum leaf node size
- */
- KDTreeSingleIndexAdaptor(const int dimensionality,
- const DatasetAdaptor &inputData,
- const KDTreeSingleIndexAdaptorParams ¶ms =
- KDTreeSingleIndexAdaptorParams())
- : dataset(inputData), index_params(params), distance(inputData) {
- BaseClassRef::root_node = NULL;
- BaseClassRef::m_size = dataset.kdtree_get_point_count();
- BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;
- BaseClassRef::dim = dimensionality;
- if (DIM > 0)
- BaseClassRef::dim = DIM;
- BaseClassRef::m_leaf_max_size = params.leaf_max_size;
- // Create a permutable array of indices to the input vectors.
- init_vind();
- }
- /**
- * Builds the index
- */
- void buildIndex() {
- BaseClassRef::m_size = dataset.kdtree_get_point_count();
- BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;
- init_vind();
- this->freeIndex(*this);
- BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;
- if (BaseClassRef::m_size == 0)
- return;
- computeBoundingBox(BaseClassRef::root_bbox);
- BaseClassRef::root_node =
- this->divideTree(*this, 0, BaseClassRef::m_size,
- BaseClassRef::root_bbox); // construct the tree
- }
- /** \name Query methods
- * @{ */
- /**
- * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored
- * inside the result object.
- *
- * Params:
- * result = the result object in which the indices of the
- * nearest-neighbors are stored vec = the vector for which to search the
- * nearest neighbors
- *
- * \tparam RESULTSET Should be any ResultSet<DistanceType>
- * \return True if the requested neighbors could be found.
- * \sa knnSearch, radiusSearch
- */
- template <typename RESULTSET>
- bool findNeighbors(RESULTSET &result, const ElementType *vec,
- const SearchParams &searchParams) const {
- assert(vec);
- if (this->size(*this) == 0)
- return false;
- if (!BaseClassRef::root_node)
- throw std::runtime_error(
- "[nanoflann] findNeighbors() called before building the index.");
- float epsError = 1 + searchParams.eps;
- distance_vector_t
- dists; // fixed or variable-sized container (depending on DIM)
- auto zero = static_cast<decltype(result.worstDist())>(0);
- assign(dists, (DIM > 0 ? DIM : BaseClassRef::dim),
- zero); // Fill it with zeros.
- DistanceType distsq = this->computeInitialDistances(*this, vec, dists);
- searchLevel(result, vec, BaseClassRef::root_node, distsq, dists,
- epsError); // "count_leaf" parameter removed since was neither
- // used nor returned to the user.
- return result.full();
- }
- /**
- * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1].
- * Their indices are stored inside the result object. \sa radiusSearch,
- * findNeighbors \note nChecks_IGNORED is ignored but kept for compatibility
- * with the original FLANN interface. \return Number `N` of valid points in
- * the result set. Only the first `N` entries in `out_indices` and
- * `out_distances_sq` will be valid. Return may be less than `num_closest`
- * only if the number of elements in the tree is less than `num_closest`.
- */
- size_t knnSearch(const ElementType *query_point, const size_t num_closest,
- IndexType *out_indices, DistanceType *out_distances_sq,
- const int /* nChecks_IGNORED */ = 10) const {
- nanoflann::KNNResultSet<DistanceType, IndexType> resultSet(num_closest);
- resultSet.init(out_indices, out_distances_sq);
- this->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
- return resultSet.size();
- }
- /**
- * Find all the neighbors to \a query_point[0:dim-1] within a maximum radius.
- * The output is given as a vector of pairs, of which the first element is a
- * point index and the second the corresponding distance. Previous contents of
- * \a IndicesDists are cleared.
- *
- * If searchParams.sorted==true, the output list is sorted by ascending
- * distances.
- *
- * For a better performance, it is advisable to do a .reserve() on the vector
- * if you have any wild guess about the number of expected matches.
- *
- * \sa knnSearch, findNeighbors, radiusSearchCustomCallback
- * \return The number of points within the given radius (i.e. indices.size()
- * or dists.size() )
- */
- size_t
- radiusSearch(const ElementType *query_point, const DistanceType &radius,
- std::vector<std::pair<IndexType, DistanceType>> &IndicesDists,
- const SearchParams &searchParams) const {
- RadiusResultSet<DistanceType, IndexType> resultSet(radius, IndicesDists);
- const size_t nFound =
- radiusSearchCustomCallback(query_point, resultSet, searchParams);
- if (searchParams.sorted)
- std::sort(IndicesDists.begin(), IndicesDists.end(), IndexDist_Sorter());
- return nFound;
- }
- /**
- * Just like radiusSearch() but with a custom callback class for each point
- * found in the radius of the query. See the source of RadiusResultSet<> as a
- * start point for your own classes. \sa radiusSearch
- */
- template <class SEARCH_CALLBACK>
- size_t radiusSearchCustomCallback(
- const ElementType *query_point, SEARCH_CALLBACK &resultSet,
- const SearchParams &searchParams = SearchParams()) const {
- this->findNeighbors(resultSet, query_point, searchParams);
- return resultSet.size();
- }
- /** @} */
- public:
- /** Make sure the auxiliary list \a vind has the same size than the current
- * dataset, and re-generate if size has changed. */
- void init_vind() {
- // Create a permutable array of indices to the input vectors.
- BaseClassRef::m_size = dataset.kdtree_get_point_count();
- if (BaseClassRef::vind.size() != BaseClassRef::m_size)
- BaseClassRef::vind.resize(BaseClassRef::m_size);
- for (size_t i = 0; i < BaseClassRef::m_size; i++)
- BaseClassRef::vind[i] = i;
- }
- void computeBoundingBox(BoundingBox &bbox) {
- resize(bbox, (DIM > 0 ? DIM : BaseClassRef::dim));
- if (dataset.kdtree_get_bbox(bbox)) {
- // Done! It was implemented in derived class
- } else {
- const size_t N = dataset.kdtree_get_point_count();
- if (!N)
- throw std::runtime_error("[nanoflann] computeBoundingBox() called but "
- "no data points found.");
- for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) {
- bbox[i].low = bbox[i].high = this->dataset_get(*this, 0, i);
- }
- for (size_t k = 1; k < N; ++k) {
- for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) {
- if (this->dataset_get(*this, k, i) < bbox[i].low)
- bbox[i].low = this->dataset_get(*this, k, i);
- if (this->dataset_get(*this, k, i) > bbox[i].high)
- bbox[i].high = this->dataset_get(*this, k, i);
- }
- }
- }
- }
- /**
- * Performs an exact search in the tree starting from a node.
- * \tparam RESULTSET Should be any ResultSet<DistanceType>
- * \return true if the search should be continued, false if the results are
- * sufficient
- */
- template <class RESULTSET>
- bool searchLevel(RESULTSET &result_set, const ElementType *vec,
- const NodePtr node, DistanceType mindistsq,
- distance_vector_t &dists, const float epsError) const {
- /* If this is a leaf node, then do check and return. */
- if ((node->child1 == NULL) && (node->child2 == NULL)) {
- // count_leaf += (node->lr.right-node->lr.left); // Removed since was
- // neither used nor returned to the user.
- DistanceType worst_dist = result_set.worstDist();
- for (IndexType i = node->node_type.lr.left; i < node->node_type.lr.right;
- ++i) {
- const IndexType index = BaseClassRef::vind[i]; // reorder... : i;
- DistanceType dist = distance.evalMetric(
- vec, index, (DIM > 0 ? DIM : BaseClassRef::dim));
- if (dist < worst_dist) {
- if (!result_set.addPoint(dist, BaseClassRef::vind[i])) {
- // the resultset doesn't want to receive any more points, we're done
- // searching!
- return false;
- }
- }
- }
- return true;
- }
- /* Which child branch should be taken first? */
- int idx = node->node_type.sub.divfeat;
- ElementType val = vec[idx];
- DistanceType diff1 = val - node->node_type.sub.divlow;
- DistanceType diff2 = val - node->node_type.sub.divhigh;
- NodePtr bestChild;
- NodePtr otherChild;
- DistanceType cut_dist;
- if ((diff1 + diff2) < 0) {
- bestChild = node->child1;
- otherChild = node->child2;
- cut_dist = distance.accum_dist(val, node->node_type.sub.divhigh, idx);
- } else {
- bestChild = node->child2;
- otherChild = node->child1;
- cut_dist = distance.accum_dist(val, node->node_type.sub.divlow, idx);
- }
- /* Call recursively to search next level down. */
- if (!searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError)) {
- // the resultset doesn't want to receive any more points, we're done
- // searching!
- return false;
- }
- DistanceType dst = dists[idx];
- mindistsq = mindistsq + cut_dist - dst;
- dists[idx] = cut_dist;
- if (mindistsq * epsError <= result_set.worstDist()) {
- if (!searchLevel(result_set, vec, otherChild, mindistsq, dists,
- epsError)) {
- // the resultset doesn't want to receive any more points, we're done
- // searching!
- return false;
- }
- }
- dists[idx] = dst;
- return true;
- }
- public:
- /** Stores the index in a binary file.
- * IMPORTANT NOTE: The set of data points is NOT stored in the file, so when
- * loading the index object it must be constructed associated to the same
- * source of data points used while building it. See the example:
- * examples/saveload_example.cpp \sa loadIndex */
- void saveIndex(FILE *stream) { this->saveIndex_(*this, stream); }
- /** Loads a previous index from a binary file.
- * IMPORTANT NOTE: The set of data points is NOT stored in the file, so the
- * index object must be constructed associated to the same source of data
- * points used while building the index. See the example:
- * examples/saveload_example.cpp \sa loadIndex */
- void loadIndex(FILE *stream) { this->loadIndex_(*this, stream); }
- }; // class KDTree
- /** kd-tree dynamic index
- *
- * Contains the k-d trees and other information for indexing a set of points
- * for nearest-neighbor matching.
- *
- * The class "DatasetAdaptor" must provide the following interface (can be
- * non-virtual, inlined methods):
- *
- * \code
- * // Must return the number of data poins
- * inline size_t kdtree_get_point_count() const { ... }
- *
- * // Must return the dim'th component of the idx'th point in the class:
- * inline T kdtree_get_pt(const size_t idx, const size_t dim) const { ... }
- *
- * // Optional bounding-box computation: return false to default to a standard
- * bbox computation loop.
- * // Return true if the BBOX was already computed by the class and returned
- * in "bb" so it can be avoided to redo it again.
- * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3
- * for point clouds) template <class BBOX> bool kdtree_get_bbox(BBOX &bb) const
- * {
- * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits
- * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits
- * ...
- * return true;
- * }
- *
- * \endcode
- *
- * \tparam DatasetAdaptor The user-provided adaptor (see comments above).
- * \tparam Distance The distance metric to use: nanoflann::metric_L1,
- * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. \tparam DIM
- * Dimensionality of data points (e.g. 3 for 3D points) \tparam IndexType Will
- * be typically size_t or int
- */
- template <typename Distance, class DatasetAdaptor, int DIM = -1,
- typename IndexType = size_t>
- class KDTreeSingleIndexDynamicAdaptor_
- : public KDTreeBaseClass<KDTreeSingleIndexDynamicAdaptor_<
- Distance, DatasetAdaptor, DIM, IndexType>,
- Distance, DatasetAdaptor, DIM, IndexType> {
- public:
- /**
- * The dataset used by this index
- */
- const DatasetAdaptor &dataset; //!< The source of our data
- KDTreeSingleIndexAdaptorParams index_params;
- std::vector<int> &treeIndex;
- Distance distance;
- typedef typename nanoflann::KDTreeBaseClass<
- nanoflann::KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM,
- IndexType>,
- Distance, DatasetAdaptor, DIM, IndexType>
- BaseClassRef;
- typedef typename BaseClassRef::ElementType ElementType;
- typedef typename BaseClassRef::DistanceType DistanceType;
- typedef typename BaseClassRef::Node Node;
- typedef Node *NodePtr;
- typedef typename BaseClassRef::Interval Interval;
- /** Define "BoundingBox" as a fixed-size or variable-size container depending
- * on "DIM" */
- typedef typename BaseClassRef::BoundingBox BoundingBox;
- /** Define "distance_vector_t" as a fixed-size or variable-size container
- * depending on "DIM" */
- typedef typename BaseClassRef::distance_vector_t distance_vector_t;
- /**
- * KDTree constructor
- *
- * Refer to docs in README.md or online in
- * https://github.com/jlblancoc/nanoflann
- *
- * The KD-Tree point dimension (the length of each point in the datase, e.g. 3
- * for 3D points) is determined by means of:
- * - The \a DIM template parameter if >0 (highest priority)
- * - Otherwise, the \a dimensionality parameter of this constructor.
- *
- * @param inputData Dataset with the input features
- * @param params Basically, the maximum leaf node size
- */
- KDTreeSingleIndexDynamicAdaptor_(
- const int dimensionality, const DatasetAdaptor &inputData,
- std::vector<int> &treeIndex_,
- const KDTreeSingleIndexAdaptorParams ¶ms =
- KDTreeSingleIndexAdaptorParams())
- : dataset(inputData), index_params(params), treeIndex(treeIndex_),
- distance(inputData) {
- BaseClassRef::root_node = NULL;
- BaseClassRef::m_size = 0;
- BaseClassRef::m_size_at_index_build = 0;
- BaseClassRef::dim = dimensionality;
- if (DIM > 0)
- BaseClassRef::dim = DIM;
- BaseClassRef::m_leaf_max_size = params.leaf_max_size;
- }
- /** Assignment operator definiton */
- KDTreeSingleIndexDynamicAdaptor_
- operator=(const KDTreeSingleIndexDynamicAdaptor_ &rhs) {
- KDTreeSingleIndexDynamicAdaptor_ tmp(rhs);
- std::swap(BaseClassRef::vind, tmp.BaseClassRef::vind);
- std::swap(BaseClassRef::m_leaf_max_size, tmp.BaseClassRef::m_leaf_max_size);
- std::swap(index_params, tmp.index_params);
- std::swap(treeIndex, tmp.treeIndex);
- std::swap(BaseClassRef::m_size, tmp.BaseClassRef::m_size);
- std::swap(BaseClassRef::m_size_at_index_build,
- tmp.BaseClassRef::m_size_at_index_build);
- std::swap(BaseClassRef::root_node, tmp.BaseClassRef::root_node);
- std::swap(BaseClassRef::root_bbox, tmp.BaseClassRef::root_bbox);
- std::swap(BaseClassRef::pool, tmp.BaseClassRef::pool);
- return *this;
- }
- /**
- * Builds the index
- */
- void buildIndex() {
- BaseClassRef::m_size = BaseClassRef::vind.size();
- this->freeIndex(*this);
- BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;
- if (BaseClassRef::m_size == 0)
- return;
- computeBoundingBox(BaseClassRef::root_bbox);
- BaseClassRef::root_node =
- this->divideTree(*this, 0, BaseClassRef::m_size,
- BaseClassRef::root_bbox); // construct the tree
- }
- /** \name Query methods
- * @{ */
- /**
- * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored
- * inside the result object.
- *
- * Params:
- * result = the result object in which the indices of the
- * nearest-neighbors are stored vec = the vector for which to search the
- * nearest neighbors
- *
- * \tparam RESULTSET Should be any ResultSet<DistanceType>
- * \return True if the requested neighbors could be found.
- * \sa knnSearch, radiusSearch
- */
- template <typename RESULTSET>
- bool findNeighbors(RESULTSET &result, const ElementType *vec,
- const SearchParams &searchParams) const {
- assert(vec);
- if (this->size(*this) == 0)
- return false;
- if (!BaseClassRef::root_node)
- return false;
- float epsError = 1 + searchParams.eps;
- // fixed or variable-sized container (depending on DIM)
- distance_vector_t dists;
- // Fill it with zeros.
- assign(dists, (DIM > 0 ? DIM : BaseClassRef::dim),
- static_cast<typename distance_vector_t::value_type>(0));
- DistanceType distsq = this->computeInitialDistances(*this, vec, dists);
- searchLevel(result, vec, BaseClassRef::root_node, distsq, dists,
- epsError); // "count_leaf" parameter removed since was neither
- // used nor returned to the user.
- return result.full();
- }
- /**
- * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1].
- * Their indices are stored inside the result object. \sa radiusSearch,
- * findNeighbors \note nChecks_IGNORED is ignored but kept for compatibility
- * with the original FLANN interface. \return Number `N` of valid points in
- * the result set. Only the first `N` entries in `out_indices` and
- * `out_distances_sq` will be valid. Return may be less than `num_closest`
- * only if the number of elements in the tree is less than `num_closest`.
- */
- size_t knnSearch(const ElementType *query_point, const size_t num_closest,
- IndexType *out_indices, DistanceType *out_distances_sq,
- const int /* nChecks_IGNORED */ = 10) const {
- nanoflann::KNNResultSet<DistanceType, IndexType> resultSet(num_closest);
- resultSet.init(out_indices, out_distances_sq);
- this->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
- return resultSet.size();
- }
- /**
- * Find all the neighbors to \a query_point[0:dim-1] within a maximum radius.
- * The output is given as a vector of pairs, of which the first element is a
- * point index and the second the corresponding distance. Previous contents of
- * \a IndicesDists are cleared.
- *
- * If searchParams.sorted==true, the output list is sorted by ascending
- * distances.
- *
- * For a better performance, it is advisable to do a .reserve() on the vector
- * if you have any wild guess about the number of expected matches.
- *
- * \sa knnSearch, findNeighbors, radiusSearchCustomCallback
- * \return The number of points within the given radius (i.e. indices.size()
- * or dists.size() )
- */
- size_t
- radiusSearch(const ElementType *query_point, const DistanceType &radius,
- std::vector<std::pair<IndexType, DistanceType>> &IndicesDists,
- const SearchParams &searchParams) const {
- RadiusResultSet<DistanceType, IndexType> resultSet(radius, IndicesDists);
- const size_t nFound =
- radiusSearchCustomCallback(query_point, resultSet, searchParams);
- if (searchParams.sorted)
- std::sort(IndicesDists.begin(), IndicesDists.end(), IndexDist_Sorter());
- return nFound;
- }
- /**
- * Just like radiusSearch() but with a custom callback class for each point
- * found in the radius of the query. See the source of RadiusResultSet<> as a
- * start point for your own classes. \sa radiusSearch
- */
- template <class SEARCH_CALLBACK>
- size_t radiusSearchCustomCallback(
- const ElementType *query_point, SEARCH_CALLBACK &resultSet,
- const SearchParams &searchParams = SearchParams()) const {
- this->findNeighbors(resultSet, query_point, searchParams);
- return resultSet.size();
- }
- /** @} */
- public:
- void computeBoundingBox(BoundingBox &bbox) {
- resize(bbox, (DIM > 0 ? DIM : BaseClassRef::dim));
- if (dataset.kdtree_get_bbox(bbox)) {
- // Done! It was implemented in derived class
- } else {
- const size_t N = BaseClassRef::m_size;
- if (!N)
- throw std::runtime_error("[nanoflann] computeBoundingBox() called but "
- "no data points found.");
- for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) {
- bbox[i].low = bbox[i].high =
- this->dataset_get(*this, BaseClassRef::vind[0], i);
- }
- for (size_t k = 1; k < N; ++k) {
- for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) {
- if (this->dataset_get(*this, BaseClassRef::vind[k], i) < bbox[i].low)
- bbox[i].low = this->dataset_get(*this, BaseClassRef::vind[k], i);
- if (this->dataset_get(*this, BaseClassRef::vind[k], i) > bbox[i].high)
- bbox[i].high = this->dataset_get(*this, BaseClassRef::vind[k], i);
- }
- }
- }
- }
- /**
- * Performs an exact search in the tree starting from a node.
- * \tparam RESULTSET Should be any ResultSet<DistanceType>
- */
- template <class RESULTSET>
- void searchLevel(RESULTSET &result_set, const ElementType *vec,
- const NodePtr node, DistanceType mindistsq,
- distance_vector_t &dists, const float epsError) const {
- /* If this is a leaf node, then do check and return. */
- if ((node->child1 == NULL) && (node->child2 == NULL)) {
- // count_leaf += (node->lr.right-node->lr.left); // Removed since was
- // neither used nor returned to the user.
- DistanceType worst_dist = result_set.worstDist();
- for (IndexType i = node->node_type.lr.left; i < node->node_type.lr.right;
- ++i) {
- const IndexType index = BaseClassRef::vind[i]; // reorder... : i;
- if (treeIndex[index] == -1)
- continue;
- DistanceType dist = distance.evalMetric(
- vec, index, (DIM > 0 ? DIM : BaseClassRef::dim));
- if (dist < worst_dist) {
- if (!result_set.addPoint(
- static_cast<typename RESULTSET::DistanceType>(dist),
- static_cast<typename RESULTSET::IndexType>(
- BaseClassRef::vind[i]))) {
- // the resultset doesn't want to receive any more points, we're done
- // searching!
- return; // false;
- }
- }
- }
- return;
- }
- /* Which child branch should be taken first? */
- int idx = node->node_type.sub.divfeat;
- ElementType val = vec[idx];
- DistanceType diff1 = val - node->node_type.sub.divlow;
- DistanceType diff2 = val - node->node_type.sub.divhigh;
- NodePtr bestChild;
- NodePtr otherChild;
- DistanceType cut_dist;
- if ((diff1 + diff2) < 0) {
- bestChild = node->child1;
- otherChild = node->child2;
- cut_dist = distance.accum_dist(val, node->node_type.sub.divhigh, idx);
- } else {
- bestChild = node->child2;
- otherChild = node->child1;
- cut_dist = distance.accum_dist(val, node->node_type.sub.divlow, idx);
- }
- /* Call recursively to search next level down. */
- searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError);
- DistanceType dst = dists[idx];
- mindistsq = mindistsq + cut_dist - dst;
- dists[idx] = cut_dist;
- if (mindistsq * epsError <= result_set.worstDist()) {
- searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError);
- }
- dists[idx] = dst;
- }
- public:
- /** Stores the index in a binary file.
- * IMPORTANT NOTE: The set of data points is NOT stored in the file, so when
- * loading the index object it must be constructed associated to the same
- * source of data points used while building it. See the example:
- * examples/saveload_example.cpp \sa loadIndex */
- void saveIndex(FILE *stream) { this->saveIndex_(*this, stream); }
- /** Loads a previous index from a binary file.
- * IMPORTANT NOTE: The set of data points is NOT stored in the file, so the
- * index object must be constructed associated to the same source of data
- * points used while building the index. See the example:
- * examples/saveload_example.cpp \sa loadIndex */
- void loadIndex(FILE *stream) { this->loadIndex_(*this, stream); }
- };
- /** kd-tree dynaimic index
- *
- * class to create multiple static index and merge their results to behave as
- * single dynamic index as proposed in Logarithmic Approach.
- *
- * Example of usage:
- * examples/dynamic_pointcloud_example.cpp
- *
- * \tparam DatasetAdaptor The user-provided adaptor (see comments above).
- * \tparam Distance The distance metric to use: nanoflann::metric_L1,
- * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. \tparam DIM
- * Dimensionality of data points (e.g. 3 for 3D points) \tparam IndexType Will
- * be typically size_t or int
- */
- template <typename Distance, class DatasetAdaptor, int DIM = -1,
- typename IndexType = size_t>
- class KDTreeSingleIndexDynamicAdaptor {
- public:
- typedef typename Distance::ElementType ElementType;
- typedef typename Distance::DistanceType DistanceType;
- protected:
- size_t m_leaf_max_size;
- size_t treeCount;
- size_t pointCount;
- /**
- * The dataset used by this index
- */
- const DatasetAdaptor &dataset; //!< The source of our data
- std::vector<int> treeIndex; //!< treeIndex[idx] is the index of tree in which
- //!< point at idx is stored. treeIndex[idx]=-1
- //!< means that point has been removed.
- KDTreeSingleIndexAdaptorParams index_params;
- int dim; //!< Dimensionality of each data point
- typedef KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>
- index_container_t;
- std::vector<index_container_t> index;
- public:
- /** Get a const ref to the internal list of indices; the number of indices is
- * adapted dynamically as the dataset grows in size. */
- const std::vector<index_container_t> &getAllIndices() const { return index; }
- private:
- /** finds position of least significant unset bit */
- int First0Bit(IndexType num) {
- int pos = 0;
- while (num & 1) {
- num = num >> 1;
- pos++;
- }
- return pos;
- }
- /** Creates multiple empty trees to handle dynamic support */
- void init() {
- typedef KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM>
- my_kd_tree_t;
- std::vector<my_kd_tree_t> index_(
- treeCount, my_kd_tree_t(dim /*dim*/, dataset, treeIndex, index_params));
- index = index_;
- }
- public:
- Distance distance;
- /**
- * KDTree constructor
- *
- * Refer to docs in README.md or online in
- * https://github.com/jlblancoc/nanoflann
- *
- * The KD-Tree point dimension (the length of each point in the datase, e.g. 3
- * for 3D points) is determined by means of:
- * - The \a DIM template parameter if >0 (highest priority)
- * - Otherwise, the \a dimensionality parameter of this constructor.
- *
- * @param inputData Dataset with the input features
- * @param params Basically, the maximum leaf node size
- */
- KDTreeSingleIndexDynamicAdaptor(const int dimensionality,
- const DatasetAdaptor &inputData,
- const KDTreeSingleIndexAdaptorParams ¶ms =
- KDTreeSingleIndexAdaptorParams(),
- const size_t maximumPointCount = 1000000000U)
- : dataset(inputData), index_params(params), distance(inputData) {
- treeCount = static_cast<size_t>(std::log2(maximumPointCount));
- pointCount = 0U;
- dim = dimensionality;
- treeIndex.clear();
- if (DIM > 0)
- dim = DIM;
- m_leaf_max_size = params.leaf_max_size;
- init();
- const size_t num_initial_points = dataset.kdtree_get_point_count();
- if (num_initial_points > 0) {
- addPoints(0, num_initial_points - 1);
- }
- }
- /** Deleted copy constructor*/
- KDTreeSingleIndexDynamicAdaptor(
- const KDTreeSingleIndexDynamicAdaptor<Distance, DatasetAdaptor, DIM,
- IndexType> &) = delete;
- /** Add points to the set, Inserts all points from [start, end] */
- void addPoints(IndexType start, IndexType end) {
- size_t count = end - start + 1;
- treeIndex.resize(treeIndex.size() + count);
- for (IndexType idx = start; idx <= end; idx++) {
- int pos = First0Bit(pointCount);
- index[pos].vind.clear();
- treeIndex[pointCount] = pos;
- for (int i = 0; i < pos; i++) {
- for (int j = 0; j < static_cast<int>(index[i].vind.size()); j++) {
- index[pos].vind.push_back(index[i].vind[j]);
- if (treeIndex[index[i].vind[j]] != -1)
- treeIndex[index[i].vind[j]] = pos;
- }
- index[i].vind.clear();
- index[i].freeIndex(index[i]);
- }
- index[pos].vind.push_back(idx);
- index[pos].buildIndex();
- pointCount++;
- }
- }
- /** Remove a point from the set (Lazy Deletion) */
- void removePoint(size_t idx) {
- if (idx >= pointCount)
- return;
- treeIndex[idx] = -1;
- }
- /**
- * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored
- * inside the result object.
- *
- * Params:
- * result = the result object in which the indices of the
- * nearest-neighbors are stored vec = the vector for which to search the
- * nearest neighbors
- *
- * \tparam RESULTSET Should be any ResultSet<DistanceType>
- * \return True if the requested neighbors could be found.
- * \sa knnSearch, radiusSearch
- */
- template <typename RESULTSET>
- bool findNeighbors(RESULTSET &result, const ElementType *vec,
- const SearchParams &searchParams) const {
- for (size_t i = 0; i < treeCount; i++) {
- index[i].findNeighbors(result, &vec[0], searchParams);
- }
- return result.full();
- }
- };
- /** An L2-metric KD-tree adaptor for working with data directly stored in an
- * Eigen Matrix, without duplicating the data storage. You can select whether a
- * row or column in the matrix represents a point in the state space.
- *
- * Example of usage:
- * \code
- * Eigen::Matrix<num_t,Dynamic,Dynamic> mat;
- * // Fill out "mat"...
- *
- * typedef KDTreeEigenMatrixAdaptor< Eigen::Matrix<num_t,Dynamic,Dynamic> >
- * my_kd_tree_t; const int max_leaf = 10; my_kd_tree_t mat_index(mat, max_leaf
- * ); mat_index.index->buildIndex(); mat_index.index->... \endcode
- *
- * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality
- * for the points in the data set, allowing more compiler optimizations. \tparam
- * Distance The distance metric to use: nanoflann::metric_L1,
- * nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. \tparam row_major
- * If set to true the rows of the matrix are used as the points, if set to false
- * the columns of the matrix are used as the points.
- */
- template <class MatrixType, int DIM = -1, class Distance = nanoflann::metric_L2,
- bool row_major = true>
- struct KDTreeEigenMatrixAdaptor {
- typedef KDTreeEigenMatrixAdaptor<MatrixType, DIM, Distance, row_major> self_t;
- typedef typename MatrixType::Scalar num_t;
- typedef typename MatrixType::Index IndexType;
- typedef
- typename Distance::template traits<num_t, self_t>::distance_t metric_t;
- typedef KDTreeSingleIndexAdaptor<metric_t, self_t,
- MatrixType::ColsAtCompileTime, IndexType>
- index_t;
- index_t *index; //! The kd-tree index for the user to call its methods as
- //! usual with any other FLANN index.
- /// Constructor: takes a const ref to the matrix object with the data points
- KDTreeEigenMatrixAdaptor(const size_t dimensionality,
- const std::reference_wrapper<const MatrixType> &mat,
- const int leaf_max_size = 10)
- : m_data_matrix(mat) {
- const auto dims = row_major ? mat.get().cols() : mat.get().rows();
- if (size_t(dims) != dimensionality)
- throw std::runtime_error(
- "Error: 'dimensionality' must match column count in data matrix");
- if (DIM > 0 && int(dims) != DIM)
- throw std::runtime_error(
- "Data set dimensionality does not match the 'DIM' template argument");
- index =
- new index_t(static_cast<int>(dims), *this /* adaptor */,
- nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size));
- index->buildIndex();
- }
- public:
- /** Deleted copy constructor */
- KDTreeEigenMatrixAdaptor(const self_t &) = delete;
- ~KDTreeEigenMatrixAdaptor() { delete index; }
- const std::reference_wrapper<const MatrixType> m_data_matrix;
- /** Query for the \a num_closest closest points to a given point (entered as
- * query_point[0:dim-1]). Note that this is a short-cut method for
- * index->findNeighbors(). The user can also call index->... methods as
- * desired. \note nChecks_IGNORED is ignored but kept for compatibility with
- * the original FLANN interface.
- */
- inline void query(const num_t *query_point, const size_t num_closest,
- IndexType *out_indices, num_t *out_distances_sq,
- const int /* nChecks_IGNORED */ = 10) const {
- nanoflann::KNNResultSet<num_t, IndexType> resultSet(num_closest);
- resultSet.init(out_indices, out_distances_sq);
- index->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
- }
- /** @name Interface expected by KDTreeSingleIndexAdaptor
- * @{ */
- const self_t &derived() const { return *this; }
- self_t &derived() { return *this; }
- // Must return the number of data points
- inline size_t kdtree_get_point_count() const {
- if(row_major)
- return m_data_matrix.get().rows();
- else
- return m_data_matrix.get().cols();
- }
- // Returns the dim'th component of the idx'th point in the class:
- inline num_t kdtree_get_pt(const IndexType idx, size_t dim) const {
- if(row_major)
- return m_data_matrix.get().coeff(idx, IndexType(dim));
- else
- return m_data_matrix.get().coeff(IndexType(dim), idx);
- }
- // Optional bounding-box computation: return false to default to a standard
- // bbox computation loop.
- // Return true if the BBOX was already computed by the class and returned in
- // "bb" so it can be avoided to redo it again. Look at bb.size() to find out
- // the expected dimensionality (e.g. 2 or 3 for point clouds)
- template <class BBOX> bool kdtree_get_bbox(BBOX & /*bb*/) const {
- return false;
- }
- /** @} */
- }; // end of KDTreeEigenMatrixAdaptor
- /** @} */
- /** @} */ // end of grouping
- } // namespace nanoflann
- #endif /* NANOFLANN_HPP_ */
|