CMS 3D CMS Logo

KDTreeLinkerAlgoT.h
Go to the documentation of this file.
1 #ifndef KDTreeLinkerAlgoTemplated_h
2 #define KDTreeLinkerAlgoTemplated_h
3 
4 #include "KDTreeLinkerToolsT.h"
5 
6 #include <cassert>
7 #include <vector>
8 
9 // Class that implements the KDTree partition of 2D space and
10 // a closest point search algorithme.
11 
12 template <typename DATA, unsigned DIM=2>
13 class KDTreeLinkerAlgo
14 {
15  public:
17 
18  // Dtor calls clear()
20 
21  // Here we build the KD tree from the "eltList" in the space define by "region".
22  void build(std::vector<KDTreeNodeInfoT<DATA,DIM> > &eltList,
23  const KDTreeBoxT<DIM> &region);
24 
25  // Here we search in the KDTree for all points that would be
26  // contained in the given searchbox. The founded points are stored in resRecHitList.
27  void search(const KDTreeBoxT<DIM> &searchBox,
28  std::vector<KDTreeNodeInfoT<DATA,DIM> > &resRecHitList);
29 
30  // This reurns true if the tree is empty
31  bool empty() {return nodePoolPos_ == -1;}
32 
33  // This returns the number of nodes + leaves in the tree
34  // (nElements should be (size() +1)/2)
35  int size() { return nodePoolPos_ + 1;}
36 
37  // This method clears all allocated structures.
38  void clear();
39 
40  private:
41  // The KDTree root
43 
44  // The node pool allow us to do just 1 call to new for each tree building.
48 
49 
50 
51  std::vector<KDTreeNodeInfoT<DATA,DIM> > *closestNeighbour;
52  std::vector<KDTreeNodeInfoT<DATA,DIM> > *initialEltList;
53 
54  private:
55 
56  // Get next node from the node pool.
58 
59  //Fast median search with Wirth algorithm in eltList between low and high indexes.
60  int medianSearch(int low,
61  int high,
62  int treeDepth);
63 
64  // Recursif kdtree builder. Is called by build()
66  int hight,
67  int depth,
68  const KDTreeBoxT<DIM> &region);
69 
70  // Recursif kdtree search. Is called by search()
71  void recSearch(const KDTreeNodeT<DATA,DIM> *current,
72  const KDTreeBoxT<DIM> &trackBox);
73 
74  // Add all elements of an subtree to the closest elements. Used during the recSearch().
75  void addSubtree(const KDTreeNodeT<DATA,DIM> *current);
76 
77  // This method frees the KDTree.
78  void clearTree();
79 };
80 
81 
82 //Implementation
83 
84 template < typename DATA, unsigned DIM >
85 void
87  const KDTreeBoxT<DIM> &region)
88 {
89  if (!eltList.empty()) {
90  initialEltList = &eltList;
91 
92  size_t size = initialEltList->size();
93  nodePoolSize_ = size * 2 - 1;
95 
96  // Here we build the KDTree
97  root_ = recBuild(0, size, 0, region);
98 
99  initialEltList = nullptr;
100  }
101 }
102 
103 //Fast median search with Wirth algorithm in eltList between low and high indexes.
104 template < typename DATA, unsigned DIM >
105 int
107  int high,
108  int treeDepth)
109 {
110  //We should have at least 1 element to calculate the median...
111  //assert(low < high);
112 
113  const int nbrElts = high - low;
114  int median = nbrElts/2 - ( 1 - 1*(nbrElts&1) );
115  median += low;
116 
117  int l = low;
118  int m = high - 1;
119 
120  while (l < m) {
121  KDTreeNodeInfoT<DATA,DIM> elt = (*initialEltList)[median];
122  int i = l;
123  int j = m;
124 
125  do {
126  // The even depth is associated to dim1 dimension
127  // The odd one to dim2 dimension
128  const unsigned thedim = treeDepth % DIM;
129  while( (*initialEltList)[i].dims[thedim] < elt.dims[thedim] ) ++i;
130  while( (*initialEltList)[j].dims[thedim] > elt.dims[thedim] ) --j;
131 
132  if (i <= j){
134  i++;
135  j--;
136  }
137  } while (i <= j);
138  if (j < median) l = i;
139  if (i > median) m = j;
140  }
141 
142  return median;
143 }
144 
145 
146 
147 template < typename DATA, unsigned DIM >
148 void
150  std::vector<KDTreeNodeInfoT<DATA,DIM> > &recHits)
151 {
152  if (root_) {
153  closestNeighbour = &recHits;
154  recSearch(root_, trackBox);
155  closestNeighbour = nullptr;
156  }
157 }
158 
159 
160 template < typename DATA, unsigned DIM >
161 void
163  const KDTreeBoxT<DIM> &trackBox)
164 {
165  /*
166  // By construction, current can't be null
167  assert(current != 0);
168 
169  // By Construction, a node can't have just 1 son.
170  assert (!(((current->left == 0) && (current->right != 0)) ||
171  ((current->left != 0) && (current->right == 0))));
172  */
173 
174  if ((current->left == nullptr) && (current->right == nullptr)) {//leaf case
175 
176  // If point inside the rectangle/area
177  bool isInside = true;
178  for( unsigned i = 0; i < DIM; ++i ) {
179  const auto thedim = current->info.dims[i];
180  isInside *= thedim >= trackBox.dimmin[i] && thedim <= trackBox.dimmax[i];
181  }
182  if( isInside ) closestNeighbour->push_back(current->info);
183 
184  } else {
185 
186  bool isFullyContained = true;
187  bool hasIntersection = true;
188  //if region( v->left ) is fully contained in the rectangle
189  for( unsigned i = 0; i < DIM; ++i ) {
190  const auto regionmin = current->left->region.dimmin[i];
191  const auto regionmax = current->left->region.dimmax[i];
192  isFullyContained *= ( regionmin >= trackBox.dimmin[i] &&
193  regionmax <= trackBox.dimmax[i] );
194  hasIntersection *= ( regionmin < trackBox.dimmax[i] && regionmax > trackBox.dimmin[i]);
195  }
196  if( isFullyContained ) {
197  addSubtree(current->left);
198  } else if ( hasIntersection ) {
199  recSearch(current->left, trackBox);
200  }
201  // reset flags
202  isFullyContained = true;
203  hasIntersection = true;
204  //if region( v->right ) is fully contained in the rectangle
205  for( unsigned i = 0; i < DIM; ++i ) {
206  const auto regionmin = current->right->region.dimmin[i];
207  const auto regionmax = current->right->region.dimmax[i];
208  isFullyContained *= ( regionmin >= trackBox.dimmin[i] &&
209  regionmax <= trackBox.dimmax[i] );
210  hasIntersection *= ( regionmin < trackBox.dimmax[i] && regionmax > trackBox.dimmin[i]);
211  }
212  if( isFullyContained ) {
213  addSubtree(current->right);
214  } else if ( hasIntersection ) {
215  recSearch(current->right, trackBox);
216  }
217  }
218 }
219 
220 template < typename DATA, unsigned DIM >
221 void
223 {
224  // By construction, current can't be null
225  // assert(current != 0);
226 
227  if ((current->left == nullptr) && (current->right == nullptr)) // leaf
228  closestNeighbour->push_back(current->info);
229  else { // node
230  addSubtree(current->left);
231  addSubtree(current->right);
232  }
233 }
234 
235 
236 
237 
238 template <typename DATA, unsigned DIM>
240  : root_ (nullptr),
241  nodePool_(nullptr),
242  nodePoolSize_(-1),
243  nodePoolPos_(-1)
244 {
245 }
246 
247 template <typename DATA, unsigned DIM>
249 {
250  clear();
251 }
252 
253 
254 template <typename DATA, unsigned DIM>
255 void
257 {
258  delete[] nodePool_;
259  nodePool_ = nullptr;
260  root_ = nullptr;
261  nodePoolSize_ = -1;
262  nodePoolPos_ = -1;
263 }
264 
265 template <typename DATA, unsigned DIM>
266 void
268 {
269  if (root_)
270  clearTree();
271 }
272 
273 
274 template <typename DATA, unsigned DIM>
277 {
278  ++nodePoolPos_;
279 
280  // The tree size is exactly 2 * nbrElts - 1 and this is the total allocated memory.
281  // If we have used more than that....there is a big problem.
282  // assert(nodePoolPos_ < nodePoolSize_);
283 
284  return &(nodePool_[nodePoolPos_]);
285 }
286 
287 
288 template <typename DATA, unsigned DIM>
291  int high,
292  int depth,
293  const KDTreeBoxT<DIM>& region)
294 {
295  int portionSize = high - low;
296 
297  // By construction, portionSize > 0 can't happend.
298  // assert(portionSize > 0);
299 
300  if (portionSize == 1) { // Leaf case
301 
303  leaf->setAttributs(region, (*initialEltList)[low]);
304  return leaf;
305 
306  } else { // Node case
307 
308  // The even depth is associated to dim1 dimension
309  // The odd one to dim2 dimension
310  int medianId = medianSearch(low, high, depth);
311 
312  // We create the node
314  node->setAttributs(region);
315 
316 
317  // Here we split into 2 halfplanes the current plane
318  KDTreeBoxT<DIM> leftRegion = region;
319  KDTreeBoxT<DIM> rightRegion = region;
320  unsigned thedim = depth % DIM;
321  auto medianVal = (*initialEltList)[medianId].dims[thedim];
322  leftRegion.dimmax[thedim] = medianVal;
323  rightRegion.dimmin[thedim] = medianVal;
324 
325  ++depth;
326  ++medianId;
327 
328  // We recursively build the son nodes
329  node->left = recBuild(low, medianId, depth, leftRegion);
330  node->right = recBuild(medianId, high, depth, rightRegion);
331 
332  return node;
333  }
334 }
335 
336 #endif
KDTreeNodeT< DATA, DIM > * right
KDTreeNodeT< DATA, DIM > * left
std::array< float, DIM > dimmin
int recBuild(int low, int hight, int depth)
std::vector< DATA > * closestNeighbour
std::vector< KDTreeNodeInfo< DATA > > * initialEltList
KDTreeNodes< DATA > nodePool_
void addSubtree(const KDTreeNodeT< DATA, DIM > *current)
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
std::vector< KDTreeNodeInfoT< DATA, DIM > > * initialEltList
void search(const KDTreeBox &searchBox, std::vector< DATA > &resRecHitList)
std::vector< KDTreeNodeInfoT< DATA, DIM > > * closestNeighbour
std::array< float, DIM > dims
void build(std::vector< KDTreeNodeInfo< DATA > > &eltList, const KDTreeBox &region)
KDTreeNodeT< DATA, DIM > * getNextNode()
#define DIM
KDTreeNodeInfoT< DATA, DIM > info
KDTreeNodeT< DATA, DIM > * root_
std::array< float, DIM > dimmax
void setAttributs(const KDTreeBoxT< DIM > &regionBox, const KDTreeNodeInfoT< DATA, DIM > &infoToStore)
KDTreeNodeT< DATA, DIM > * nodePool_
int medianSearch(int low, int high, int treeDepth)
void recSearch(int current, float dimCurrMin, float dimCurrMax, float dimOtherMin, float dimOtherMax)