Skip to content

Commit

Permalink
Return numerically maximal index (unsigned) or -1 (signed) for no mat…
Browse files Browse the repository at this point in the history
…ch case (#79)

Additionally, provide public static access to invalid index and invalid distance values.
  • Loading branch information
magehrig authored Nov 3, 2017
1 parent 243a708 commit 34e2cc0
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 21 deletions.
18 changes: 9 additions & 9 deletions nabo/index_heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ namespace Nabo
typedef typename Eigen::Matrix<Index, Eigen::Dynamic, 1> IndexVector;
//! vector of values
typedef typename Eigen::Matrix<Value, Eigen::Dynamic, 1> ValueVector;

//! storage for the tree
Entries data;
//! number of neighbours requested
Expand All @@ -83,7 +83,7 @@ namespace Nabo
//! Constructor
/*! \param size number of elements in the heap */
IndexHeapSTL(const size_t size):
data(1, Entry(0, std::numeric_limits<VT>::infinity())),
data(1, Entry(invalidIndex<IT>(), invalidValue<VT>())),
nbNeighbours(size)
{
data.reserve(size);
Expand All @@ -93,7 +93,7 @@ namespace Nabo
inline void reset()
{
data.clear();
data.push_back(Entry(0, std::numeric_limits<VT>::infinity()));
data.push_back(Entry(invalidIndex<IT>(), invalidValue<VT>()));
}

//! get the largest value of the heap
Expand Down Expand Up @@ -143,8 +143,8 @@ namespace Nabo
}
for (; i < nbNeighbours; ++i)
{
const_cast<Eigen::MatrixBase<DI>&>(indices).coeffRef(i) = 0;
const_cast<Eigen::MatrixBase<DV>&>(values).coeffRef(i) = std::numeric_limits<VT>::infinity();
const_cast<Eigen::MatrixBase<DI>&>(indices).coeffRef(i) = invalidIndex<IT>();
const_cast<Eigen::MatrixBase<DV>&>(values).coeffRef(i) = invalidValue<VT>();
}
}

Expand Down Expand Up @@ -285,7 +285,7 @@ namespace Nabo
typedef typename Eigen::Matrix<Index, Eigen::Dynamic, 1> IndexVector;
//! vector of values
typedef typename Eigen::Matrix<Value, Eigen::Dynamic, 1> ValueVector;

//! storage for the tree
Entries data;
//! reference to the largest value in the tree, to optimise access speed
Expand All @@ -296,7 +296,7 @@ namespace Nabo
//! Constructor
/*! \param size number of elements in the heap */
IndexHeapBruteForceVector(const size_t size):
data(size, Entry(0, std::numeric_limits<VT>::infinity())),
data(size, Entry(invalidIndex<IT>(), invalidValue<VT>())),
headValueRef((data.end() - 1)->value),
sizeMinusOne(data.size() - 1)
{
Expand All @@ -307,8 +307,8 @@ namespace Nabo
{
for (typename Entries::iterator it(data.begin()); it != data.end(); ++it)
{
it->value = std::numeric_limits<VT>::infinity();
it->index = 0;
it->value = invalidValue<VT>();
it->index = invalidIndex<IT>();
}
}

Expand Down
8 changes: 4 additions & 4 deletions nabo/nabo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ namespace Nabo
switch (preferedType)
{
case BRUTE_FORCE: return new BruteForceSearch<T, CloudType>(cloud, dim, creationOptionFlags);
case KDTREE_LINEAR_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapBruteForceVector<int,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
case KDTREE_TREE_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapSTL<int,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
case KDTREE_LINEAR_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapBruteForceVector<Index,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
case KDTREE_TREE_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapSTL<Index,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
#ifdef HAVE_OPENCL
case KDTREE_CL_PT_IN_NODES: return new KDTreeBalancedPtInNodesStackOpenCL<T, CloudType>(cloud, dim, creationOptionFlags, CL_DEVICE_TYPE_GPU);
case KDTREE_CL_PT_IN_LEAVES: return new KDTreeBalancedPtInLeavesStackOpenCL<T, CloudType>(cloud, dim, creationOptionFlags, CL_DEVICE_TYPE_GPU);
Expand All @@ -167,15 +167,15 @@ namespace Nabo
{
if (dim <= 0)
throw runtime_error() << "Your space must have at least one dimension";
return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapBruteForceVector<int,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapBruteForceVector<Index,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
}

template<typename T, typename CloudType>
NearestNeighbourSearch<T, CloudType>* NearestNeighbourSearch<T, CloudType>::createKDTreeTreeHeap(const CloudType& cloud, const Index dim, const unsigned creationOptionFlags, const Parameters& additionalParameters)
{
if (dim <= 0)
throw runtime_error() << "Your space must have at least one dimension";
return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapSTL<int,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapSTL<Index,T>, CloudType>(cloud, dim, creationOptionFlags, additionalParameters);
}

template struct NearestNeighbourSearch<float>;
Expand Down
26 changes: 21 additions & 5 deletions nabo/nabo.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,18 @@ namespace Nabo
#define NABO_VERSION "1.0.6"
//! version of the Nabo library as an int
#define NABO_VERSION_INT 10006


// TODO (c++14) Convert invalidIndex, invalidValue to constexpr templated variables.
template <typename IndexType>
inline constexpr IndexType invalidIndex() {
return std::is_unsigned<IndexType>::value ? std::numeric_limits<IndexType>::max() : IndexType(-1);
}

template <typename ValueType>
inline constexpr ValueType invalidValue() {
return std::numeric_limits<ValueType>::infinity();
}

//! Parameter vector
//
// TODO: replace with C++17 std::any.
Expand Down Expand Up @@ -269,7 +280,12 @@ namespace Nabo
const Vector minBound;
//! the high bound of the search space (axis-aligned bounding box)
const Vector maxBound;


//! the invalid index
static constexpr Index InvalidIndex = invalidIndex<Index>();
//! the invalid value
static constexpr T InvalidValue = invalidValue<T>();

//! type of search
enum SearchType
{
Expand All @@ -296,7 +312,7 @@ namespace Nabo
};

//! Find the k nearest neighbours of query
/*! If the search finds less than k points, the empty entries in dists2 will be filled with infinity and the indices with 0. If you must query more than one point at once, use the version of the knn() function taking matrices as input, because it is much faster.
/*! If the search finds less than k points, the empty entries in dists2 will be filled with InvalidValue and the indices with InvalidIndex. If you must query more than one point at once, use the version of the knn() function taking matrices as input, because it is much faster.
* \param query query point
* \param indices indices of nearest neighbours, must be of size k
* \param dists2 squared distances to nearest neighbours, must be of size k
Expand All @@ -309,7 +325,7 @@ namespace Nabo
unsigned long knn(const Vector& query, IndexVector& indices, Vector& dists2, const Index k = 1, const T epsilon = 0, const unsigned optionFlags = 0, const T maxRadius = std::numeric_limits<T>::infinity()) const;

//! Find the k nearest neighbours for each point of query
/*! If the search finds less than k points, the empty entries in dists2 will be filled with infinity and the indices with 0.
/*! If the search finds less than k points, the empty entries in dists2 will be filled with InvalidValue and the indices with InvalidIndex.
* \param query query points
* \param indices indices of nearest neighbours, must be of size k x query.cols()
* \param dists2 squared distances to nearest neighbours, must be of size k x query.cols()
Expand All @@ -322,7 +338,7 @@ namespace Nabo
virtual unsigned long knn(const Matrix& query, IndexMatrix& indices, Matrix& dists2, const Index k = 1, const T epsilon = 0, const unsigned optionFlags = 0, const T maxRadius = std::numeric_limits<T>::infinity()) const = 0;

//! Find the k nearest neighbours for each point of query
/*! If the search finds less than k points, the empty entries in dists2 will be filled with infinity and the indices with 0.
/*! If the search finds less than k points, the empty entries in dists2 will be filled with InvalidValue and the indices with InvalidIndex.
* \param query query points
* \param indices indices of nearest neighbours, must be of size k x query.cols()
* \param dists2 squared distances to nearest neighbours, must be of size k x query.cols()
Expand Down
6 changes: 3 additions & 3 deletions tests/knnvalidate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ void validate(const char *fileName, const int K, const int dim, const int method
{
for (size_t k = 0; k < size_t(K); ++k)
{
if (dists2_bf(k,i) == numeric_limits<float>::infinity())
if (dists2_bf(k,i) == NNS::InvalidValue)
continue;
const int pbfi(indexes_bf(k,i));
const Vector pbf(d.col(pbfi));
Expand All @@ -190,8 +190,8 @@ void validate(const char *fileName, const int K, const int dim, const int method
}
const Vector pkdtree(d.col(pkdt));
const Vector pq(q.col(i));
const float distDiff(fabsf((pbf-pq).squaredNorm() - (pkdtree-pq).squaredNorm()));
if (distDiff > numeric_limits<float>::epsilon())
const T distDiff(fabsf((pbf-pq).squaredNorm() - (pkdtree-pq).squaredNorm()));
if (distDiff > numeric_limits<T>::epsilon())
{
cerr << "Method " << j << ", query point " << i << ", neighbour " << k << " of " << K << " is different between bf and kdtree (dist2 " << distDiff << ")\n";
cerr << "* query point:\n";
Expand Down

0 comments on commit 34e2cc0

Please sign in to comment.