8#ifndef LAR_KD_TREE_LINKER_ALGO_TEMPLATED_H
9#define LAR_KD_TREE_LINKER_ALGO_TEMPLATED_H
21template <
typename DATA,
unsigned DIM = 2>
161template <
typename DATA,
unsigned DIM>
167 closestNeighbour(nullptr),
168 initialEltList(nullptr)
174template <
typename DATA,
unsigned DIM>
182template <
typename DATA,
unsigned DIM>
187 initialEltList = &eltList;
188 const size_t mysize = initialEltList->size();
190 nodePoolSize_ = mysize * 2 - 1;
194 root_ = this->recBuild(0, mysize, 0, region);
195 initialEltList =
nullptr;
201template <
typename DATA,
unsigned DIM>
207 const int nbrElts = high - low;
208 int median = nbrElts / 2 - (1 - 1 * (nbrElts & 1));
223 const unsigned thedim = treeDepth % DIM;
224 while ((*initialEltList)[i].dims[thedim] < elt.
dims[thedim])
226 while ((*initialEltList)[j].dims[thedim] > elt.
dims[thedim])
231 std::swap((*initialEltList)[i], (*initialEltList)[j]);
248template <
typename DATA,
unsigned DIM>
253 closestNeighbour = &recHits;
254 this->recSearch(root_, trackBox);
255 closestNeighbour =
nullptr;
261template <
typename DATA,
unsigned DIM>
269 if ((current->
left ==
nullptr) && (current->
right ==
nullptr))
273 bool isInside =
true;
275 for (
unsigned i = 0; i < DIM; ++i)
277 const auto thedim = current->
info.dims[i];
278 isInside = isInside && thedim >= trackBox.
dimmin[i] && thedim <= trackBox.
dimmax[i];
282 closestNeighbour->push_back(current->
info);
288 bool isFullyContained =
true;
289 bool hasIntersection =
true;
291 for (
unsigned i = 0; i < DIM; ++i)
293 const auto regionmin = current->
left->region.dimmin[i];
294 const auto regionmax = current->
left->region.dimmax[i];
295 isFullyContained = isFullyContained && (regionmin >= trackBox.
dimmin[i] && regionmax <= trackBox.
dimmax[i]);
296 hasIntersection = hasIntersection && (regionmin < trackBox.
dimmax[i] && regionmax > trackBox.
dimmin[i]);
299 if (isFullyContained)
301 this->addSubtree(current->
left);
303 else if (hasIntersection)
305 this->recSearch(current->
left, trackBox);
309 isFullyContained =
true;
310 hasIntersection =
true;
312 for (
unsigned i = 0; i < DIM; ++i)
314 const auto regionmin = current->
right->region.dimmin[i];
315 const auto regionmax = current->
right->region.dimmax[i];
316 isFullyContained = isFullyContained && (regionmin >= trackBox.
dimmin[i] && regionmax <= trackBox.
dimmax[i]);
317 hasIntersection = hasIntersection && (regionmin < trackBox.
dimmax[i] && regionmax > trackBox.
dimmin[i]);
320 if (isFullyContained)
322 this->addSubtree(current->
right);
324 else if (hasIntersection)
326 this->recSearch(current->
right, trackBox);
333template <
typename DATA,
unsigned DIM>
337 if (
nullptr != result || distance != std::numeric_limits<float>::max())
340 distance = std::numeric_limits<float>::max();
346 this->recNearestNeighbour(0, root_, point, best_match, distance);
348 if (distance != std::numeric_limits<float>::max())
350 result = &(best_match->
info);
351 distance = std::sqrt(distance);
358template <
typename DATA,
unsigned DIM>
362 const unsigned int current_dim = depth % DIM;
364 if (current->
left ==
nullptr && current->
right ==
nullptr)
366 best_match = current;
367 best_dist = this->dist2(point, best_match->
info);
372 const float dist_to_axis = point.
dims[current_dim] - current->
info.dims[current_dim];
374 if (dist_to_axis < 0.f)
376 this->recNearestNeighbour(depth + 1, current->
left, point, best_match, best_dist);
380 this->recNearestNeighbour(depth + 1, current->
right, point, best_match, best_dist);
384 const float dist_current = this->dist2(point, current->
info);
386 if (dist_current < best_dist)
388 best_dist = dist_current;
389 best_match = current;
393 if (best_dist > dist_to_axis * dist_to_axis)
397 float check_dist = best_dist;
399 if (dist_to_axis < 0.f)
401 this->recNearestNeighbour(depth + 1, current->
right, point, check_best, check_dist);
405 this->recNearestNeighbour(depth + 1, current->
left, point, check_best, check_dist);
408 if (check_dist < best_dist)
410 best_dist = check_dist;
411 best_match = check_best;
420template <
typename DATA,
unsigned DIM>
426 if ((current->
left ==
nullptr) && (current->
right ==
nullptr))
429 closestNeighbour->push_back(current->
info);
434 this->addSubtree(current->
left);
435 this->addSubtree(current->
right);
441template <
typename DATA,
unsigned DIM>
446 for (
unsigned i = 0; i < DIM; ++i)
448 const double diff = a.
dims[i] - b.
dims[i];
457template <
typename DATA,
unsigned DIM>
469template <
typename DATA,
unsigned DIM>
472 return (nodePoolPos_ == -1);
477template <
typename DATA,
unsigned DIM>
480 return (nodePoolPos_ + 1);
485template <
typename DATA,
unsigned DIM>
494template <
typename DATA,
unsigned DIM>
503 return &(nodePool_[nodePoolPos_]);
508template <
typename DATA,
unsigned DIM>
511 const int portionSize = high - low;
516 if (portionSize == 1)
526 int medianId = this->medianSearch(low, high, depth);
531 node->
info = (*initialEltList)[medianId];
537 const unsigned thedim = depth % DIM;
538 auto medianVal = (*initialEltList)[medianId].dims[thedim];
539 leftRegion.
dimmax[thedim] = medianVal;
540 rightRegion.
dimmin[thedim] = medianVal;
546 node->
left = this->recBuild(low, medianId, depth, leftRegion);
547 node->
right = this->recBuild(medianId, high, depth, rightRegion);
Box structure used to define 2D field. It's used in KDTree building step to divide the detector space...
std::array< float, DIM > dimmax
std::array< float, DIM > dimmin
Class that implements the KDTree partition of 2D space and a closest point search algorithm.
KDTreeLinkerAlgo()
Default constructor.
void recSearch(const KDTreeNodeT< DATA, DIM > *current, const KDTreeBoxT< DIM > &trackBox)
Recursive kdtree search. Is called by search()
std::vector< KDTreeNodeInfoT< DATA, DIM > > * initialEltList
The initial element list.
int medianSearch(int low, int high, int treeDepth)
Fast median search with Wirth algorithm in eltList between low and high indexes.
void clearTree()
Frees the KDTree.
void addSubtree(const KDTreeNodeT< DATA, DIM > *current)
Add all elements of an subtree to the closest elements. Used during the recSearch().
~KDTreeLinkerAlgo()
Destructor calls clear.
KDTreeNodeT< DATA, DIM > * root_
The KDTree root.
int size()
Return the number of nodes + leaves in the tree (nElements should be (size() +1) / 2)
int nodePoolPos_
The node pool position.
void recNearestNeighbour(unsigned depth, const KDTreeNodeT< DATA, DIM > *current, const KDTreeNodeInfoT< DATA, DIM > &point, const KDTreeNodeT< DATA, DIM > *&best_match, float &best_dist)
Recursive nearest neighbour search. Is called by findNearestNeighbour()
int nodePoolSize_
The node pool size.
void clear()
Clear all allocated structures.
void build(std::vector< KDTreeNodeInfoT< DATA, DIM > > &eltList, const KDTreeBoxT< DIM > ®ion)
Build the KD tree from the "eltList" in the space define by "region".
KDTreeNodeT< DATA, DIM > * nodePool_
Node pool allows us to do just 1 call to new for each tree building.
void search(const KDTreeBoxT< DIM > &searchBox, std::vector< KDTreeNodeInfoT< DATA, DIM > > &resRecHitList)
Search in the KDTree for all points that would be contained in the given searchbox The founded points...
KDTreeNodeT< DATA, DIM > * getNextNode()
Get the next node from the node pool.
KDTreeNodeT< DATA, DIM > * recBuild(int low, int high, int depth, const KDTreeBoxT< DIM > ®ion)
Recursive kdtree builder. Is called by build()
std::vector< KDTreeNodeInfoT< DATA, DIM > > * closestNeighbour
The closest neighbour.
bool empty()
Whether the tree is empty.
float dist2(const KDTreeNodeInfoT< DATA, DIM > &a, const KDTreeNodeInfoT< DATA, DIM > &b) const
dist2
void findNearestNeighbour(const KDTreeNodeInfoT< DATA, DIM > &point, const KDTreeNodeInfoT< DATA, DIM > *&result, float &distance)
findNearestNeighbour
Data stored in each KDTree node. The dim1/dim2 fields are usually the duplication of some PFRecHit va...
std::array< float, DIM > dims
KDTreeNodeT< DATA, DIM > * left
Left son.
void setAttributs(const KDTreeBoxT< DIM > ®ionBox, const KDTreeNodeInfoT< DATA, DIM > &infoToStore)
setAttributs
KDTreeNodeInfoT< DATA, DIM > info
Data.
KDTreeNodeT< DATA, DIM > * right
Right son.