CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/RecoParticleFlow/PFProducer/src/KDTreeLinkerAlgo.cc

Go to the documentation of this file.
00001 #include "RecoParticleFlow/PFProducer/interface/KDTreeLinkerAlgo.h"
00002 
00003 KDTreeLinkerAlgo::KDTreeLinkerAlgo()
00004   : root_ (0),
00005     nodePool_(0),
00006     nodePoolSize_(-1),
00007     nodePoolPos_(-1)
00008 {
00009 }
00010 
00011 KDTreeLinkerAlgo::~KDTreeLinkerAlgo()
00012 {
00013   clear();
00014 }
00015 
00016 void
00017 KDTreeLinkerAlgo::build(std::vector<KDTreeNodeInfo>     &eltList, 
00018                         const KDTreeBox                 &region)
00019 {
00020   if (eltList.size()) {
00021     nodePoolSize_ = eltList.size() * 2 - 1;
00022     nodePool_ = new KDTreeNode[nodePoolSize_];
00023 
00024     // Here we build the KDTree
00025     root_ = recBuild(eltList, 0, eltList.size(), 0, region);
00026   }
00027 }
00028 
00029 
00030 KDTreeNode*
00031 KDTreeLinkerAlgo::recBuild(std::vector<KDTreeNodeInfo>  &eltList, 
00032                            int                          low, 
00033                            int                          high, 
00034                            int                          depth,
00035                            const KDTreeBox&             region)
00036 {
00037   int portionSize = high - low;
00038 
00039   // By construction, portionSize > 0 can't happend.
00040   assert(portionSize > 0);
00041 
00042   if (portionSize == 1) { // Leaf case
00043    
00044     KDTreeNode *leaf = getNextNode();
00045     leaf->setAttributs(region, eltList[low]);
00046     return leaf;
00047 
00048   } else { // Node case
00049     
00050     // The even depth is associated to dim1 dimension
00051     // The odd one to dim2 dimension
00052     int medianId = medianSearch(eltList, low, high, depth);
00053 
00054     // We create the node
00055     KDTreeNode *node = getNextNode();
00056     node->setAttributs(region);
00057 
00058 
00059     // Here we split into 2 halfplanes the current plane
00060     KDTreeBox leftRegion = region;
00061     KDTreeBox rightRegion = region;
00062     if (depth & 1) {
00063 
00064       double medianVal = eltList[medianId].dim2;
00065       leftRegion.dim2max = medianVal;
00066       rightRegion.dim2min = medianVal;
00067 
00068     } else {
00069 
00070       double medianVal = eltList[medianId].dim1;
00071       leftRegion.dim1max = medianVal;
00072       rightRegion.dim1min = medianVal;
00073 
00074     }
00075 
00076     ++depth;
00077     ++medianId;
00078 
00079     // We recursively build the son nodes
00080     node->left = recBuild(eltList, low, medianId, depth, leftRegion);
00081     node->right = recBuild(eltList, medianId, high, depth, rightRegion);
00082 
00083     return node;
00084   }
00085 }
00086 
00087 
00088 //Fast median search with Wirth algorithm in eltList between low and high indexes.
00089 int
00090 KDTreeLinkerAlgo::medianSearch(std::vector<KDTreeNodeInfo>      &eltList,
00091                                int                              low,
00092                                int                              high,
00093                                int                              treeDepth)
00094 {
00095   //We should have at least 1 element to calculate the median...
00096   assert(low < high);
00097 
00098   int nbrElts = high - low;
00099   int median = (nbrElts & 1)    ? nbrElts / 2 
00100                                 : nbrElts / 2 - 1;
00101   median += low;
00102 
00103   int l = low;
00104   int m = high - 1;
00105   
00106   while (l < m) {
00107     KDTreeNodeInfo elt = eltList[median];
00108     int i = l;
00109     int j = m;
00110 
00111     do {
00112 
00113       // The even depth is associated to dim1 dimension
00114       // The odd one to dim2 dimension
00115       if (treeDepth & 1) {
00116         while (eltList[i].dim2 < elt.dim2) i++;
00117         while (eltList[j].dim2 > elt.dim2) j--;
00118       } else {
00119         while (eltList[i].dim1 < elt.dim1) i++;
00120         while (eltList[j].dim1 > elt.dim1) j--;
00121       }
00122 
00123       if (i <= j){
00124         swap(eltList[i], eltList[j]);
00125         i++; 
00126         j--;
00127       }
00128     } while (i <= j);
00129     if (j < median) l = i;
00130     if (i > median) m = j;
00131   }
00132 
00133   return median;
00134 }
00135 
00136 void 
00137 KDTreeLinkerAlgo::swap(KDTreeNodeInfo   &e1, 
00138                        KDTreeNodeInfo   &e2)
00139 {
00140   KDTreeNodeInfo tmp = e1;
00141   e1 = e2;
00142   e2 = tmp;
00143 }
00144 
00145 void
00146 KDTreeLinkerAlgo::search(const KDTreeBox                &trackBox,
00147                          std::vector<KDTreeNodeInfo>    &recHits)
00148 {
00149   if (root_)
00150     recSearch(root_, trackBox, recHits);
00151 }
00152 
00153 void 
00154 KDTreeLinkerAlgo::recSearch(const KDTreeNode            *current,
00155                             const KDTreeBox             &trackBox,
00156                             std::vector<KDTreeNodeInfo> &recHits)
00157 {
00158   // By construction, current can't be null
00159   assert(current != 0);
00160 
00161   // By Construction, a node can't have just 1 son.
00162   assert (!(((current->left == 0) && (current->right != 0)) ||
00163             ((current->left != 0) && (current->right == 0))));
00164     
00165   if ((current->left == 0) && (current->right == 0)) {//leaf case
00166   
00167     // If point inside the rectangle/area
00168     if ((current->rh.dim1 >= trackBox.dim1min) && (current->rh.dim1 <= trackBox.dim1max) &&
00169         (current->rh.dim2 >= trackBox.dim2min) && (current->rh.dim2 <= trackBox.dim2max))
00170       recHits.push_back(current->rh);
00171 
00172   } else {
00173 
00174     //if region( v->left ) is fully contained in the rectangle
00175     if ((current->left->region.dim1min >= trackBox.dim1min) && 
00176         (current->left->region.dim1max <= trackBox.dim1max) &&
00177         (current->left->region.dim2min >= trackBox.dim2min) && 
00178         (current->left->region.dim2max <= trackBox.dim2max))
00179       addSubtree(current->left, recHits);
00180     
00181     else { //if region( v->left ) intersects the rectangle
00182       
00183       if (!((current->left->region.dim1min >= trackBox.dim1max) || 
00184             (current->left->region.dim1max <= trackBox.dim1min) ||
00185             (current->left->region.dim2min >= trackBox.dim2max) || 
00186             (current->left->region.dim2max <= trackBox.dim2min)))
00187         recSearch(current->left, trackBox, recHits);
00188     }
00189     
00190     //if region( v->right ) is fully contained in the rectangle
00191     if ((current->right->region.dim1min >= trackBox.dim1min) && 
00192         (current->right->region.dim1max <= trackBox.dim1max) &&
00193         (current->right->region.dim2min >= trackBox.dim2min) && 
00194         (current->right->region.dim2max <= trackBox.dim2max))
00195       addSubtree(current->right, recHits);
00196 
00197     else { //if region( v->right ) intersects the rectangle
00198      
00199       if (!((current->right->region.dim1min >= trackBox.dim1max) || 
00200             (current->right->region.dim1max <= trackBox.dim1min) ||
00201             (current->right->region.dim2min >= trackBox.dim2max) || 
00202             (current->right->region.dim2max <= trackBox.dim2min)))
00203         recSearch(current->right, trackBox, recHits);
00204     } 
00205   }
00206 }
00207 
00208 void
00209 KDTreeLinkerAlgo::addSubtree(const KDTreeNode           *current, 
00210                    std::vector<KDTreeNodeInfo>  &recHits)
00211 {
00212   // By construction, current can't be null
00213   assert(current != 0);
00214 
00215   if ((current->left == 0) && (current->right == 0)) // leaf
00216     recHits.push_back(current->rh);
00217   else { // node
00218     addSubtree(current->left, recHits);
00219     addSubtree(current->right, recHits);
00220   }
00221 }
00222 
00223 
00224 void 
00225 KDTreeLinkerAlgo::clearTree()
00226 {
00227   delete[] nodePool_;
00228   nodePool_ = 0;
00229   root_ = 0;
00230   nodePoolSize_ = -1;
00231   nodePoolPos_ = -1;
00232 }
00233 
00234 void 
00235 KDTreeLinkerAlgo::clear()
00236 {
00237   if (root_)
00238     clearTree();
00239 }
00240 
00241 
00242 KDTreeNode* 
00243 KDTreeLinkerAlgo::getNextNode()
00244 {
00245   ++nodePoolPos_;
00246 
00247   // The tree size is exactly 2 * nbrElts - 1 and this is the total allocated memory.
00248   // If we have used more than that....there is a big problem.
00249   assert(nodePoolPos_ < nodePoolSize_);
00250 
00251   return &(nodePool_[nodePoolPos_]);
00252 }