63 for (T i = 0; i < 64; ++i)
76 template<
typename T,
typename CloudType>
81 for (
int i = 0; i < v.size(); ++i)
93 template<
typename T,
typename Heap,
typename CloudType>
96 T minVal(std::numeric_limits<T>::max());
97 T maxVal(std::numeric_limits<T>::lowest());
101 const T val(cloud.coeff(dim, *it));
102 minVal =
min(val, minVal);
103 maxVal =
max(val, maxVal);
106 return make_pair(minVal, maxVal);
109 template<
typename T,
typename Heap,
typename CloudType>
112 const int count(last - first);
114 const unsigned pos(nodes.size());
117 if (count <=
int(bucketSize))
119 const uint32_t initBucketsSize(buckets.size());
121 for (
int i = 0; i < count; ++i)
123 const Index index(*(first+i));
124 assert(index < cloud.cols());
125 buckets.push_back(
BucketEntry(&cloud.coeff(0, index), index));
129 nodes.push_back(
Node(createDimChildBucketSize(dim, count),initBucketsSize));
134 const unsigned cutDim = argMax<T, CloudType>(maxValues - minValues);
135 const T idealCutVal((maxValues(cutDim) + minValues(cutDim))/2);
138 const pair<T,T> minMaxVals(getBounds(first, last, cutDim));
142 if (idealCutVal < minMaxVals.first)
143 cutVal = minMaxVals.first;
144 else if (idealCutVal > minMaxVals.second)
145 cutVal = minMaxVals.second;
147 cutVal = idealCutVal;
154 while (l < count && cloud.coeff(cutDim, *(first+l)) < cutVal)
156 while (r >= 0 && cloud.coeff(cutDim, *(first+r)) >= cutVal)
160 swap(*(first+l), *(first+r));
168 while (l < count && cloud.coeff(cutDim, *(first+l)) <= cutVal)
170 while (r >= br1 && cloud.coeff(cutDim, *(first+r)) > cutVal)
174 swap(*(first+l), *(first+r));
181 if (idealCutVal < minMaxVals.first)
183 else if (idealCutVal > minMaxVals.second)
185 else if (br1 > count / 2)
187 else if (br2 < count / 2)
190 leftCount = count / 2;
191 assert(leftCount > 0);
205 assert(leftCount < count);
208 Vector leftMaxValues(maxValues);
209 leftMaxValues[cutDim] = cutVal;
211 Vector rightMinValues(minValues);
212 rightMinValues[cutDim] = cutVal;
215 nodes.push_back(
Node(0, cutVal));
218 const unsigned _UNUSED leftChild = buildNodes(first, first + leftCount, minValues, leftMaxValues);
219 assert(leftChild == pos + 1);
220 const unsigned rightChild = buildNodes(first + leftCount, last, rightMinValues, maxValues);
223 nodes[pos].dimChildBucketSize = createDimChildBucketSize(cutDim, rightChild);
227 template<
typename T,
typename Heap,
typename CloudType>
230 bucketSize(additionalParameters.
get<unsigned>(
"bucketSize", 8)),
232 dimMask((1<<dimBitCount)-1)
239 for (
int i = 0; i < cloud.cols(); ++i)
245 const uint64_t maxNodeCount((0x1ULL << (32-
dimBitCount)) - 1);
246 const uint64_t estimatedNodeCount(cloud.cols() / (
bucketSize / 2));
247 if (estimatedNodeCount > maxNodeCount)
249 throw runtime_error(
"Cloud has a risk to have more nodes (" + std::to_string(estimatedNodeCount) +
") than the kd-tree allows (" + std::to_string(maxNodeCount) +
"). " 250 "The kd-tree has " + std::to_string(
dimBitCount) +
" bits for dimensions and " + std::to_string((32-
dimBitCount)) +
" bits for node indices");
255 buildPoints.reserve(cloud.cols());
256 for (
int i = 0; i < cloud.cols(); ++i)
258 const Vector& v(cloud.block(0,i,this->dim,1));
259 buildPoints.push_back(i);
274 template<
typename T,
typename Heap,
typename CloudType>
282 const T maxRadius2(maxRadius * maxRadius);
283 const T maxError2((1+epsilon)*(1+epsilon));
284 const int colCount(query.cols());
286 assert(
nodes.size() > 0);
289 unsigned long leafTouchedCount(0);
295 std::vector<T> off(
dim, 0);
297 #pragma omp for reduction(+:leafTouchedCount) schedule(guided,32) 298 for (
int i = 0; i < colCount; ++i)
300 leafTouchedCount +=
onePointKnn(query, indices, dists2, i, heap, off, maxError2, maxRadius2, allowSelfMatch, collectStatistics, sortResults);
303 return leafTouchedCount;
306 template<
typename T,
typename Heap,
typename CloudType>
309 checkSizesKnn(query, indices, dists2, k, optionFlags, &maxRadii);
314 const T maxError2((1+epsilon)*(1+epsilon));
315 const int colCount(query.cols());
317 assert(
nodes.size() > 0);
319 unsigned long leafTouchedCount(0);
325 std::vector<T> off(
dim, 0);
327 #pragma omp for reduction(+:leafTouchedCount) schedule(guided,32) 328 for (
int i = 0; i < colCount; ++i)
330 const T maxRadius(maxRadii[i]);
331 const T maxRadius2(maxRadius * maxRadius);
332 leafTouchedCount +=
onePointKnn(query, indices, dists2, i, heap, off, maxError2, maxRadius2, allowSelfMatch, collectStatistics, sortResults);
335 return leafTouchedCount;
338 template<
typename T,
typename Heap,
typename CloudType>
339 unsigned long KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<T, Heap, CloudType>::onePointKnn(
const Matrix& query,
IndexMatrix& indices,
Matrix& dists2,
int i, Heap& heap, std::vector<T>& off,
const T maxError2,
const T maxRadius2,
const bool allowSelfMatch,
const bool collectStatistics,
const bool sortResults)
const 341 fill(off.begin(), off.end(),
static_cast<T
>(0));
343 unsigned long leafTouchedCount(0);
347 if (collectStatistics)
348 leafTouchedCount += recurseKnn<true, true>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
350 recurseKnn<true, false>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
354 if (collectStatistics)
355 leafTouchedCount += recurseKnn<false, true>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
357 recurseKnn<false, false>(&query.coeff(0, i), 0, 0, heap, off, maxError2, maxRadius2);
363 heap.getData(indices.col(i), dists2.col(i));
364 return leafTouchedCount;
367 template<
typename T,
typename Heap,
typename CloudType>
template<
bool allowSelfMatch,
bool collectStatistics>
373 if (cd == uint32_t(
dim))
384 const T* qPtr(query);
385 const T* dPtr(bucket->
pt);
386 for (
int i = 0; i < this->
dim; ++i)
388 const T
diff(*qPtr - *dPtr);
392 if ((dist <= maxRadius2) &&
393 (dist < heap.headValue()) &&
394 (allowSelfMatch || (dist > numeric_limits<T>::epsilon()))
396 heap.replaceHead(bucket->
index, dist);
404 unsigned long leafVisitedCount(0);
407 const T old_off(offcd);
408 const T new_off(query[cd] - node.
cutVal);
411 if (collectStatistics)
412 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
414 recurseKnn<allowSelfMatch, false>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
415 rd += - old_off*old_off + new_off*new_off;
416 if ((rd <= maxRadius2) &&
417 (rd * maxError2 < heap.headValue()))
420 if (collectStatistics)
421 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, n + 1, rd, heap, off, maxError2, maxRadius2);
423 recurseKnn<allowSelfMatch, false>(query, n + 1, rd, heap, off, maxError2, maxRadius2);
429 if (collectStatistics)
430 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, n+1, rd, heap, off, maxError2, maxRadius2);
432 recurseKnn<allowSelfMatch, false>(query, n+1, rd, heap, off, maxError2, maxRadius2);
433 rd += - old_off*old_off + new_off*new_off;
434 if ((rd <= maxRadius2) &&
435 (rd * maxError2 < heap.headValue()))
438 if (collectStatistics)
439 leafVisitedCount += recurseKnn<allowSelfMatch, true>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
441 recurseKnn<allowSelfMatch, false>(query, rightChild, rd, heap, off, maxError2, maxRadius2);
445 return leafVisitedCount;
Index index
index of point
uint32_t createDimChildBucketSize(const uint32_t dim, const uint32_t childIndex) const
create the compound index containing the dimension and the index of the child or the bucket size ...
KDTree, unbalanced, points in leaves, stack, implicit bounds, ANN_KD_SL_MIDPT, optimised implementati...
const unsigned creationOptionFlags
creation options
NearestNeighbourSearch< T, CloudType >::IndexMatrix IndexMatrix
T cutVal
for split node, split value
NearestNeighbourSearch< T, CloudType >::Index Index
std::vector< Index > BuildPoints
indices of points during kd-tree construction
NearestNeighbourSearch< T, CloudType >::Vector Vector
unsigned long onePointKnn(const Matrix &query, IndexMatrix &indices, Matrix &dists2, int i, Heap &heap, std::vector< T > &off, const T maxError, const T maxRadius2, const bool allowSelfMatch, const bool collectStatistics, const bool sortResults) const
search one point, call recurseKnn with the correct template parameters
BuildPoints::iterator BuildPointsIt
iterator to indices of points during kd-tree construction
implementation of index heaps
void checkSizesKnn(const Matrix &query, const IndexMatrix &indices, const Matrix &dists2, const Index k, const unsigned optionFlags, const Vector *maxRadii=0) const
Make sure that the output matrices have the right sizes. Throw an exception otherwise.
Nearest neighbour search interface, templatized on scalar type.
T getStorageBitCount(T v)
Return the number of bit required to store a value.
IMETHOD Vector diff(const Vector &p_w_a, const Vector &p_w_b, double dt=1)
void swap(linb::any &lhs, linb::any &rhs) noexcept
NearestNeighbourSearch< T, CloudType >::Matrix Matrix
unsigned buildNodes(const BuildPointsIt first, const BuildPointsIt last, const Vector minValues, const Vector maxValues)
construct nodes for points [first..last[ inside the hyperrectangle [minValues..maxValues] ...
KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt(const CloudType &cloud, const Index dim, const unsigned creationOptionFlags, const Parameters &additionalParameters)
constructor, calls NearestNeighbourSearch<T>(cloud)
uint32_t getDim(const uint32_t dimChildBucketSize) const
get the dimension out of the compound index
unsigned long recurseKnn(const T *query, const unsigned n, T rd, Heap &heap, std::vector< T > &off, const T maxError, const T maxRadius2) const
recursive search, strongly inspired by ANN and [Arya & Mount, Algorithms for fast vector quantization...
size_t argMax(const typename NearestNeighbourSearch< T, CloudType >::Vector &v)
Return the index of the maximum value of a vector of positive values.
const Vector maxBound
the high bound of the search space (axis-aligned bounding box)
double min(double a, double b)
const M::mapped_type & get(const M &m, const typename M::key_type &k)
uint32_t getChildBucketSize(const uint32_t dimChildBucketSize) const
get the child index or the bucket size out of the coumpount index
const Vector minBound
the low bound of the search space (axis-aligned bounding box)
std::pair< T, T > getBounds(const BuildPointsIt first, const BuildPointsIt last, const unsigned dim)
return the bounds of points from [first..last[ on dimension dim
const unsigned bucketSize
size of bucket
const Index dim
the dimensionality of the data-point cloud
BuildPoints::const_iterator BuildPointsCstIt
const-iterator to indices of points during kd-tree construction
uint32_t bucketIndex
for leaf node, pointer to bucket
uint32_t dimChildBucketSize
cut dimension for split nodes (dimBitCount lsb), index of right node or number of bucket(rest)...
virtual unsigned long knn(const Matrix &query, IndexMatrix &indices, Matrix &dists2, const Index k, const T epsilon, const unsigned optionFlags, const T maxRadius) const
double max(double a, double b)
const T * pt
pointer to first value of point data, 0 if end of bucket
header for implementation
const uint32_t dimBitCount
number of bits required to store dimension index + number of dimensions