00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
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 
00035 
00036 
00037 template <class KDData>
00038 class KDNode : public FD::Object
00039 {
00040 public:
00041         
00042 
00043 
00044 
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 
00055 
00056 
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 
00071 
00072 
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 
00097 
00098 
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 
00123 
00124 
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 
00136 
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 
00145         KDNode<KDData> & operator =(const KDNode<KDData> &i_ref)
00146         {
00147                 
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 
00182 
00183 
00184 
00185 
00186 
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 
00241 
00242 
00243 
00244 
00245 
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 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
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 
00340 
00341 
00342 
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350 
00351 
00352 
00353 
00354 
00355 
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 
00375 
00376 
00377 
00378 
00379 
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                                         
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                                         
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 
00445 
00446 
00447 
00448 
00449 
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                                 
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                                         
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 
00512 
00513 
00514 
00515 
00516 
00517 
00518 
00519 
00520 
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                 
00532                 for (int i=0; i<m_nPts; ++i) {
00533                         
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                                 
00544                                 if (dist >= minDist) {
00545                                         break;
00546                                 }
00547                         }
00548 
00549                         
00550                         if (d >= m_dimSize && dist < minDist) {
00551                                 io_nnQueue->Insert(dist, &(m_bucketIdx[i]));
00552                                 minDist = io_nnQueue->GetMaxKey();
00553                         }
00554                 }
00555 
00556                 
00557                 io_numVisited += m_nPts;
00558         }
00559 
00560         
00561 
00562 
00563 
00564 
00565 
00566 
00567 
00568 
00569 
00570 
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                 
00582                 for (int i=0; i<m_nPts; ++i) {
00583                         
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                                 
00594                                 if (dist >= minDist) {
00595                                         break;
00596                                 }
00597                         }
00598 
00599                         
00600                         if (d >= m_dimSize && dist < minDist) {
00601                                 io_nnQueue->Insert(dist, &(m_bucket[i]));
00602                                 minDist = io_nnQueue->GetMaxKey();
00603                         }
00604                 }
00605 
00606                 
00607                 io_numVisited += m_nPts;
00608         }
00609 
00610         
00611 
00612 
00613 
00614 
00615 
00616 
00617 
00618 
00619 
00620 
00621 
00622 
00623 
00624 
00625 
00626 
00627 
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                 
00634                 
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                         
00643                         if (m_children[KDN_LOW] != NULL) {
00644                                 
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                                 
00651                                 if (bboxDiff < 0.0) {
00652                                         bboxDiff = 0.0;
00653                                 }
00654 
00655                                 
00656                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00657 
00658                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00659                                         
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                         
00667                         if (m_children[KDN_HIGH] != NULL) {
00668                                 
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                                 
00675                                 if (bboxDiff < 0.0) {
00676                                         bboxDiff = 0.0;
00677                                 }
00678 
00679                                 
00680                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00681 
00682                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00683                                         
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 
00693 
00694 
00695 
00696 
00697 
00698 
00699 
00700 
00701 
00702 
00703 
00704 
00705 
00706 
00707 
00708 
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                 
00715                 
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                         
00724                         if (m_children[KDN_LOW] != NULL) {
00725                                 
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                                 
00732                                 if (bboxDiff < 0.0) {
00733                                         bboxDiff = 0.0;
00734                                 }
00735 
00736                                 
00737                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00738 
00739                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00740                                         
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                         
00748                         if (m_children[KDN_HIGH] != NULL) {
00749                                 
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                                 
00756                                 if (bboxDiff < 0.0) {
00757                                         bboxDiff = 0.0;
00758                                 }
00759 
00760                                 
00761                                 io_bbDist += cutDist*cutDist - bboxDiff*bboxDiff;
00762 
00763                                 if (io_bbDist*i_maxErr < io_nnQueue->GetMaxKey()) {
00764                                         
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         
00774         int m_cutDim;
00775         
00776         KDData m_cutVal;
00777         
00778         KDData m_cutBnds[2];
00779         
00780         KDNode *m_children[2];
00781 
00782         
00783         int m_nPts;
00784         
00785         int m_dimSize;
00786         
00787         KDPoint<KDData> *m_bucket;
00788         
00789         int *m_bucketIdx;
00790 };
00791 
00792 }
00793 
00794 #endif