00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "nabo.h"
00033 #include "nabo_private.h"
00034 #include "index_heap.h"
00035 #include <limits>
00036 #include <algorithm>
00037 #include <stdexcept>
00038 #include <boost/format.hpp>
00039
00045 namespace Nabo
00046 {
00047 using namespace std;
00048
00049 template<typename T>
00050 NearestNeighbourSearch<T>::NearestNeighbourSearch(const Matrix& cloud, const Index dim, const unsigned creationOptionFlags):
00051 cloud(cloud),
00052 dim(min(dim, int(cloud.rows()))),
00053 creationOptionFlags(creationOptionFlags),
00054 minBound(Vector::Constant(this->dim, numeric_limits<T>::max())),
00055 maxBound(Vector::Constant(this->dim, numeric_limits<T>::min()))
00056 {
00057
00058 }
00059
00060 template<typename T>
00061 unsigned long NearestNeighbourSearch<T>::knn(const Vector& query, IndexVector& indices, Vector& dists2, const Index k, const T epsilon, const unsigned optionFlags, const T maxRadius) const
00062 {
00063 #ifdef EIGEN3_API
00064 const Eigen::Map<const Matrix> queryMatrix(&query.coeff(0,0), dim, 1);
00065 #else // EIGEN3_API
00066 const Eigen::Map<Matrix> queryMatrix(&query.coeff(0,0), dim, 1);
00067 #endif // EIGEN3_API
00068
00069
00070
00071
00072 IndexMatrix indexMatrix(k, 1);
00073 Matrix dists2Matrix(k, 1);
00074 const unsigned long stats = knn(queryMatrix, indexMatrix, dists2Matrix, k, epsilon, optionFlags, maxRadius);
00075 indices = indexMatrix.col(0);
00076 dists2 = dists2Matrix.col(0);
00077 return stats;
00078 }
00079
00080 template<typename T>
00081 void NearestNeighbourSearch<T>::checkSizesKnn(const Matrix& query, const IndexMatrix& indices, const Matrix& dists2, const Index k, const Vector* maxRadii) const
00082 {
00083 if (query.rows() < dim)
00084 throw runtime_error((boost::format("Query has less dimensions (%1%) than requested for cloud (%2%)") % query.rows() % dim).str());
00085 if (indices.rows() != k)
00086 throw runtime_error((boost::format("Index matrix has a different number of rows (%1%) than k (%2%)") % indices.rows() % k).str());
00087 if (indices.cols() != query.cols())
00088 throw runtime_error((boost::format("Index matrix has a different number of columns (%1%) than query (%2%)") % indices.rows() % query.cols()).str());
00089 if (dists2.rows() != k)
00090 throw runtime_error((boost::format("Distance matrix has a different number of rows (%1%) than k (%2%)") % dists2.rows() % k).str());
00091 if (dists2.cols() != query.cols())
00092 throw runtime_error((boost::format("Distance matrix has a different number of columns (%1%) than query (%2%)") % dists2.rows() % query.cols()).str());
00093 if (maxRadii && (maxRadii->size() != query.cols()))
00094 throw runtime_error((boost::format("Maximum radii vector has not the same length (%1%) than query has columns (%2%)") % maxRadii->size() % k).str());
00095 }
00096
00097
00098 template<typename T>
00099 NearestNeighbourSearch<T>* NearestNeighbourSearch<T>::create(const Matrix& cloud, const Index dim, const SearchType preferedType, const unsigned creationOptionFlags, const Parameters& additionalParameters)
00100 {
00101 if (dim <= 0)
00102 throw runtime_error("Your space must have at least one dimension");
00103 switch (preferedType)
00104 {
00105 case BRUTE_FORCE: return new BruteForceSearch<T>(cloud, dim, creationOptionFlags);
00106 case KDTREE_LINEAR_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapBruteForceVector<int,T> >(cloud, dim, creationOptionFlags, additionalParameters);
00107 case KDTREE_TREE_HEAP: return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapSTL<int,T> >(cloud, dim, creationOptionFlags, additionalParameters);
00108 #ifdef HAVE_OPENCL
00109 case KDTREE_CL_PT_IN_NODES: return new KDTreeBalancedPtInNodesStackOpenCL<T>(cloud, dim, creationOptionFlags, CL_DEVICE_TYPE_GPU);
00110 case KDTREE_CL_PT_IN_LEAVES: return new KDTreeBalancedPtInLeavesStackOpenCL<T>(cloud, dim, creationOptionFlags, CL_DEVICE_TYPE_GPU);
00111 case BRUTE_FORCE_CL: return new BruteForceSearchOpenCL<T>(cloud, dim, creationOptionFlags, CL_DEVICE_TYPE_GPU);
00112 #else // HAVE_OPENCL
00113 case KDTREE_CL_PT_IN_NODES: throw runtime_error("OpenCL not found during compilation");
00114 case KDTREE_CL_PT_IN_LEAVES: throw runtime_error("OpenCL not found during compilation");
00115 case BRUTE_FORCE_CL: throw runtime_error("OpenCL not found during compilation");
00116 #endif // HAVE_OPENCL
00117 default: throw runtime_error("Unknown search type");
00118 }
00119 }
00120
00121 template<typename T>
00122 NearestNeighbourSearch<T>* NearestNeighbourSearch<T>::createBruteForce(const Matrix& cloud, const Index dim, const unsigned creationOptionFlags)
00123 {
00124 if (dim <= 0)
00125 throw runtime_error("Your space must have at least one dimension");
00126 return new BruteForceSearch<T>(cloud, dim, creationOptionFlags);
00127 }
00128
00129 template<typename T>
00130 NearestNeighbourSearch<T>* NearestNeighbourSearch<T>::createKDTreeLinearHeap(const Matrix& cloud, const Index dim, const unsigned creationOptionFlags, const Parameters& additionalParameters)
00131 {
00132 if (dim <= 0)
00133 throw runtime_error("Your space must have at least one dimension");
00134 return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapBruteForceVector<int,T> >(cloud, dim, creationOptionFlags, additionalParameters);
00135 }
00136
00137 template<typename T>
00138 NearestNeighbourSearch<T>* NearestNeighbourSearch<T>::createKDTreeTreeHeap(const Matrix& cloud, const Index dim, const unsigned creationOptionFlags, const Parameters& additionalParameters)
00139 {
00140 if (dim <= 0)
00141 throw runtime_error("Your space must have at least one dimension");
00142 return new KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, IndexHeapSTL<int,T> >(cloud, dim, creationOptionFlags, additionalParameters);
00143 }
00144
00145 template struct NearestNeighbourSearch<float>;
00146 template struct NearestNeighbourSearch<double>;
00147 }