From 34e2cc0fba58c15f64c24aa3a7c4184235fba1b9 Mon Sep 17 00:00:00 2001 From: Mathias Gehrig Date: Fri, 3 Nov 2017 20:52:52 +0100 Subject: [PATCH] Return numerically maximal index (unsigned) or -1 (signed) for no match case (#79) Additionally, provide public static access to invalid index and invalid distance values. --- nabo/index_heap.h | 18 +++++++++--------- nabo/nabo.cpp | 8 ++++---- nabo/nabo.h | 26 +++++++++++++++++++++----- tests/knnvalidate.cpp | 6 +++--- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/nabo/index_heap.h b/nabo/index_heap.h index 657689a..d1c82dc 100644 --- a/nabo/index_heap.h +++ b/nabo/index_heap.h @@ -73,7 +73,7 @@ namespace Nabo typedef typename Eigen::Matrix IndexVector; //! vector of values typedef typename Eigen::Matrix ValueVector; - + //! storage for the tree Entries data; //! number of neighbours requested @@ -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::infinity())), + data(1, Entry(invalidIndex(), invalidValue())), nbNeighbours(size) { data.reserve(size); @@ -93,7 +93,7 @@ namespace Nabo inline void reset() { data.clear(); - data.push_back(Entry(0, std::numeric_limits::infinity())); + data.push_back(Entry(invalidIndex(), invalidValue())); } //! get the largest value of the heap @@ -143,8 +143,8 @@ namespace Nabo } for (; i < nbNeighbours; ++i) { - const_cast&>(indices).coeffRef(i) = 0; - const_cast&>(values).coeffRef(i) = std::numeric_limits::infinity(); + const_cast&>(indices).coeffRef(i) = invalidIndex(); + const_cast&>(values).coeffRef(i) = invalidValue(); } } @@ -285,7 +285,7 @@ namespace Nabo typedef typename Eigen::Matrix IndexVector; //! vector of values typedef typename Eigen::Matrix ValueVector; - + //! storage for the tree Entries data; //! reference to the largest value in the tree, to optimise access speed @@ -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::infinity())), + data(size, Entry(invalidIndex(), invalidValue())), headValueRef((data.end() - 1)->value), sizeMinusOne(data.size() - 1) { @@ -307,8 +307,8 @@ namespace Nabo { for (typename Entries::iterator it(data.begin()); it != data.end(); ++it) { - it->value = std::numeric_limits::infinity(); - it->index = 0; + it->value = invalidValue(); + it->index = invalidIndex(); } } diff --git a/nabo/nabo.cpp b/nabo/nabo.cpp index 8aaaf37..6b32b7b 100644 --- a/nabo/nabo.cpp +++ b/nabo/nabo.cpp @@ -139,8 +139,8 @@ namespace Nabo switch (preferedType) { case BRUTE_FORCE: return new BruteForceSearch(cloud, dim, creationOptionFlags); - case KDTREE_LINEAR_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); - case KDTREE_TREE_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); + case KDTREE_LINEAR_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); + case KDTREE_TREE_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); #ifdef HAVE_OPENCL case KDTREE_CL_PT_IN_NODES: return new KDTreeBalancedPtInNodesStackOpenCL(cloud, dim, creationOptionFlags, CL_DEVICE_TYPE_GPU); case KDTREE_CL_PT_IN_LEAVES: return new KDTreeBalancedPtInLeavesStackOpenCL(cloud, dim, creationOptionFlags, CL_DEVICE_TYPE_GPU); @@ -167,7 +167,7 @@ namespace Nabo { if (dim <= 0) throw runtime_error() << "Your space must have at least one dimension"; - return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); + return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); } template @@ -175,7 +175,7 @@ namespace Nabo { if (dim <= 0) throw runtime_error() << "Your space must have at least one dimension"; - return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); + return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt, CloudType>(cloud, dim, creationOptionFlags, additionalParameters); } template struct NearestNeighbourSearch; diff --git a/nabo/nabo.h b/nabo/nabo.h index 018812b..06e6427 100644 --- a/nabo/nabo.h +++ b/nabo/nabo.h @@ -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 + inline constexpr IndexType invalidIndex() { + return std::is_unsigned::value ? std::numeric_limits::max() : IndexType(-1); + } + + template + inline constexpr ValueType invalidValue() { + return std::numeric_limits::infinity(); + } + //! Parameter vector // // TODO: replace with C++17 std::any. @@ -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(); + //! the invalid value + static constexpr T InvalidValue = invalidValue(); + //! type of search enum SearchType { @@ -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 @@ -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::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() @@ -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::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() diff --git a/tests/knnvalidate.cpp b/tests/knnvalidate.cpp index ad23f92..2430249 100644 --- a/tests/knnvalidate.cpp +++ b/tests/knnvalidate.cpp @@ -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::infinity()) + if (dists2_bf(k,i) == NNS::InvalidValue) continue; const int pbfi(indexes_bf(k,i)); const Vector pbf(d.col(pbfi)); @@ -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::epsilon()) + const T distDiff(fabsf((pbf-pq).squaredNorm() - (pkdtree-pq).squaredNorm())); + if (distDiff > numeric_limits::epsilon()) { cerr << "Method " << j << ", query point " << i << ", neighbour " << k << " of " << K << " is different between bf and kdtree (dist2 " << distDiff << ")\n"; cerr << "* query point:\n";