Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Namespace Members | Data Fields | Globals

KDTree.h

Go to the documentation of this file.
00001 /* Copyright (C) 2004
00002    K-Dimension Tree Data Structure Implementation
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with this library; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 */
00018 
00019 #ifndef _KDTREE_H_
00020 #define _KDTREE_H_
00021 
00022 #include "Object.h"
00023 #include <stdio.h>
00024 #include <math.h>
00025 #include "KDNode.h"
00026 #include "KDPoint.h"
00027 #include "KDPQueue.h"
00028 
00029 namespace RobotFlow {
00030 // Template class for node values
00031 // IMPORTANT: class requires =, -, >, < operators
00032 //            it should usually be either double, float, int, ...
00033 template <class KDData>
00034 class KDTree : public FD::Object
00035 {
00036 public:
00037         /*
00038                 KDTree
00039 
00040                 Default constructor
00041         */
00042         KDTree()
00043         : m_bboxLow(), m_bboxHigh()
00044         {
00045 
00046         }
00047 
00048         /*
00049                 KDTree
00050 
00051                 Other constructor wih user data
00052 
00053                 PARAMETERS
00054                 i_dataPts : array of data describing the points used to built the tree.
00055                                         The array should be constructed as follow:
00056                                         i_dataPts[<Number of points>][<Dimension size of the points>]
00057                 i_numPts : number of points in the given array
00058                 i_dimSize : dimension size of the points in the given array
00059                 i_bucketSize : bucket size of the leaf nodes i.e. the maximum number of
00060                                                 points strored in a leaf node.
00061         */
00062         KDTree(KDData **i_dataPts, int i_numPts, int i_dimSize, int i_bucketSize)
00063         : m_numPts(i_numPts), m_dimSize(i_dimSize), m_bucketSize(i_bucketSize),
00064         m_bboxLow(m_dimSize, (KDData)0), m_bboxHigh(m_dimSize, (KDData)0)
00065         {
00066                 m_root = NULL;
00067                 int *ptsIdx = new int[m_numPts];
00068 
00069                 if(m_numPts == 0) {
00070                         return;
00071                 }
00072 
00073                 // First assign identity indexes
00074                 for(int i=0; i<m_numPts; ++i) {
00075                         ptsIdx[i] = i;
00076                 }
00077 
00078                 SetBBoxes(i_dataPts, ptsIdx);
00079 
00080                 m_root = RecurBuildTree(i_dataPts, ptsIdx, m_numPts);
00081 
00082                 delete [] ptsIdx;
00083         }
00084 
00085         /*
00086                 ~KDTree
00087 
00088                 Destructor
00089         */
00090         ~KDTree()
00091         {
00092                 delete m_root;
00093         }
00094 
00095         /*
00096                 printOn
00097 
00098                 Object routine required to print its content
00099 
00100                 PARAMETERS
00101                 out : output stream to print the object content
00102         */
00103         void printOn(std::ostream &out) const
00104         {
00105                 out << "<KDTree " << std::endl;
00106                 out << "<NumPts " << m_numPts << " >" << std::endl;
00107                 out << "<DimSize " << m_dimSize << " >" << std::endl;
00108                 out << "<BucketSize " << m_bucketSize << " >" << std::endl;
00109 
00110                 out << "<BBoxLow " << std::endl;
00111                 m_bboxLow.printOn(out);
00112                 out << " >" << std::endl;
00113 
00114                 out << "<BBoxHigh " << std::endl;
00115                 m_bboxHigh.printOn(out);
00116                 out << " >" << std::endl;
00117 
00118                 if (m_root != NULL) {
00119                         out << "<KDRoot " << std::endl;
00120                         m_root->printOn(out);
00121                         out << " >" << std::endl;
00122                 }
00123 
00124                 out << " >" << std::endl;
00125         }
00126 
00127         /*
00128                 readFrom
00129 
00130                 Object routine required to read an Object content
00131 
00132                 PARAMETERS
00133                 in : input stream to read the object content
00134         */
00135         void readFrom(std::istream &in)
00136         {
00137                 std::string tag;
00138 
00139                 while (1) {
00140                         char ch;
00141                         in >> ch;
00142 
00143                         if (ch == '>') {
00144                                 break;
00145                         }
00146                         else if (ch != '<') {
00147                                 throw new FD::GeneralException ("KDTree::readFrom : Parse error: '<' expected",__FILE__,__LINE__);
00148                         }
00149 
00150                         in >> tag;
00151 
00152                         if (tag == "KDTree") {
00153                                 continue;
00154                         }
00155                         else if (tag == "NumPts") {
00156                                 in >> m_numPts;
00157                         }
00158                         else if (tag == "DimSize") {
00159                                 in >> m_dimSize;
00160                         }
00161                         else if (tag == "BucketSize") {
00162                                 in >> m_bucketSize;
00163                         }
00164                         else if (tag == "BBoxLow") {
00165                                 try {
00166                                         m_bboxLow.readFrom(in);
00167                                 }
00168                                 catch (FD::GeneralException *e) {
00169                                         throw e->add(new FD::GeneralException("In KDTree::readFrom : ",__FILE__,__LINE__));
00170                                 }
00171                         }
00172                         else if (tag == "BBoxHigh") {
00173                                 try {
00174                                         m_bboxHigh.readFrom(in);
00175                                 }
00176                                 catch (FD::GeneralException *e) {
00177                                         throw e->add(new FD::GeneralException("In KDTree::readFrom : ",__FILE__,__LINE__));
00178                                 }
00179                         }
00180                         else if (tag == "KDRoot") {
00181                                 // Allocate root node
00182                                 try {
00183                                         m_root = new KDNode<KDData>();
00184                                         m_root->readFrom(in);
00185                                 }
00186                                 catch (FD::GeneralException *e) {
00187                                         throw e->add(new FD::GeneralException("In KDTree::readFrom : ",__FILE__,__LINE__));
00188                                 }
00189                         }
00190                         else {
00191                                 throw new FD::GeneralException ("KDTree::readFrom : Unknown argument: " + tag,__FILE__,__LINE__);
00192                         }
00193 
00194                         if (!in) {
00195                                 throw new FD::GeneralException ("KDTree::readFrom : Parse error trying to build " + tag,__FILE__,__LINE__);
00196                         }
00197 
00198                         in >> tag;
00199                         if (tag != ">") {
00200                                 throw new FD::GeneralException ("KDTree::readFrom : Parse error: '>' expected ",__FILE__,__LINE__);
00201                         }
00202                 }
00203         }
00204 
00205         /*
00206                 NNSearch
00207 
00208                 Nearest neighbor search routine where the actual NN points are returned.
00209                 This function requires the tree to be already built.
00210 
00211                 PARAMETERS
00212                 i_qp : query point given to find its nearest neighbor in the tree points
00213                                 NOTE: the query point dimension size must be the same as the tree
00214                                                 points.
00215                 i_maxNumNodes : maximum number of leaf nodes to visit before to stop the
00216                                                 search. If it is set to 0, than all the tree can be
00217                                                 searched.
00218                 i_errBnd : error bound to determine if we should visit a child node.
00219                                         A value of 0 means the search will visit all the potential
00220                                         nodes.
00221                 i_numNN : number of nearest neighbors to look for
00222                 i_squareDist : is the return NN distances in squared value?
00223                 o_nnDist : output array to contain the NN distances.
00224                                         NOTE: we assume enough memeory has been allocated
00225                 o_nn : output array to contain the NN.
00226                                 NOTE: we assume enough memeory has been allocated
00227         */
00228         void NNSearch(KDPoint<KDData> *i_qp, int i_maxNumNodes, double i_errBnd,
00229                 int i_numNN, bool i_squareDist, double *o_nnDist, KDPoint<KDData> *o_nn)
00230         {
00231                 int numVisited = 0;
00232                 double maxErr = (1.0 + i_errBnd)*(1.0 + i_errBnd);
00233                 double dist =  BBoxDist2Point(i_qp);
00234                 KDPQueue<double, KDPoint<KDData> > nnQueue(i_numNN);
00235 
00236                 // Sanity check
00237                 if (m_root == NULL) {
00238                         throw new FD::GeneralException ("KDTree::NNSearch : nearest neighbor search requires the KDTree to contain reference points. ",__FILE__,__LINE__);
00239                 }
00240 
00241                 if (i_qp == NULL) {
00242                         throw new FD::GeneralException ("KDTree::NNSearch : NULL query point. ",__FILE__,__LINE__);
00243                 }
00244 
00245                 if (o_nnDist == NULL) {
00246                         throw new FD::GeneralException ("KDTree::NNSearch : NULL nearest neighbor distances array. ",__FILE__,__LINE__);
00247                 }
00248 
00249                 if (o_nn == NULL) {
00250                         throw new FD::GeneralException ("KDTree::NNSearch : NULL nearest neighbor points array. ",__FILE__,__LINE__);
00251                 }
00252 
00253                 if (i_qp->GetDimSize() != m_dimSize) {
00254                         throw new FD::GeneralException ("KDTree::NNSearch : query point dimension size differs from KDTree reference points. ",__FILE__,__LINE__);
00255                 }
00256 
00257                 if (i_numNN == 0) {
00258                         return;
00259                 }
00260 
00261                 if (i_numNN > m_numPts) {
00262                         throw new FD::GeneralException ("KDTree::NNSearch : cannot search for more nearest neighbors than the number of reference points in KDTree. ",__FILE__,__LINE__);
00263                 }
00264 
00265                 // Start search at root node
00266                 m_root->NNSearch(i_qp, i_maxNumNodes, numVisited, maxErr, dist, &nnQueue);
00267 
00268                 // Copy NN and distances
00269                 if (i_squareDist) {
00270                         for (int i=0; i<i_numNN; ++i) {
00271                                 o_nnDist[i] = nnQueue.GetIthKey(i);
00272                                 o_nn[i] = *(nnQueue.GetIthElement(i));
00273                         }
00274                 }
00275                 else {
00276                         for (int i=0; i<i_numNN; ++i) {
00277                                 o_nnDist[i] = sqrt(nnQueue.GetIthKey(i));
00278                                 o_nn[i] = *(nnQueue.GetIthElement(i));
00279                         }
00280                 }
00281         }
00282 
00283         /*
00284                 NNSearch
00285 
00286                 Nearest neighbor search routine where the indexes to the NN reference points
00287                 array used to build the tree are returned.
00288                 This function requires the tree to be already built.
00289 
00290                 PARAMETERS
00291                 i_qp : query point given to find its nearest neighbor in the tree points
00292                                 NOTE: the query point dimension size must be the same as the tree
00293                                                 points.
00294                 i_maxNumNodes : maximum number of leaf nodes to visit before to stop the
00295                                                 search. If it is set to 0, than all the tree can be
00296                                                 searched.
00297                 i_errBnd : error bound to determine if we should visit a child node.
00298                                         A value of 0 means the search will visit all the potential
00299                                         nodes.
00300                 i_numNN : number of nearest neighbors to look for
00301                 i_squareDist : is the return NN distances in squared value?
00302                 o_nnDist : output array to contain the NN distances.
00303                                         NOTE: we assume enough memeory has been allocated
00304                 o_nnIdx : output array to contain the NN indexes.
00305                                 NOTE: we assume enough memeory has been allocated
00306         */
00307         void NNSearch(KDPoint<KDData> *i_qp, int i_maxNumNodes, double i_errBnd,
00308                 int i_numNN, bool i_squareDist, double *o_nnDist, int *o_nnIdx)
00309         {
00310                 int numVisited = 0;
00311                 double maxErr = (1.0 + i_errBnd)*(1.0 + i_errBnd);
00312                 double dist =  BBoxDist2Point(i_qp);
00313                 KDPQueue<double, int> nnQueue(i_numNN);
00314 
00315                 // Sanity check
00316                 if (m_root == NULL) {
00317                         throw new FD::GeneralException ("KDTree::NNSearch : nearest neighbor search requires the KDTree to contain reference points. ",__FILE__,__LINE__);
00318                 }
00319 
00320                 if (i_qp == NULL) {
00321                         throw new FD::GeneralException ("KDTree::NNSearch : NULL query point. ",__FILE__,__LINE__);
00322                 }
00323 
00324                 if (o_nnDist == NULL) {
00325                         throw new FD::GeneralException ("KDTree::NNSearch : NULL nearest neighbor distances array. ",__FILE__,__LINE__);
00326                         
00327                 }
00328 
00329                 if (o_nnIdx == NULL) {
00330                         throw new FD::GeneralException ("KDTree::NNSearch : NULL nearest neighbor indexes array. ",__FILE__,__LINE__);
00331                 }
00332 
00333                 if (i_qp->GetDimSize() != m_dimSize) {
00334                         throw new FD::GeneralException ("KDTree::NNSearch : query point dimension size differs from KDTree reference points. ",__FILE__,__LINE__);
00335                 }
00336 
00337                 if (i_numNN == 0) {
00338                         return;
00339                 }
00340 
00341                 if (i_numNN > m_numPts) {
00342                         throw new FD::GeneralException ("KDTree::NNSearch : cannot search for more nearest neighbors than the number of reference points in KDTree. ",__FILE__,__LINE__);
00343                 }
00344 
00345                 // Start search at root node
00346                 m_root->NNSearch(i_qp, i_maxNumNodes, numVisited, maxErr, dist, &nnQueue);
00347 
00348                 // Copy NN and distances
00349                 if (i_squareDist) {
00350                         for (int i=0; i<i_numNN; ++i) {
00351                                 o_nnDist[i] = nnQueue.GetIthKey(i);
00352                                 o_nnIdx[i] = *(nnQueue.GetIthElement(i));
00353                         }
00354                 }
00355                 else {
00356                         for (int i=0; i<i_numNN; ++i) {
00357                                 o_nnDist[i] = sqrt(nnQueue.GetIthKey(i));
00358                                 o_nnIdx[i] = *(nnQueue.GetIthElement(i));
00359                         }
00360                 }
00361         }
00362 
00363 private:
00364         /*
00365                 BBoxDist2Point
00366 
00367                 Compute the distance from a given point to the current tree
00368                 bounding box including all the reference points
00369 
00370                 PARAMETERS
00371                 i_qp : query point used to compute the distance
00372 
00373                 RETURNS
00374                 Distance from the given point to the bounding box
00375         */
00376         double BBoxDist2Point(KDPoint<KDData> *i_qp)
00377         {
00378                 // Sum of squared distances
00379                 double dist = 0.0;
00380                 double tmp;
00381 
00382                 for (int d = 0; d < m_dimSize; ++d) {
00383                         if (i_qp->GetCoord(d) < m_bboxLow.GetCoord(d)) {
00384                                 // Query point is left of BBox
00385                                 tmp = m_bboxLow.GetCoord(d) - i_qp->GetCoord(d);
00386                                 dist += tmp*tmp;
00387                         }
00388                         else if (i_qp->GetCoord(d) > m_bboxHigh.GetCoord(d)) {
00389                                 // Query point is right of BBox
00390                                 tmp = i_qp->GetCoord(d) - m_bboxHigh.GetCoord(d);
00391                                 dist += tmp*tmp;
00392                         }
00393                 }
00394 
00395                 return dist;
00396         }
00397 
00398         /*
00399                 SetBBoxes
00400 
00401                 Compute a bounding box including all the reference points.
00402                 The bounding box is kept in member data.
00403 
00404                 PARAMETERS
00405                 i_points : given points used to build the tree structure
00406                 i_ptsIdx : indexes to the points in the given array
00407         */
00408         void SetBBoxes(KDData **i_points, int *i_ptsIdx)
00409         {
00410                 // find smallest enclosing rectangle
00411                 for (int d=0; d<m_dimSize; ++d) {
00412                         // lower bound on dimension d
00413                         KDData low = i_points[i_ptsIdx[0]][d];
00414                         // upper bound on dimension d
00415                         KDData high = i_points[i_ptsIdx[0]][d];
00416 
00417                         for (int i=0; i<m_numPts; ++i) {
00418                                 KDData cur = i_points[i_ptsIdx[i]][d];
00419                                 if (cur < low) {
00420                                         low = cur;
00421                                 }
00422                                 else if (cur > high) {
00423                                         high = cur;
00424                                 }
00425                         }
00426 
00427                         m_bboxLow.SetCoord(d, low);
00428                         m_bboxHigh.SetCoord(d, high);
00429                 }
00430         }
00431 
00432         /*
00433                 RecurBuildTree
00434 
00435                 Recursive routine to build the tree. When the number of points
00436                 is less or equal to the leaf node bucket size, we make a new
00437                 leaf node. Otherwise, we build a new internal node. To construct
00438                 an internal node, we need to find the cutting plane that will
00439                 indicate which points go to the left side and which go to the
00440                 right. The cutting plane is computed using Bentley's standard
00441                 splitting routine for kd-trees.
00442 
00443                 PARAMETERS
00444                 i_points : given points used to build the tree structure
00445                 i_ptsIdx : indexes to the points in the given array
00446                 i_nPts : number of points left
00447         */
00448         KDNode<KDData> *RecurBuildTree(KDData **i_points, int *i_ptsIdx, int i_nPts)
00449         {
00450                 // If i_nPts small, make a leaf node
00451                 if (i_nPts <= m_bucketSize) {
00452                         if (i_nPts == 0) {
00453                                 // Return a reference to an empty leaf node
00454                                 return NULL;
00455                         }
00456                         else {
00457                                 // Return a new leaf node
00458                                 return new KDNode<KDData>(i_points, i_ptsIdx, i_nPts , m_dimSize);
00459                         }
00460                 }
00461 
00462                 // i_nPts large, make a splitting node
00463                 // Cutting dimension
00464                 int cd;
00465                 // Cutting value
00466                 KDData cv;
00467                 // Number of data on left side of the cut
00468                 int lowNum;
00469                 // Low and high children
00470                 KDNode<KDData> *lowNode, *highNode;
00471 
00472                 // Find splitting node
00473                 StdSplit(i_points, i_ptsIdx, i_nPts, cd, cv, lowNum);
00474 
00475                 // Save bounds for cutting dimension
00476                 KDData lv = m_bboxLow.GetCoord(cd);
00477                 KDData hv = m_bboxHigh.GetCoord(cd);
00478 
00479                 // Build left (low) subtree
00480                 m_bboxHigh.SetCoord(cd, cv);
00481                 lowNode = RecurBuildTree(i_points, i_ptsIdx, lowNum);
00482 
00483                 // Restore bounds
00484                 m_bboxHigh.SetCoord(cd, hv);
00485 
00486                 // Build right (high) subtree
00487                 m_bboxLow.SetCoord(cd, cv);
00488                 highNode = RecurBuildTree(i_points, i_ptsIdx + lowNum, i_nPts-lowNum);
00489                 // Restore bounds
00490                 m_bboxLow.SetCoord(cd, lv);
00491 
00492                 // Create the internal node
00493                 return new KDNode<KDData>(cd, cv, lv, hv, lowNode, highNode);
00494         }
00495 
00496         /*
00497                 StdSplit
00498 
00499                 Bentley's standard splitting routine for kd-trees. We find the dimension
00500                 with the greatest spread, and split just before the median point along
00501                 this dimension.
00502 
00503                 PARAMETERS
00504                 i_points : given points used to build the tree structure
00505                 i_ptsIdx : indexes to the points in the given array
00506                 i_nPts : number of points in given array
00507                 o_cd : cutting dimension (returned)
00508                 o_cv : cutting value (returned)
00509                 o_lowNum : number of points on low (left) side
00510         */
00511         void StdSplit(KDData **i_points, int *i_ptsIdx, int i_nPts, int &o_cd,
00512                 KDData &o_cv, int &o_lowNum)
00513         {
00514                 // Find dimension with maximum spread
00515                 o_cd = MaxSpread(i_points, i_ptsIdx, i_nPts);
00516 
00517                 // Median rank
00518                 o_lowNum = i_nPts >> 1;
00519 
00520                 MedianSplit(i_points, i_ptsIdx, i_nPts, o_cd, o_cv, o_lowNum);
00521         }
00522 
00523         /*
00524                 MaxSpread
00525 
00526                 Computes the dimension with the greatest spread in a given
00527                 points array.
00528 
00529                 PARAMETERS
00530                 i_points : given points used to build the tree structure
00531                 i_ptsIdx : indexes to the points in the given array
00532                 i_nPts : number of points in given array
00533 
00534                 RETURNS
00535                 Dimension with the greatest spread
00536         */
00537         int MaxSpread(KDData **i_points, int *i_ptsIdx, int i_nPts)
00538         {
00539                 int maxDim = 0;
00540                 KDData maxSprd = (KDData)0;
00541 
00542                 if (i_nPts == 0) {
00543                         return maxDim;
00544                 }
00545 
00546                 for (int d=0; d<m_dimSize; ++d) {
00547                         KDData sprd = DimSpread(i_points, i_ptsIdx, i_nPts, d);
00548 
00549                         if (sprd > maxSprd) {
00550                                 maxSprd = sprd;
00551                                 maxDim = d;
00552                         }
00553                 }
00554 
00555                 return maxDim;
00556         }
00557 
00558         /*
00559                 DimSpread
00560 
00561                 Computes the total spread along a given dimension in a given
00562                 points array.
00563 
00564                 PARAMETERS
00565                 i_points : given points used to build the tree structure
00566                 i_ptsIdx : indexes to the points in the given array
00567                 i_nPts : number of points in given array
00568                 i_dim : given dimension where to compute total spread
00569 
00570                 RETURNS
00571                 Total spread along given dimension
00572         */
00573         KDData DimSpread(KDData **i_points, int *i_ptsIdx, int i_nPts, int i_dim)
00574         {
00575                 KDData min = i_points[i_ptsIdx[0]][i_dim];
00576                 KDData max = i_points[i_ptsIdx[0]][i_dim];
00577 
00578                 for (int i=0; i<i_nPts; ++i) {
00579                         KDData cur = i_points[i_ptsIdx[i]][i_dim];
00580 
00581                         if (cur < min) {
00582                                 min = cur;
00583                         }
00584                         else if (cur > max) {
00585                                 max = cur;
00586                         }
00587                 }
00588 
00589                 // Total spread over the dimension is the extremum difference
00590                 return (max - min);
00591         }
00592 
00593         /*
00594                 MedianSplit
00595 
00596                 Split points array about its median into a subarray of points about
00597                 an element of given rank in dimension i_dim. Here the points indexes
00598                 are swap accordingly and the cutting value is computed.
00599 
00600                 PARAMETERS
00601                 i_points : given points used to build the tree structure
00602                 i_ptsIdx : indexes to the points in the given array (modified)
00603                 i_nPts : number of points in given array
00604                 i_dim : given dimension to consider
00605                 o_cv : cutting value (returned)
00606                 i_lowIdx : number of points on low (left) side
00607         */
00608         void MedianSplit(KDData **i_points, int *i_ptsIdx, int i_nPts, int i_dim,
00609                 KDData &o_cv, int i_lowIdx)
00610         {
00611                 // left end of current data
00612                 int l = 0;
00613                 // right end of current data
00614                 int r = i_nPts-1;
00615 
00616                 while (l < r) {
00617                         // select middle as pivot
00618                         int i = (r+l)/2;
00619                         int k = 0;
00620 
00621                         // Pivot needs to be less than the last value
00622                         if (i_points[i_ptsIdx[i]][i_dim] > i_points[i_ptsIdx[r]][i_dim]) {
00623                                 SwapPtsIdx(i_ptsIdx,i,r);
00624                         }
00625 
00626                         // move pivot to first position
00627                         SwapPtsIdx(i_ptsIdx,l,i);
00628 
00629                         KDData pivot = i_points[i_ptsIdx[l]][i_dim];
00630                         i = l;
00631                         k = r;
00632 
00633                         // Pivot around its value
00634                         while (1) {
00635                                 while (i_points[i_ptsIdx[++i]][i_dim] < pivot);
00636                                 while (i_points[i_ptsIdx[--k]][i_dim] > pivot);
00637                                 if (i < k) {
00638                                         SwapPtsIdx(i_ptsIdx,i,k);
00639                                 }
00640                                 else {
00641                                         break;
00642                                 }
00643                         }
00644 
00645                         // Place pivot at k
00646                         SwapPtsIdx(i_ptsIdx,l,k);
00647 
00648                         // Try to get the median
00649                         if (k > i_lowIdx) {
00650                                 r = k-1;
00651                         }
00652                         else if (k < i_lowIdx) {
00653                                 l = k+1;
00654                         }
00655                         else {
00656                                 // Got it
00657                                 break;
00658                         }
00659                 }
00660 
00661                 // Search for next smaller data
00662                 if (i_lowIdx > 0) {
00663                         KDData c = i_points[i_ptsIdx[0]][i_dim];
00664                         int k = 0;
00665 
00666                         for (int i = 1; i < i_lowIdx; i++) {
00667                                 if (i_points[i_ptsIdx[i]][i_dim] > c) {
00668                                         c = i_points[i_ptsIdx[i]][i_dim];
00669                                         k = i;
00670                                 }
00671                         }
00672 
00673                         SwapPtsIdx(i_ptsIdx, i_lowIdx-1, k);
00674                 }
00675 
00676                 // Cut value is midpoint value
00677                 o_cv = (i_points[i_ptsIdx[i_lowIdx-1]][i_dim] + i_points[i_ptsIdx[i_lowIdx]][i_dim])/(KDData)2;
00678         }
00679 
00680         /*
00681                 SwapPtsIdx
00682 
00683                 Swap element i_i with i_j in given array.
00684 
00685                 PARAMETERS
00686                 i_ptsIdx : array used to swap (modified)
00687                 i_i : index of first element in array
00688                 i_j : index of second element in array
00689         */
00690         void SwapPtsIdx(int *i_ptsIdx, int i_i, int i_j)
00691         {
00692                 int tmp = i_ptsIdx[i_i];
00693                 i_ptsIdx[i_i] = i_ptsIdx[i_j];
00694                 i_ptsIdx[i_j] = tmp;
00695         }
00696 
00697 private:
00698         // Number of reference points in tree structure
00699         int m_numPts;
00700         // Dimension size of reference points
00701         int m_dimSize;
00702         // Bucket size of leaf nodes
00703         int m_bucketSize;
00704         // Low corner point of bounding box including all the
00705         // reference points
00706         KDPoint<KDData> m_bboxLow;
00707         // High corner point of bounding box including all the
00708         // reference points
00709         KDPoint<KDData> m_bboxHigh;
00710         // Reference to root node
00711         KDNode<KDData> *m_root;
00712 
00713         // NN Search data member
00714         // Number of leaf nodes so far visisted
00715         int m_numVisited;
00716         // Maximum error to consider the exploration of the next node
00717         double m_maxErr;
00718 };
00719 
00720 }//namespace RobotFlow
00721 
00722 #endif

Generated on Wed Oct 5 14:36:12 2005 for RobotFlow by  doxygen 1.4.4