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

KDNode.h

Go to the documentation of this file.
00001 /* Copyright (C) 2004
00002    K-Dimension Tree Node 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 _KDNODE_H_
00020 #define _KDNODE_H_
00021 
00022 #include "Object.h"
00023 #include <stdio.h>
00024 #include <iostream>
00025 #include <math.h>
00026 #include "KDPoint.h"
00027 #include "KDPQueue.h"
00028 
00029 namespace RobotFlow {
00030 
00031 #define KDN_LOW 0
00032 #define KDN_HIGH 1
00033 
00034 // Template class for node values
00035 // IMPORTANT: class requires =, -, >, < operators
00036 //            it should usually be either double, float, int, ...
00037 template <class KDData>
00038 class KDNode : public FD::Object
00039 {
00040 public:
00041         /*
00042                 KDNode
00043 
00044                 Default constructor
00045         */
00046         KDNode()
00047         : m_nPts(0), m_dimSize(0), m_bucket(NULL), m_bucketIdx(NULL)
00048         {
00049                 m_children[KDN_LOW] = NULL;
00050                 m_children[KDN_HIGH] = NULL;
00051         }
00052 
00053         /*
00054                 KDNode
00055 
00056                 Internal Tree Node Constructor
00057         */
00058         KDNode(int i_cutDim, KDData i_cutVal, KDData i_lowVal,
00059                 KDData i_highVal, KDNode *i_lowChild, KDNode *i_highChild)
00060         : m_cutDim(i_cutDim), m_cutVal(i_cutVal), m_nPts(0), m_dimSize(0),
00061         m_bucket(NULL), m_bucketIdx(NULL)
00062         {
00063                 m_children[KDN_LOW] = i_lowChild;
00064                 m_children[KDN_HIGH] = i_highChild;
00065                 m_cutBnds[KDN_LOW] = i_lowVal;
00066                 m_cutBnds[KDN_HIGH] = i_highVal;
00067         }
00068 
00069         /*
00070                 KDNode
00071 
00072                 Leaf Node Constructor
00073         */
00074         KDNode(KDPoint<KDData> *i_dataPts, int *i_ptsIdx, int i_numPts, int i_dimSize)
00075         : m_nPts(i_numPts), m_dimSize(i_dimSize)
00076         {
00077                 m_children[KDN_LOW] = NULL;
00078                 m_children[KDN_HIGH] = NULL;
00079 
00080                 if (m_nPts == 0) {
00081                         m_bucket = NULL;
00082                         m_bucketIdx = NULL;
00083                         return;
00084                 }
00085 
00086                 m_bucket = new KDPoint<KDData>[m_nPts];
00087                 m_bucketIdx = new int[m_nPts];
00088 
00089                 for (int i=0; i<m_nPts; ++i) {
00090                         m_bucket[i] = i_dataPts[i_ptsIdx[i]];
00091                         m_bucketIdx[i] = i_ptsIdx[i];
00092                 }
00093         }
00094 
00095         /*
00096                 KDNode
00097 
00098                 Other Leaf Node Constructor
00099         */
00100         KDNode(KDData **i_dataPts, int *i_ptsIdx, int i_numPts, int i_dimSize)
00101         : m_nPts(i_numPts), m_dimSize(i_dimSize)
00102         {
00103                 m_children[KDN_LOW] = NULL;
00104                 m_children[KDN_HIGH] = NULL;
00105 
00106                 if (m_nPts == 0) {
00107                         m_bucket = NULL;
00108                         m_bucketIdx = NULL;
00109                         return;
00110                 }
00111 
00112                 m_bucket = new KDPoint<KDData>[m_nPts](m_dimSize);
00113                 m_bucketIdx = new int[m_nPts];
00114 
00115                 for (int i=0; i<m_nPts; ++i) {
00116                         m_bucket[i].SetPoint(i_dataPts[i_ptsIdx[i]]);
00117                         m_bucketIdx[i] = i_ptsIdx[i];
00118                 }
00119         }
00120 
00121         /*
00122                 ~KDNode
00123 
00124                 Destructor
00125         */
00126         ~KDNode()
00127         {
00128                 delete [] m_bucket;
00129                 delete [] m_bucketIdx;
00130                 delete m_children[KDN_LOW];
00131                 delete m_children[KDN_HIGH];
00132         }
00133 
00134         /*
00135                 operator =
00136 
00137                 Equal operator
00138 
00139                 PARAMETERS
00140                 i_ref : reference to node to copy
00141 
00142                 RETURNS
00143                 A copy of the given reference node
00144         */
00145         KDNode<KDData> & operator =(const KDNode<KDData> &i_ref)
00146         {
00147                 // Avoid self assignment
00148                 if (&i_ref == this) {
00149                         return *this;
00150                 }
00151 
00152                 m_cutDim = i_ref.m_cutDim;
00153                 m_cutVal = i_ref.m_cutVal;
00154                 m_cutBnds[0] = i_ref.m_cutBnds[0];
00155                 m_cutBnds[1] = i_ref.m_cutBnds[1];
00156                 m_nPts = i_ref.m_nPts;
00157                 m_dimSize = i_ref.m_dimSize;
00158 
00159                 if (m_bucket) {
00160                         delete [] m_bucket;
00161                 }
00162                 m_bucket = new KDPoint<KDData>[m_nPts];
00163 
00164                 if (m_bucketIdx) {
00165                         delete [] m_bucketIdx;
00166                 }
00167                 m_bucketIdx = new int[m_nPts];
00168 
00169                 for (int i=0; i<m_nPts; ++i) {
00170                         m_bucket[i] = i_ref.m_bucket[i];
00171                         m_bucketIdx[i] = i_ref.m_bucketIdx[i];
00172                 }
00173 
00174                 m_children[0] = i_ref.m_children[0];
00175                 m_children[1] = i_ref.m_children[1];
00176 
00177                 return *this;
00178         }
00179 
00180         /*
00181                 printOn
00182 
00183                 Object routine required to print its content
00184 
00185                 PARAMETERS
00186                 out : output stream to print the object content
00187         */
00188         void printOn(std::ostream &out) const
00189         {
00190                 out << "<KDNode " << std::endl;
00191                 if (m_children[KDN_LOW] == NULL &&
00192                         m_children[KDN_HIGH] == NULL &&
00193                         m_bucket != NULL) {
00194                         out << "<Type Leaf " << std::endl;
00195                         out << "<NumPts " << m_nPts << " >" << std::endl;
00196                         out << "<DimSize " << m_dimSize << " >" << std::endl;
00197 
00198                         out << "<Bucket " << std::endl;
00199                         for (int i=0; i<m_nPts; ++i) {
00200                                 m_bucket[i].printOn(out);
00201                         }
00202                         out << " >" << std::endl;
00203 
00204                         out << "<BucketIdx ";
00205                         for (int i=0; i<m_nPts; ++i) {
00206                                 out << m_bucketIdx[i] << " ";
00207                         }
00208                         out << " >" << std::endl;
00209 
00210                         out << " >" << std::endl;
00211                         out << " >" << std::endl;
00212                 }
00213                 else {
00214                         out << "<Type Internal " << std::endl;
00215                         out << "<CutDim " << m_cutDim << " >" << std::endl;
00216                         out << "<CutVal " << m_cutVal << " >" << std::endl;
00217                         out << "<CutBounds " << m_cutBnds[0] << " " << m_cutBnds[1]
00218                                 << " >" << std::endl;
00219 
00220                         if (m_children[KDN_LOW] != NULL) {
00221                                 out << "<LowChild " << std::endl;
00222                                 m_children[KDN_LOW]->printOn(out);
00223                                 out << " >" << std::endl;
00224                         }
00225 
00226                         if (m_children[KDN_HIGH] != NULL) {
00227                                 out << "<HighChild " << std::endl;
00228                                 m_children[KDN_HIGH]->printOn(out);
00229                                 out << " >" << std::endl;
00230                         }
00231 
00232                         out << " >" << std::endl;
00233                         out << " >" << std::endl;
00234                 }
00235 
00236                 out << " >" << std::endl;
00237         }
00238 
00239         /*
00240                 readFrom
00241 
00242                 Object routine required to read an Object content
00243 
00244                 PARAMETERS
00245                 in : input stream to read the object content
00246         */
00247         void readFrom(std::istream &in)
00248         {
00249                 std::string tag;
00250 
00251                 while (1) {
00252                         char ch;
00253                         in >> ch;
00254 
00255                         if (ch == '>') {
00256                                 break;
00257                         }
00258                         else if (ch != '<') {
00259                                 throw new FD::GeneralException ("KDNode::readFrom : Parse error: '<' expected",__FILE__,__LINE__);
00260                         }
00261 
00262                         in >> tag;
00263 
00264                         if (tag == "KDNode") {
00265                                 continue;
00266                         }
00267                         else if (tag == "Type") {
00268                                 in >> tag;
00269                                 if (tag == "Internal") {
00270                                         try {
00271                                                 readFromInternal(in);
00272                                         }
00273                                         catch (FD::GeneralException *e) {
00274                                                 throw e;
00275                                         }
00276                                 }
00277                                 else if (tag == "Leaf") {
00278                                         try {
00279                                                 readFromLeaf(in);
00280                                         }
00281                                         catch (FD::GeneralException *e) {
00282                                                 throw e;
00283                                         }
00284                                 }
00285                                 else {
00286                                         throw new FD::GeneralException ("KDNode::readFrom : unknown KDNode type",__FILE__,__LINE__);
00287                                 }
00288                         }
00289                         else {
00290                                 throw new FD::GeneralException ("KDNode::readFrom : Unknown argument: " + tag,__FILE__,__LINE__);
00291                         }
00292 
00293                         if (!in) {
00294                                 throw new FD::GeneralException ("KDNode::readFrom : Parse error trying to build " + tag,__FILE__,__LINE__);
00295                         }
00296 
00297                         in >> tag;
00298                         if (tag != ">") {
00299                                 throw new FD::GeneralException ("KDNode::readFrom : Parse error: '>' expected ",__FILE__,__LINE__);
00300                         }
00301                 }
00302         }
00303 
00304         /*
00305                 NNSearch
00306 
00307                 Nearest neighbor recursive search routine. At this level, we only determine
00308                 if we need to make a search in a leaf node (search its bucket) or in an
00309                 internal node (find the next node to search).
00310 
00311                 PARAMETERS
00312                 i_qp : query point given to find its nearest neighbors
00313                 i_maxNumNodes : maximum number of leaf nodes to visit before to stop the
00314                         search. If it is set to 0, than all the tree can be
00315                         searched.
00316                 io_numVisited : number of leaf nodes visited so far (modified)
00317                 i_maxErr : error bound to determine if we should visit a child node.
00318                 io_bbDist : distance from query point to the tree points bounding box.
00319                 io_nnQueue : priority queue containing the current NN information (modified).
00320                         In this priority queue, the NN distances are used as keys and the
00321                         NN point indexes, as elements.
00322 
00323         */
00324         void NNSearch(KDPoint<KDData> *i_qp, int i_maxNumNodes, int &io_numVisited,
00325                 double i_maxErr, double io_bbDist, KDPQueue<double, int> *io_nnQueue)
00326         {
00327                 if (m_children[KDN_LOW] == NULL &&
00328                         m_children[KDN_HIGH] == NULL &&
00329                         m_bucket != NULL) {
00330                         NNBucketSearch(i_qp, io_numVisited, io_nnQueue);
00331                 }
00332                 else if (m_children[KDN_LOW] != NULL || m_children[KDN_HIGH] != NULL) {
00333                         NNNodeSearch(i_qp, i_maxNumNodes, io_numVisited, i_maxErr, io_bbDist,
00334                                 io_nnQueue);
00335                 }
00336         }
00337 
00338         /*
00339                 NNSearch
00340 
00341                 Nearest neighbor search recursive routine. At this level, we only determine
00342                 if we need to make a search in a leaf node (search its bucket) or in an
00343                 internal node (find the next node to search).
00344 
00345                 PARAMETERS
00346                 i_qp : query point given to find its nearest neighbors
00347                 i_maxNumNodes : maximum number of leaf nodes to visit before to stop the
00348                         search. If it is set to 0, than all the tree can be
00349                         searched.
00350                 io_numVisited : number of leaf nodes visited so far (modified)
00351                 i_maxErr : error bound to determine if we should visit a child node.
00352                 io_bbDist : distance from query point to the tree points bounding box.
00353                 io_nnQueue : priority queue containing the current NN information (modified).
00354                         In this priority queue, the NN distances are used as keys and the
00355                         NN points, as elements. (modified)
00356 
00357         */
00358         void NNSearch(KDPoint<KDData> *i_qp, int i_maxNumNodes, int &io_numVisited,
00359                 double i_maxErr, double io_bbDist, KDPQueue<double, KDPoint<KDData> > *io_nnQueue)
00360         {
00361                 if (m_children[KDN_LOW] == NULL &&
00362                         m_children[KDN_HIGH] == NULL &&
00363                         m_bucket != NULL) {
00364                         NNBucketSearch(i_qp, io_numVisited, io_nnQueue);
00365                 }
00366                 else if (m_children[KDN_LOW] != NULL || m_children[KDN_HIGH] != NULL) {
00367                         NNNodeSearch(i_qp, i_maxNumNodes, io_numVisited, i_maxErr, io_bbDist,
00368                                 io_nnQueue);
00369                 }
00370         }
00371 
00372 private:
00373         /*
00374                 readFromInternal
00375 
00376                 Specific routine to read the content of an internal node
00377 
00378                 PARAMETERS
00379                 in : input stream to read the object content
00380         */
00381         void readFromInternal(std::istream &in)
00382         {
00383                 std::string tag;
00384 
00385                 while (1) {
00386                         char ch;
00387                         in >> ch;
00388 
00389                         if (ch == '>') {
00390                                 break;
00391                         }
00392                         else if (ch != '<') {
00393                                 throw new FD::GeneralException ("KDNode::readFromInternal : Parse error: '<' expected",__FILE__,__LINE__);
00394                         }
00395 
00396                         in >> tag;
00397 
00398                         if (tag == "CutDim") {
00399                                 in >> m_cutDim;
00400                         }
00401                         else if (tag == "CutVal") {
00402                                 in >> m_cutVal;
00403                         }
00404                         else if (tag == "CutBounds") {
00405                                 in >> m_cutBnds[0];
00406                                 in >> m_cutBnds[1];
00407                         }
00408                         else if (tag == "LowChild") {
00409                                 try {
00410                                         // Allocate low child node
00411                                         m_children[KDN_LOW] = new KDNode<KDData>();
00412                                         m_children[KDN_LOW]->readFrom(in);
00413                                 }
00414                                 catch (FD::GeneralException *e) {
00415                                         throw e;
00416                                 }
00417                         }
00418                         else if (tag == "HighChild") {
00419                                 try {
00420                                         // Allocate high child node
00421                                         m_children[KDN_HIGH] = new KDNode<KDData>();
00422                                         m_children[KDN_HIGH]->readFrom(in);
00423                                 }
00424                                 catch (FD::GeneralException *e) {
00425                                         throw e;
00426                                 }
00427                         }
00428                         else {
00429                                 throw new FD::GeneralException ("KDNode::readFromInternal : Unknown argument: " + tag,__FILE__,__LINE__);
00430                         }
00431 
00432                         if (!in) {
00433                                 throw new FD::GeneralException ("KDNode::readFromInternal : Parse error trying to build " + tag,__FILE__,__LINE__);
00434                         }
00435 
00436                         in >> tag;
00437                         if (tag != ">") {
00438                                 throw new FD::GeneralException ("KDNode::readFromInternal : Parse error: '>' expected ",__FILE__,__LINE__);
00439                         }
00440                 }
00441         }
00442 
00443         /*
00444                 readFromLeaf
00445 
00446                 Specific routine to read the content of a leaf node
00447 
00448                 PARAMETERS
00449                 in : input stream to read the object content
00450         */
00451         void readFromLeaf(std::istream &in)
00452         {
00453                 std::string tag;
00454 
00455                 while (1) {
00456                         char ch;
00457                         in >> ch;
00458 
00459                         if (ch == '>') {
00460                                 break;
00461                         }
00462                         else if (ch != '<') {
00463                                 throw new FD::GeneralException ("KDNode::readFromLeaf : Parse error: '<' expected",__FILE__,__LINE__);
00464                         }
00465 
00466                         in >> tag;
00467 
00468                         if (tag == "NumPts") {
00469                                 in >> m_nPts;
00470                         }
00471                         else if (tag == "DimSize") {
00472                                 in >> m_dimSize;
00473                         }
00474                         else if (tag == "BucketIdx") {
00475                                 // Allocate index bucket
00476                                 m_bucketIdx = new int[m_nPts];
00477 
00478                                 for (int i=0; i<m_nPts; ++i) {
00479                                         in >> m_bucketIdx[i];
00480                                 }
00481                         }
00482                         else if (tag == "Bucket") {
00483                                 try {
00484                                         // Allocate bucket
00485                                         m_bucket = new KDPoint<KDData>[m_nPts];
00486 
00487                                         for (int i=0; i<m_nPts; ++i) {
00488                                                 m_bucket[i].readFrom(in);
00489                                         }
00490                                 }
00491                                 catch (FD::GeneralException *e) {
00492                                         throw e->add(new FD::GeneralException("In KDNode::readFromLeaf : ",__FILE__,__LINE__));
00493                                 }
00494                         }
00495                         else {
00496                                 throw new FD::GeneralException ("KDNode::readFromLeaf : Unknown argument: " + tag,__FILE__,__LINE__);
00497                         }
00498 
00499                         if (!in) {
00500                                 throw new FD::GeneralException ("KDNode::readFromLeaf : Parse error trying to build " + tag,__FILE__,__LINE__);
00501                         }
00502 
00503                         in >> tag;
00504                         if (tag != ">") {
00505                                 throw new FD::GeneralException ("KDNode::readFromLeaf : Parse error: '>' expected ",__FILE__,__LINE__);
00506                         }
00507                 }
00508         }
00509 
00510         /*
00511                 NNBucketSearch
00512 
00513                 Nearest neighbor search routine to search the content of a leaf node bucket.
00514 
00515                 PARAMETERS
00516                 i_qp : query point given to find its nearest neighbors
00517                 io_numVisited : number of leaf nodes visited so far (modified)
00518                 io_nnQueue : priority queue containing the current NN information (modified).
00519                         In this priority queue, the NN distances are used as keys and the
00520                         NN point indexes, as elements. (modified)
00521 
00522         */
00523         void NNBucketSearch(KDPoint<KDData> *i_qp, int &io_numVisited,
00524                 KDPQueue<double, int> *io_nnQueue)
00525         {
00526                 int d;
00527                 double dist;
00528                 double tmp;
00529                 double minDist = io_nnQueue->GetMaxKey();
00530 
00531                 //Search through all points in bucket
00532                 for (int i=0; i<m_nPts; ++i) {
00533                         // Use pointers on coordinates of bucket and query points
00534                         KDData *bktDataPtr = m_bucket[i].GetPoint();
00535                         KDData *queryPtPtr = i_qp->GetPoint();
00536 
00537                         dist = 0.0;
00538 
00539                         for (d=0; d<m_dimSize; ++d) {
00540                                 tmp = (double)(*(bktDataPtr++)) - (double)(*(queryPtPtr++));
00541                                 dist += tmp*tmp;
00542 
00543                                 // Check if current distance exceeds min distance so far
00544                                 if (dist >= minDist) {
00545                                         break;
00546                                 }
00547                         }
00548 
00549                         // Check if current point is the current nearest neighbor
00550                         if (d >= m_dimSize && dist < minDist) {
00551                                 io_nnQueue->Insert(dist, &(m_bucketIdx[i]));
00552                                 minDist = io_nnQueue->GetMaxKey();
00553                         }
00554                 }
00555 
00556                 // Increment number of points visited
00557                 io_numVisited += m_nPts;
00558         }
00559 
00560         /*
00561                 NNBucketSearch
00562 
00563                 Nearest neighbor search routine to search the content of a leaf node bucket.
00564 
00565                 PARAMETERS
00566                 i_qp : query point given to find its nearest neighbors
00567                 io_numVisited : number of leaf nodes visited so far (modified)
00568                 io_nnQueue : priority queue containing the current NN information (modified).
00569                         In this priority queue, the NN distances are used as keys and the
00570                         NN points, as elements. (modified)
00571 
00572         */
00573         void NNBucketSearch(KDPoint<KDData> *i_qp, int &io_numVisited,
00574                 KDPQueue<double, KDPoint<KDData> > *io_nnQueue)
00575         {
00576                 int d;
00577                 double dist;
00578                 double tmp;
00579                 double minDist = io_nnQueue->GetMaxKey();
00580 
00581                 //Search through all points in bucket
00582                 for (int i=0; i<m_nPts; ++i) {
00583                         // Use pointers on coordinates of bucket and query points
00584                         KDData *bktDataPtr = m_bucket[i].GetPoint();
00585                         KDData *queryPtPtr = i_qp->GetPoint();
00586 
00587                         dist = 0.0;
00588 
00589                         for (d=0; d<m_dimSize; ++d) {
00590                                 tmp = (double)(*(bktDataPtr++)) - (double)(*(queryPtPtr++));
00591                                 dist += tmp*tmp;
00592 
00593                                 // Check if current distance exceeds min distance so far
00594                                 if (dist >= minDist) {
00595                                         break;
00596                                 }
00597                         }
00598 
00599                         // Check if current point is the current nearest neighbor
00600                         if (d >= m_dimSize && dist < minDist) {
00601                                 io_nnQueue->Insert(dist, &(m_bucket[i]));
00602                                 minDist = io_nnQueue->GetMaxKey();
00603                         }
00604                 }
00605 
00606                 // Increment number of points visited
00607                 io_numVisited += m_nPts;
00608         }
00609 
00610         /*
00611                 NNNodeSearch
00612 
00613                 Nearest neighbor search recursive routine. At this level, we only determine
00614                 if we need to make a search in a leaf node (search its bucket) or in an
00615                 internal node (find the next node to search).
00616 
00617                 PARAMETERS
00618                 i_qp : query point given to find its nearest neighbors
00619                 i_maxNumNodes : maximum number of leaf nodes to visit before to stop the
00620                         search. If it is set to 0, than all the tree can be
00621                         searched.
00622                 io_numVisited : number of leaf nodes visited so far (modified)
00623                 i_maxErr : error bound to determine if we should visit a child node.
00624                 io_bbDist : distance from query point to the tree points bounding box.
00625                 io_nnQueue : priority queue containing the current NN information (modified).
00626                         In this priority queue, the NN distances are used as keys and the
00627                         NN points, as elements. (modified)
00628 
00629         */
00630         void NNNodeSearch(KDPoint<KDData> *i_qp, int i_maxNumNodes, int &io_numVisited,
00631                 double i_maxErr, double io_bbDist, KDPQueue<double, int> *io_nnQueue)
00632         {
00633                 // Verify if we visited enough leaf nodes. If i_maxNumNodes = 0, we make a
00634                 // complete search
00635                 if (i_maxNumNodes && io_numVisited >= i_maxNumNodes) {
00636                         return;
00637                 }
00638 
00639                 double cutDist = (double)(i_qp->GetCoord(m_cutDim)) - (double)m_cutVal;
00640 
00641                 if (cutDist < 0.0) {
00642                         // Left side of cutting plane
00643                         if (m_children[KDN_LOW] != NULL) {
00644                                 // Visit closer child first
00645                                 m_children[KDN_LOW]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00646                                         i_maxErr, io_bbDist, io_nnQueue);
00647 
00648                                 double bboxDiff = (double)(m_cutBnds[KDN_LOW]) - (double)(i_qp->GetCoord(m_cutDim));
00649 
00650                                 // Ignore if within bounds
00651                                 if (bboxDiff < 0.0) {
00652                                         bboxDiff = 0.0;
00653                                 }
00654 
00655                                 // Increase distance to include child bounding box
00656                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00657 
00658                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00659                                         // Other child is close enough
00660                                         m_children[KDN_HIGH]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00661                                                 i_maxErr, io_bbDist, io_nnQueue);
00662                                 }
00663                         }
00664                 }
00665                 else {
00666                         // Right side of cutting plane
00667                         if (m_children[KDN_HIGH] != NULL) {
00668                                 // Visit closer child first
00669                                 m_children[KDN_HIGH]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00670                                         i_maxErr, io_bbDist, io_nnQueue);
00671 
00672                                 double bboxDiff = (double)(i_qp->GetCoord(m_cutDim)) - (double)(m_cutBnds[KDN_HIGH]);
00673 
00674                                 // Ignore if within bounds
00675                                 if (bboxDiff < 0.0) {
00676                                         bboxDiff = 0.0;
00677                                 }
00678 
00679                                 // Increase distance to include child bounding box
00680                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00681 
00682                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00683                                         // Other child is close enough
00684                                         m_children[KDN_LOW]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00685                                                 i_maxErr, io_bbDist, io_nnQueue);
00686                                 }
00687                         }
00688                 }
00689         }
00690 
00691         /*
00692                 NNNodeSearch
00693 
00694                 Nearest neighbor search recursive routine. At this level, we only determine
00695                 if we need to make a search in a leaf node (search its bucket) or in an
00696                 internal node (find the next node to search).
00697 
00698                 PARAMETERS
00699                 i_qp : query point given to find its nearest neighbors
00700                 i_maxNumNodes : maximum number of leaf nodes to visit before to stop the
00701                         search. If it is set to 0, than all the tree can be
00702                         searched.
00703                 io_numVisited : number of leaf nodes visited so far (modified)
00704                 i_maxErr : error bound to determine if we should visit a child node.
00705                 io_bbDist : distance from query point to the tree points bounding box.
00706                 io_nnQueue : priority queue containing the current NN information (modified).
00707                         In this priority queue, the NN distances are used as keys and the
00708                         NN point indexes, as elements. (modified)
00709 
00710         */
00711         void NNNodeSearch(KDPoint<KDData> *i_qp, int i_maxNumNodes, int &io_numVisited,
00712                 double i_maxErr, double io_bbDist, KDPQueue<double, KDPoint<KDData> > *io_nnQueue)
00713         {
00714                 // Verify if we visited enough leaf nodes. If i_maxNumNodes = 0, we make a
00715                 // complete search
00716                 if (i_maxNumNodes && io_numVisited >= i_maxNumNodes) {
00717                         return;
00718                 }
00719 
00720                 double cutDist = (double)(i_qp->GetCoord(m_cutDim)) - (double)m_cutVal;
00721 
00722                 if (cutDist < 0.0) {
00723                         // Left side of cutting plane
00724                         if (m_children[KDN_LOW] != NULL) {
00725                                 // Visit closer child first
00726                                 m_children[KDN_LOW]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00727                                         i_maxErr, io_bbDist, io_nnQueue);
00728 
00729                                 double bboxDiff = (double)(m_cutBnds[KDN_LOW]) - (double)(i_qp->GetCoord(m_cutDim));
00730 
00731                                 // Ignore if within bounds
00732                                 if (bboxDiff < 0.0) {
00733                                         bboxDiff = 0.0;
00734                                 }
00735 
00736                                 // Increase distance to include child bounding box
00737                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00738 
00739                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00740                                         // Other child is close enough
00741                                         m_children[KDN_HIGH]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00742                                                 i_maxErr, io_bbDist, io_nnQueue);
00743                                 }
00744                         }
00745                 }
00746                 else {
00747                         // Right side of cutting plane
00748                         if (m_children[KDN_HIGH] != NULL) {
00749                                 // Visit closer child first
00750                                 m_children[KDN_HIGH]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00751                                         i_maxErr, io_bbDist, io_nnQueue);
00752 
00753                                 double bboxDiff = (double)(i_qp->GetCoord(m_cutDim)) - (double)(m_cutBnds[KDN_HIGH]);
00754 
00755                                 // Ignore if within bounds
00756                                 if (bboxDiff < 0.0) {
00757                                         bboxDiff = 0.0;
00758                                 }
00759 
00760                                 // Increase distance to include child bounding box
00761                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00762 
00763                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00764                                         // Other child is close enough
00765                                         m_children[KDN_LOW]->NNSearch(i_qp, i_maxNumNodes, io_numVisited,
00766                                                 i_maxErr, io_bbDist, io_nnQueue);
00767                                 }
00768                         }
00769                 }
00770         }
00771 
00772 private:
00773         // Orthogonal dimension to cutting plane
00774         int m_cutDim;
00775         // Location of cutting plane
00776         KDData m_cutVal;
00777         // Bounds along orthogonal dimension to cutting plane
00778         KDData m_cutBnds[2];
00779         // Current node children
00780         KDNode *m_children[2];
00781 
00782         // Number of points in bucket
00783         int m_nPts;
00784         // Dimension size of points in bucket
00785         int m_dimSize;
00786         // Bucket of points
00787         KDPoint<KDData> *m_bucket;
00788         // Bucket of indexes of the points
00789         int *m_bucketIdx;
00790 };
00791 
00792 }//namespace RobotFlow
00793 
00794 #endif

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