Skip to content

Commit

Permalink
Merge pull request autowarefoundation#217 from jlblancoc/feature/rknn2
Browse files Browse the repository at this point in the history
Add RKNN searches, and more code coverage and tests
  • Loading branch information
jlblancoc authored Nov 27, 2023
2 parents 89a1166 + eba478c commit 67edc08
Showing 1 changed file with 119 additions and 3 deletions.
122 changes: 119 additions & 3 deletions include/nanoflann.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* 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-2022 Jose Luis Blanco (joseluisblancoc@gmail.com).
* Copyright 2011-2023 Jose Luis Blanco (joseluisblancoc@gmail.com).
* All rights reserved.
*
* THE BSD LICENSE
Expand Down Expand Up @@ -60,7 +60,7 @@
#include <vector>

/** Library version: 0xMmP (M=Major,m=minor,P=patch) */
#define NANOFLANN_VERSION 0x150
#define NANOFLANN_VERSION 0x151

// Avoid conflicting declaration of min/max macros in Windows headers
#if !defined(NOMINMAX) && \
Expand Down Expand Up @@ -158,6 +158,8 @@ inline typename std::enable_if<!has_assign<Container>::value, void>::type

/** @addtogroup result_sets_grp Result set classes
* @{ */

/** Result set for KNN searches (N-closest neighbors) */
template <
typename _DistanceType, typename _IndexType = size_t,
typename _CountType = size_t>
Expand Down Expand Up @@ -191,8 +193,92 @@ class KNNResultSet

CountType size() const { return count; }
bool empty() const { return count == 0; }
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
*/
bool addPoint(DistanceType dist, IndexType index)
{
CountType i;
for (i = count; i > 0; --i)
{
/** If defined and two points have the same distance, the one with
* the lowest-index will be returned first. */
#ifdef NANOFLANN_FIRST_MATCH
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;
}

DistanceType worstDist() const { return dists[capacity - 1]; }
};

/** Result set for RKNN searches (N-closest neighbors with a maximum radius) */
template <
typename _DistanceType, typename _IndexType = size_t,
typename _CountType = size_t>
class RKNNResultSet
{
public:
using DistanceType = _DistanceType;
using IndexType = _IndexType;
using CountType = _CountType;

bool full() const { return count == capacity; }
private:
IndexType* indices;
DistanceType* dists;
CountType capacity;
CountType count;
DistanceType maximumSearchDistanceSquared;

public:
explicit RKNNResultSet(
CountType capacity_, DistanceType maximumSearchDistanceSquared_)
: indices(nullptr),
dists(nullptr),
capacity(capacity_),
count(0),
maximumSearchDistanceSquared(maximumSearchDistanceSquared_)
{
}

void init(IndexType* indices_, DistanceType* dists_)
{
indices = indices_;
dists = dists_;
count = 0;
if (capacity)
dists[capacity - 1] = (std::numeric_limits<DistanceType>::max)();
}

CountType size() const { return count; }
bool empty() const { return count == 0; }
bool full() const { return count == capacity; }

/**
* Called during search to add an element matching the criteria.
Expand All @@ -201,6 +287,8 @@ class KNNResultSet
*/
bool addPoint(DistanceType dist, IndexType index)
{
if (dist > maximumSearchDistanceSquared) return true;

CountType i;
for (i = count; i > 0; --i)
{
Expand Down Expand Up @@ -1681,6 +1769,34 @@ class KDTreeSingleIndexAdaptor
return resultSet.size();
}

/**
* Find the first N 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.
*
* \sa radiusSearch, findNeighbors
* \return Number `N` of valid points in the result set.
*
* \note If L2 norms are used, all returned distances are actually squared
* distances.
*
* \note Only the first `N` entries in `out_indices` and `out_distances`
* will be valid. Return is less than `num_closest` only if the
* number of elements in the tree is less than `num_closest`.
*/
Size rknnSearch(
const ElementType* query_point, const Size num_closest,
IndexType* out_indices, DistanceType* out_distances,
const DistanceType& radius) const
{
nanoflann::RKNNResultSet<DistanceType, IndexType> resultSet(
num_closest, radius);
resultSet.init(out_indices, out_distances);
findNeighbors(resultSet, query_point);
return resultSet.size();
}

/** @} */

public:
Expand Down

0 comments on commit 67edc08

Please sign in to comment.