File indexing completed on 2026-09-27 09:15:00
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef LC_KD_TREE_LINKER_ALGO_TEMPLATED_H
0009 #define LC_KD_TREE_LINKER_ALGO_TEMPLATED_H
0010
0011 #include "LCUtility/KDTreeLinkerToolsT.h"
0012
0013 #include <vector>
0014
0015 namespace lc_content {
0016
0017
0018
0019
0020 template <typename DATA, unsigned DIM = 2>
0021 class KDTreeLinkerAlgo {
0022 public:
0023
0024
0025
0026 KDTreeLinkerAlgo();
0027
0028
0029
0030
0031 ~KDTreeLinkerAlgo();
0032
0033
0034
0035
0036
0037
0038
0039 void build(std::vector<KDTreeNodeInfoT<DATA, DIM>>& eltList, const KDTreeBoxT<DIM>& region);
0040
0041
0042
0043
0044
0045
0046
0047
0048 void search(const KDTreeBoxT<DIM>& searchBox, std::vector<KDTreeNodeInfoT<DATA, DIM>>& resRecHitList);
0049
0050
0051
0052
0053
0054
0055
0056
0057 void findNearestNeighbour(const KDTreeNodeInfoT<DATA, DIM>& point, const KDTreeNodeInfoT<DATA, DIM>*& result,
0058 float& distance);
0059
0060
0061
0062
0063
0064
0065 bool empty();
0066
0067
0068
0069
0070
0071
0072 int size();
0073
0074
0075
0076
0077 void clear();
0078
0079 private:
0080
0081
0082
0083
0084
0085 KDTreeNodeT<DATA, DIM>* getNextNode();
0086
0087
0088
0089
0090
0091
0092
0093
0094 int medianSearch(int low, int high, int treeDepth);
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 KDTreeNodeT<DATA, DIM>* recBuild(int low, int high, int depth, const KDTreeBoxT<DIM>& region);
0105
0106
0107
0108
0109
0110
0111
0112 void recSearch(const KDTreeNodeT<DATA, DIM>* current, const KDTreeBoxT<DIM>& trackBox);
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 void recNearestNeighbour(unsigned depth, const KDTreeNodeT<DATA, DIM>* current,
0124 const KDTreeNodeInfoT<DATA, DIM>& point, const KDTreeNodeT<DATA, DIM>*& best_match,
0125 float& best_dist);
0126
0127
0128
0129
0130
0131
0132 void addSubtree(const KDTreeNodeT<DATA, DIM>* current);
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142 float dist2(const KDTreeNodeInfoT<DATA, DIM>& a, const KDTreeNodeInfoT<DATA, DIM>& b) const;
0143
0144
0145
0146
0147 void clearTree();
0148
0149 KDTreeNodeT<DATA, DIM>* root_;
0150 KDTreeNodeT<DATA, DIM>* nodePool_;
0151 int nodePoolSize_;
0152 int nodePoolPos_;
0153
0154 std::vector<KDTreeNodeInfoT<DATA, DIM>>* closestNeighbour;
0155 std::vector<KDTreeNodeInfoT<DATA, DIM>>* initialEltList;
0156 };
0157
0158
0159
0160
0161 template <typename DATA, unsigned DIM>
0162 inline KDTreeLinkerAlgo<DATA, DIM>::KDTreeLinkerAlgo()
0163 : root_(nullptr), nodePool_(nullptr), nodePoolSize_(-1), nodePoolPos_(-1), closestNeighbour(nullptr),
0164 initialEltList(nullptr) {}
0165
0166
0167
0168 template <typename DATA, unsigned DIM>
0169 inline KDTreeLinkerAlgo<DATA, DIM>::~KDTreeLinkerAlgo() {
0170 this->clear();
0171 }
0172
0173
0174
0175 template <typename DATA, unsigned DIM>
0176 inline void KDTreeLinkerAlgo<DATA, DIM>::build(std::vector<KDTreeNodeInfoT<DATA, DIM>>& eltList,
0177 const KDTreeBoxT<DIM>& region) {
0178 if (eltList.size()) {
0179 initialEltList = &eltList;
0180 const size_t mysize = initialEltList->size();
0181
0182 nodePoolSize_ = mysize * 2 - 1;
0183 nodePool_ = new KDTreeNodeT<DATA, DIM>[nodePoolSize_];
0184
0185
0186 root_ = this->recBuild(0, mysize, 0, region);
0187 initialEltList = nullptr;
0188 }
0189 }
0190
0191
0192
0193 template <typename DATA, unsigned DIM>
0194 inline int KDTreeLinkerAlgo<DATA, DIM>::medianSearch(int low, int high, int treeDepth) {
0195
0196
0197
0198 const int nbrElts = high - low;
0199 int median = nbrElts / 2 - (1 - 1 * (nbrElts & 1));
0200 median += low;
0201
0202 int l = low;
0203 int m = high - 1;
0204
0205 while (l < m) {
0206 KDTreeNodeInfoT<DATA, DIM> elt = (*initialEltList)[median];
0207 int i = l;
0208 int j = m;
0209
0210 do {
0211
0212 const unsigned thedim = treeDepth % DIM;
0213 while ((*initialEltList)[i].dims[thedim] < elt.dims[thedim])
0214 ++i;
0215 while ((*initialEltList)[j].dims[thedim] > elt.dims[thedim])
0216 --j;
0217
0218 if (i <= j) {
0219 std::swap((*initialEltList)[i], (*initialEltList)[j]);
0220 i++;
0221 j--;
0222 }
0223 } while (i <= j);
0224
0225 if (j < median)
0226 l = i;
0227 if (i > median)
0228 m = j;
0229 }
0230
0231 return median;
0232 }
0233
0234
0235
0236 template <typename DATA, unsigned DIM>
0237 inline void KDTreeLinkerAlgo<DATA, DIM>::search(const KDTreeBoxT<DIM>& trackBox,
0238 std::vector<KDTreeNodeInfoT<DATA, DIM>>& recHits) {
0239 if (root_) {
0240 closestNeighbour = &recHits;
0241 this->recSearch(root_, trackBox);
0242 closestNeighbour = nullptr;
0243 }
0244 }
0245
0246
0247
0248 template <typename DATA, unsigned DIM>
0249 inline void KDTreeLinkerAlgo<DATA, DIM>::recSearch(const KDTreeNodeT<DATA, DIM>* current,
0250 const KDTreeBoxT<DIM>& trackBox) {
0251
0252
0253
0254
0255
0256 if ((current->left == nullptr) && (current->right == nullptr)) {
0257
0258
0259 bool isInside = true;
0260
0261 for (unsigned i = 0; i < DIM; ++i) {
0262 const auto thedim = current->info.dims[i];
0263 isInside = isInside && thedim >= trackBox.dimmin[i] && thedim <= trackBox.dimmax[i];
0264 }
0265
0266 if (isInside)
0267 closestNeighbour->push_back(current->info);
0268 } else {
0269
0270
0271 bool isFullyContained = true;
0272 bool hasIntersection = true;
0273
0274 for (unsigned i = 0; i < DIM; ++i) {
0275 const auto regionmin = current->left->region.dimmin[i];
0276 const auto regionmax = current->left->region.dimmax[i];
0277 isFullyContained = isFullyContained && (regionmin >= trackBox.dimmin[i] && regionmax <= trackBox.dimmax[i]);
0278 hasIntersection = hasIntersection && (regionmin < trackBox.dimmax[i] && regionmax > trackBox.dimmin[i]);
0279 }
0280
0281 if (isFullyContained) {
0282 this->addSubtree(current->left);
0283 } else if (hasIntersection) {
0284 this->recSearch(current->left, trackBox);
0285 }
0286
0287
0288 isFullyContained = true;
0289 hasIntersection = true;
0290
0291 for (unsigned i = 0; i < DIM; ++i) {
0292 const auto regionmin = current->right->region.dimmin[i];
0293 const auto regionmax = current->right->region.dimmax[i];
0294 isFullyContained = isFullyContained && (regionmin >= trackBox.dimmin[i] && regionmax <= trackBox.dimmax[i]);
0295 hasIntersection = hasIntersection && (regionmin < trackBox.dimmax[i] && regionmax > trackBox.dimmin[i]);
0296 }
0297
0298 if (isFullyContained) {
0299 this->addSubtree(current->right);
0300 } else if (hasIntersection) {
0301 this->recSearch(current->right, trackBox);
0302 }
0303 }
0304 }
0305
0306
0307
0308 template <typename DATA, unsigned DIM>
0309 inline void KDTreeLinkerAlgo<DATA, DIM>::findNearestNeighbour(const KDTreeNodeInfoT<DATA, DIM>& point,
0310 const KDTreeNodeInfoT<DATA, DIM>*& result,
0311 float& distance) {
0312 if (nullptr != result || distance != std::numeric_limits<float>::max()) {
0313 result = nullptr;
0314 distance = std::numeric_limits<float>::max();
0315 }
0316
0317 if (root_) {
0318 const KDTreeNodeT<DATA, DIM>* best_match = nullptr;
0319 this->recNearestNeighbour(0, root_, point, best_match, distance);
0320
0321 if (distance != std::numeric_limits<float>::max()) {
0322 result = &(best_match->info);
0323 distance = std::sqrt(distance);
0324 }
0325 }
0326 }
0327
0328
0329
0330 template <typename DATA, unsigned DIM>
0331 inline void KDTreeLinkerAlgo<DATA, DIM>::recNearestNeighbour(unsigned int depth, const KDTreeNodeT<DATA, DIM>* current,
0332 const KDTreeNodeInfoT<DATA, DIM>& point,
0333 const KDTreeNodeT<DATA, DIM>*& best_match,
0334 float& best_dist) {
0335 const unsigned int current_dim = depth % DIM;
0336
0337 if (current->left == nullptr && current->right == nullptr) {
0338 best_match = current;
0339 best_dist = this->dist2(point, best_match->info);
0340 return;
0341 } else {
0342 const float dist_to_axis = point.dims[current_dim] - current->info.dims[current_dim];
0343
0344 if (dist_to_axis < 0.f) {
0345 this->recNearestNeighbour(depth + 1, current->left, point, best_match, best_dist);
0346 } else {
0347 this->recNearestNeighbour(depth + 1, current->right, point, best_match, best_dist);
0348 }
0349
0350
0351
0352 const float dist_current = this->dist2(point, current->info);
0353
0354 if (dist_current < best_dist) {
0355 best_dist = dist_current;
0356 best_match = current;
0357 }
0358
0359
0360 if (best_dist > dist_to_axis * dist_to_axis) {
0361
0362 const KDTreeNodeT<DATA, DIM>* check_best = best_match;
0363 float check_dist = best_dist;
0364
0365 if (dist_to_axis < 0.f) {
0366 this->recNearestNeighbour(depth + 1, current->right, point, check_best, check_dist);
0367 } else {
0368 this->recNearestNeighbour(depth + 1, current->left, point, check_best, check_dist);
0369 }
0370
0371 if (check_dist < best_dist) {
0372 best_dist = check_dist;
0373 best_match = check_best;
0374 }
0375 }
0376 return;
0377 }
0378 }
0379
0380
0381
0382 template <typename DATA, unsigned DIM>
0383 inline void KDTreeLinkerAlgo<DATA, DIM>::addSubtree(const KDTreeNodeT<DATA, DIM>* current) {
0384
0385
0386
0387 if ((current->left == nullptr) && (current->right == nullptr)) {
0388
0389 closestNeighbour->push_back(current->info);
0390 } else {
0391
0392 this->addSubtree(current->left);
0393 this->addSubtree(current->right);
0394 }
0395 }
0396
0397
0398
0399 template <typename DATA, unsigned DIM>
0400 inline float KDTreeLinkerAlgo<DATA, DIM>::dist2(const KDTreeNodeInfoT<DATA, DIM>& a,
0401 const KDTreeNodeInfoT<DATA, DIM>& b) const {
0402 double d = 0.;
0403
0404 for (unsigned i = 0; i < DIM; ++i) {
0405 const double diff = a.dims[i] - b.dims[i];
0406 d += diff * diff;
0407 }
0408
0409 return (float)d;
0410 }
0411
0412
0413
0414 template <typename DATA, unsigned DIM>
0415 inline void KDTreeLinkerAlgo<DATA, DIM>::clearTree() {
0416 delete[] nodePool_;
0417 nodePool_ = nullptr;
0418 root_ = nullptr;
0419 nodePoolSize_ = -1;
0420 nodePoolPos_ = -1;
0421 }
0422
0423
0424
0425 template <typename DATA, unsigned DIM>
0426 inline bool KDTreeLinkerAlgo<DATA, DIM>::empty() {
0427 return (nodePoolPos_ == -1);
0428 }
0429
0430
0431
0432 template <typename DATA, unsigned DIM>
0433 inline int KDTreeLinkerAlgo<DATA, DIM>::size() {
0434 return (nodePoolPos_ + 1);
0435 }
0436
0437
0438
0439 template <typename DATA, unsigned DIM>
0440 inline void KDTreeLinkerAlgo<DATA, DIM>::clear() {
0441 if (root_)
0442 this->clearTree();
0443 }
0444
0445
0446
0447 template <typename DATA, unsigned DIM>
0448 inline KDTreeNodeT<DATA, DIM>* KDTreeLinkerAlgo<DATA, DIM>::getNextNode() {
0449 ++nodePoolPos_;
0450
0451
0452
0453
0454
0455 return &(nodePool_[nodePoolPos_]);
0456 }
0457
0458
0459
0460 template <typename DATA, unsigned DIM>
0461 inline KDTreeNodeT<DATA, DIM>* KDTreeLinkerAlgo<DATA, DIM>::recBuild(int low, int high, int depth,
0462 const KDTreeBoxT<DIM>& region) {
0463 const int portionSize = high - low;
0464
0465
0466
0467
0468 if (portionSize == 1) {
0469
0470 KDTreeNodeT<DATA, DIM>* leaf = this->getNextNode();
0471 leaf->setAttributs(region, (*initialEltList)[low]);
0472 return leaf;
0473 } else {
0474
0475 int medianId = this->medianSearch(low, high, depth);
0476
0477
0478 KDTreeNodeT<DATA, DIM>* node = this->getNextNode();
0479 node->setAttributs(region);
0480 node->info = (*initialEltList)[medianId];
0481
0482
0483 KDTreeBoxT<DIM> leftRegion = region;
0484 KDTreeBoxT<DIM> rightRegion = region;
0485
0486 const unsigned thedim = depth % DIM;
0487 auto medianVal = (*initialEltList)[medianId].dims[thedim];
0488 leftRegion.dimmax[thedim] = medianVal;
0489 rightRegion.dimmin[thedim] = medianVal;
0490
0491 ++depth;
0492 ++medianId;
0493
0494
0495 node->left = this->recBuild(low, medianId, depth, leftRegion);
0496 node->right = this->recBuild(medianId, high, depth, rightRegion);
0497 return node;
0498 }
0499 }
0500
0501 }
0502
0503 #endif