latest version v1.9 - last update 10 Apr 2010 |
00001 /* 00002 * Copyright (C) 2003, 2004, 2005, 2006 00003 * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany 00004 * 00005 * This file is part of the LTI-Computer Vision Library (LTI-Lib) 00006 * 00007 * The LTI-Lib is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public License (LGPL) 00009 * as published by the Free Software Foundation; either version 2.1 of 00010 * the License, or (at your option) any later version. 00011 * 00012 * The LTI-Lib is distributed in the hope that it will be 00013 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00014 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with the LTI-Lib; see the file LICENSE. If 00019 * not, write to the Free Software Foundation, Inc., 59 Temple Place - 00020 * Suite 330, Boston, MA 02111-1307, USA. 00021 */ 00022 00023 00024 /*-------------------------------------------------------------------- 00025 * project ....: LTI-Lib: Image Processing and Computer Vision Library 00026 * file .......: ltiKdTree.h 00027 * authors ....: Frederik Lange, Pablo Alvarado, Jens Rietzschel 00028 * organization: LTI, RWTH Aachen 00029 * creation ...: 9.1.2003 00030 * revisions ..: $Id: ltiKdTree.h,v 1.29 2006/02/08 12:28:23 ltilib Exp $ 00031 */ 00032 00033 #ifndef _LTI_KD_TREE_H_ 00034 #define _LTI_KD_TREE_H_ 00035 00036 #include "ltiMathObject.h" 00037 #include "ltiMath.h" 00038 #include "ltiQuickMedian.h" 00039 #include "ltiL2Distance.h" 00040 #include "ltiSTLIoInterface.h" 00041 #include "ltiTypeInfo.h" 00042 00043 #include <list> 00044 #include <map> 00045 00046 namespace lti { 00047 00048 /** 00049 * A class for k-d tree. 00050 * 00051 * A k-d tree is a generalization of the simple binary tree used for 00052 * sorting and searching. At each level of the tree, a 00053 * n-dimensional subspace is split in two subspaces at a given 00054 * dimension. The leaves of the tree contain a "bucket" of data 00055 * within the described subspace. 00056 * 00057 * You can consider data for building with the add() method. Then 00058 * you can either build() the tree from that data, discarding the 00059 * old data, or rebuild() the tree, which will then contain the data 00060 * added since the last call to build() or rebuild() plus the newly 00061 * added data. 00062 * 00063 * This type allows to search in an efficient way for the 00064 * more similar neighbors of a given point. 00065 * 00066 * The type T describes a point in an n-dimensional space. Usually, 00067 * you will use vector<float> or vector<double>, but types like 00068 * rgbPixel, trgbPixel<float>, tpoint<float> are also supported. 00069 * The type T MUST provide following methods/operators: 00070 00071 * - copy %operator=() 00072 * - access operator[]() 00073 * - size() method 00074 * - must define the type <code>value_type</code>, which describes the 00075 * type of each element in the container. 00076 * - comparison %operator==() 00077 * 00078 * (lti::vector, lti::tpoint, lti::tpoint3D, lti::trgbpixel and 00079 * lti::rgbPixel provide this interface) 00080 * 00081 * The type D describes the data contained at each node, which is per default 00082 * just an integer value. It must provide following methods/operators 00083 * - copy operator=() 00084 * 00085 * The type U specifies a "distantor" policy, i.e. it specifies the 00086 * distance to be used while computing the nearest neighbors. If 00087 * not given, the default value will be l2SquareDistantor, which 00088 * provides, as the name says, the square of the euclidian distance. 00089 * Only Minkowski distances are allowed. If you need your own 00090 * distance measure you can create your policy following the 00091 * interfaces of one of the classes lti::l2Distantor, 00092 * lti::l1Distantor or l2SquareDistantor. 00093 * 00094 * \Note: Elements added to the tree after a call to build() or 00095 * rebuild() are not saved when calling write(). 00096 * 00097 * The original kd-Tree algorithm for k-neareast neighbors problems was 00098 * introduced in: 00099 * Friedman, J.H., Bentley, J.L. and Finkel, R.A. An Algorithm for Finding 00100 * Best Matches in Logarithmic Expected Time. ACM Transaction on 00101 * Mathematical Software, Vol. 3, No. 3, September 1977, Pages 209-225 00102 * 00103 * @ingroup gAggregate 00104 */ 00105 template <class T,class D=int,class U=l2SquareDistantor<T> > 00106 class kdTree : public mathObject, public status { 00107 public: 00108 /** 00109 * Value type at each dimension of the space 00110 */ 00111 typedef typename T::value_type value_type; 00112 00113 /** 00114 * Type used to accumulate data of value_type elements 00115 */ 00116 typedef typename typeInfo<value_type>::accumulation_type acc_type; 00117 00118 /** 00119 * At the leave nodes, a list of elements of this type will contain 00120 * the points and their corresponding data. 00121 * 00122 * Implementation must be here due to MS VC++ bug 00123 */ 00124 class element : public ioObject { 00125 public: 00126 00127 /** 00128 * n-dimensional point representing the position of this element 00129 * in the n-dimensional space 00130 */ 00131 T point; 00132 00133 /** 00134 * data contained in this element. 00135 */ 00136 D data; 00137 00138 /** 00139 * Constructor 00140 */ 00141 element() : ioObject(),point(T()),data(D()) { 00142 }; 00143 00144 /** 00145 * Constructor 00146 * 00147 * @param pos n-dimensional vector position of this element 00148 * @param dat data contained in this element 00149 */ 00150 element(const T& pos, const D& dat) 00151 : ioObject(),point(pos),data(dat) { 00152 }; 00153 00154 /** 00155 * Copy constructor 00156 */ 00157 element(const element& other) 00158 : ioObject(),point(other.point),data(other.data) { 00159 }; 00160 00161 /** 00162 * destructor 00163 */ 00164 ~element() { 00165 }; 00166 00167 /** 00168 * shortcut to access the point value at each dimension 00169 */ 00170 inline value_type& operator[](const int a) {return point[a];} 00171 00172 /** 00173 * shortcut to access the point value at each dimension 00174 */ 00175 inline const value_type& operator[](const int a) const {return point[a];} 00176 00177 /** 00178 * shortcut to access the size of the points stored 00179 */ 00180 inline int size() const { 00181 return point.size(); 00182 } 00183 00184 /** 00185 * copy method 00186 */ 00187 element& copy(const element& other) { 00188 point=other.point; 00189 data=other.data; 00190 return *this; 00191 } 00192 00193 /** 00194 * copy operator 00195 */ 00196 inline element& operator=(const element& other) { 00197 return copy(other); 00198 } 00199 00200 /** 00201 * clone member 00202 */ 00203 element* clone() const { 00204 return new element(*this); 00205 } 00206 00207 # ifndef _LTI_MSC_6 00208 /** 00209 * read the parameters from the given ioHandler 00210 * @param handler the ioHandler to be used 00211 * @param complete if true (the default) the enclosing begin/end will 00212 * be also read, otherwise only the data block will be read. 00213 * @return true if write was successful 00214 */ 00215 virtual bool read(ioHandler &handler, const bool complete=true) 00216 # else 00217 bool readMS(ioHandler& handler,const bool complete=true) 00218 # endif 00219 { 00220 bool b=true; 00221 00222 if (complete) { 00223 b = handler.readBegin(); 00224 } 00225 00226 b = b && lti::read(handler,point); 00227 b = b && handler.readDataSeparator(); 00228 b = b && lti::read(handler,data); 00229 00230 if (complete) { 00231 b= b && handler.readEnd(); 00232 } 00233 00234 return b; 00235 } 00236 00237 # ifdef _LTI_MSC_6 00238 /** 00239 * read the parameters from the given ioHandler 00240 * @param handler the ioHandler to be used 00241 * @param complete if true (the default) the enclosing begin/end will 00242 * be also read, otherwise only the data block will be read. 00243 * @return true if write was successful 00244 */ 00245 virtual bool read(ioHandler& handler,const bool complete=true) { 00246 // ...we need this workaround to cope with another really awful MSVC 00247 // bug. 00248 return readMS(handler,complete); 00249 } 00250 # endif 00251 00252 # ifndef _LTI_MSC_6 00253 /** 00254 * write the parameters in the given ioHandler 00255 * @param handler the ioHandler to be used 00256 * @param complete if true (the default) the enclosing begin/end will 00257 * be also written, otherwise only the data block will be 00258 * written. 00259 * @return true if write was successful 00260 */ 00261 virtual bool write(ioHandler& handler,const bool complete=true) const 00262 # else 00263 bool writeMS(ioHandler& handler,const bool complete=true) const 00264 # endif 00265 { 00266 bool b=true; 00267 00268 if (complete) { 00269 b = handler.writeBegin(); 00270 } 00271 00272 b = b && lti::write(handler,point); 00273 b = b && handler.writeDataSeparator(); 00274 b = b && lti::write(handler,data); 00275 00276 if (complete) { 00277 b= b && handler.writeEnd(); 00278 } 00279 00280 return b; 00281 } 00282 00283 # ifdef _LTI_MSC_6 00284 /** 00285 * write the parameters to the given ioHandler 00286 * @param handler the ioHandler to be used 00287 * @param complete if true (the default) the enclosing begin/end will 00288 * be also writen, otherwise only the data block will be writen. 00289 * @return true if write was successful 00290 */ 00291 virtual bool write(ioHandler& handler,const bool complete=true) { 00292 // ...we need this workaround to cope with another really awful MSVC 00293 // bug. 00294 return writeMS(handler,complete); 00295 } 00296 # endif 00297 }; 00298 00299 /** 00300 * Class of nodes of the kd-tree 00301 * 00302 * Implementation must be here due to MS VC++ bug 00303 */ 00304 class node : public ioObject { 00305 // the enclosing class is a friend of mine. 00306 friend class kdTree<T,D,U>; 00307 public: 00308 00309 /** 00310 * type used for the container of elements. 00311 * A std::vector is for the search much more appropriate because 00312 * the access through iterators is about a factor 5 faster than the 00313 * std::list type. 00314 */ 00315 typedef std::vector<element*> points_type; 00316 00317 /** 00318 * @name Attributes 00319 */ 00320 //@{ 00321 /** 00322 * Points stored in this node. These are pointers to the data 00323 * allocated in the kdTree class, this way the data can be 00324 * "transfered" more efficiently between different nodes. The 00325 * memory managment is done by this node. 00326 */ 00327 points_type points; 00328 00329 /** 00330 * the left subtree (lower coordinate) from the split plane 00331 */ 00332 node* left; 00333 00334 /** 00335 * the right subtree (higher coordinate) from the split plane 00336 */ 00337 node* right; 00338 00339 /** 00340 * the dimension in which the subnodes are split. This is 00341 * called in the original paper "discriminator" 00342 */ 00343 int splitDim; 00344 00345 /** 00346 * Value at the split dimension where the splitting takes place. 00347 * Usually this value corresponds to the median at the given 00348 * split dimension. 00349 * 00350 */ 00351 value_type partition; 00352 //@} 00353 00354 /** 00355 * constructor 00356 */ 00357 node() 00358 : ioObject(),points(),left(0),right(0),splitDim(0), 00359 partition(value_type()) { 00360 }; 00361 00362 /** 00363 * copy constructor. 00364 * Makes a deep copy, i.e. the pointers will be different 00365 */ 00366 node(const node& other) 00367 : ioObject(),points(),left(0),right(0) { 00368 copy(other); 00369 } 00370 00371 /** 00372 * destructor 00373 */ 00374 ~node() { 00375 clearPoints(); 00376 00377 if(left!=0) { 00378 delete left; 00379 left=0; 00380 } 00381 if(right!=0) { 00382 delete right; 00383 right=0; 00384 } 00385 }; 00386 00387 /** 00388 * insert a pointer to an element into the points list. 00389 * 00390 * The pointed element will be inserted as is (without copying), and 00391 * the memory managment is controled by the node itself. 00392 * 00393 * The dimensionality of each element MUST be equal than the one 00394 * of the first element added. 00395 */ 00396 void add(element* f) { 00397 points.push_back(f); 00398 } 00399 00400 /** 00401 * return true if this node is a leaf. 00402 */ 00403 inline bool isLeaf() const { 00404 return (!points.empty()); 00405 } 00406 00407 /** 00408 * copy method 00409 */ 00410 node& copy(const node& other) { 00411 00412 // copy the data 00413 splitDim = other.splitDim; 00414 partition = other.partition; 00415 00416 // remove the current elements 00417 clearPoints(); 00418 00419 // deep copy the other elements 00420 typename points_type::const_iterator cit,ceit; 00421 for (cit=other.points.begin(),ceit=other.points.end(); 00422 cit!=ceit; 00423 ++cit) { 00424 points.push_back((*cit)->clone()); 00425 } 00426 00427 // remove old data 00428 if (notNull(left)) { 00429 delete left; 00430 left = 0; 00431 } 00432 00433 if (notNull(right)) { 00434 delete right; 00435 right = 0; 00436 } 00437 00438 // copy children if necessary. 00439 if (notNull(other.left)) { 00440 left = other.left->clone(); 00441 } 00442 00443 if (notNull(other.right)) { 00444 right = other.right->clone(); 00445 } 00446 00447 return *this; 00448 } 00449 00450 /** 00451 * copy method 00452 */ 00453 inline node& operator=(const node& other) { 00454 return copy(other); 00455 } 00456 00457 00458 /** 00459 * clone method 00460 */ 00461 node* clone() const { 00462 return new node(*this); 00463 } 00464 00465 # ifndef _LTI_MSC_6 00466 /** 00467 * read the parameters from the given ioHandler 00468 * @param handler the ioHandler to be used 00469 * @param complete if true (the default) the enclosing begin/end will 00470 * be also read, otherwise only the data block will be read. 00471 * @return true if write was successful 00472 */ 00473 virtual bool read(ioHandler &handler, const bool complete=true) 00474 # else 00475 bool readMS(ioHandler& handler,const bool complete=true) 00476 # endif 00477 { 00478 bool b=true; 00479 00480 delete left; 00481 left = 0; 00482 delete right; 00483 right = 0; 00484 00485 if (complete) { 00486 b = handler.readBegin(); 00487 } 00488 00489 b = b && lti::read(handler,"splitDim",splitDim); 00490 b = b && lti::read(handler,"partition",partition); 00491 00492 // read the points with their corresponding data 00493 clearPoints(); 00494 00495 // ----------------------------------------------------- 00496 00497 b = b && handler.readBegin(); // points field (1) 00498 b = b && handler.trySymbol("points"); // 00499 b = b && handler.readKeyValueSeparator(); // 00500 b = b && handler.readBegin(); // vector data (2) 00501 00502 // ----------------------------- 00503 int i; 00504 element* tmpElem; 00505 int pointsSize; 00506 b = b && handler.read("size",pointsSize); 00507 00508 points.resize(pointsSize); 00509 00510 b = b && handler.readBegin(); // data block of vector (3) 00511 if (pointsSize > 0) { 00512 for (i=0;i<pointsSize-1;++i) { 00513 tmpElem = new element; 00514 b = b && tmpElem->read(handler); 00515 points[i] = tmpElem; 00516 tmpElem=0; 00517 b = b && handler.readDataSeparator(); 00518 } 00519 tmpElem = new element; 00520 b = b && tmpElem->read(handler); 00521 points[i] = tmpElem; 00522 tmpElem=0; 00523 } 00524 b = b && handler.readEnd(); // data block of vector (2) 00525 00526 // ----------------------------- 00527 00528 b = b && handler.readEnd(); // vector data (1) 00529 b = b && handler.readEnd(); // points field (0) 00530 00531 // ----------------------------------------------------- 00532 00533 00534 // load the children 00535 00536 00537 // left node first 00538 b = b && handler.readBegin(); // left scope (1) 00539 b = b && handler.trySymbol("left"); // 00540 b = b && handler.readKeyValueSeparator(); // 00541 b = b && handler.readBegin(); // left data (2) 00542 // 00543 if (!handler.tryEnd()) { // 00544 left = new node; // 00545 // recursively read the children // 00546 b = b && left->read(handler,false); // 00547 b = b && handler.readEnd(); // left data (1) 00548 } // 00549 // 00550 b = b && handler.readEnd(); // left scope (0) 00551 00552 // right node next 00553 b = b && handler.readBegin(); // right scope (1) 00554 b = b && handler.trySymbol("right"); // 00555 b = b && handler.readKeyValueSeparator(); // 00556 b = b && handler.readBegin(); // right data (2) 00557 // 00558 if (!handler.tryEnd()) { // 00559 right = new node(); // 00560 // recursively read the children // 00561 b = b && right->read(handler,false); // 00562 b = b && handler.readEnd(); // right data (1) 00563 } // 00564 // 00565 b = b && handler.readEnd(); // right scope (0) 00566 00567 if (complete) { 00568 b = b && handler.readEnd(); 00569 } 00570 00571 return b; 00572 } 00573 00574 # ifdef _LTI_MSC_6 00575 /** 00576 * read the parameters from the given ioHandler 00577 * @param handler the ioHandler to be used 00578 * @param complete if true (the default) the enclosing begin/end will 00579 * be also read, otherwise only the data block will be read. 00580 * @return true if write was successful 00581 */ 00582 virtual bool read(ioHandler& handler,const bool complete=true) { 00583 // ...we need this workaround to cope with another really awful MSVC 00584 // bug. 00585 return readMS(handler,complete); 00586 } 00587 # endif 00588 00589 # ifndef _LTI_MSC_6 00590 /** 00591 * write the parameters in the given ioHandler 00592 * @param handler the ioHandler to be used 00593 * @param complete if true (the default) the enclosing begin/end will 00594 * be also written, otherwise only the data block will be 00595 * written. 00596 * @return true if write was successful 00597 */ 00598 virtual bool write(ioHandler& handler,const bool complete=true) const 00599 # else 00600 bool writeMS(ioHandler& handler,const bool complete=true) const 00601 # endif 00602 { 00603 bool b=true; 00604 00605 if (complete) { 00606 b = handler.writeBegin(); 00607 } 00608 00609 b = b && lti::write(handler,"splitDim",splitDim); 00610 b = b && lti::write(handler,"partition",partition); 00611 00612 // write from the points only the index 00613 // ------------------------------------------------------- 00614 00615 b = b && handler.writeBegin(); // points field 00616 b = b && handler.writeSymbol("points"); // 00617 b = b && handler.writeKeyValueSeparator(); // 00618 // 00619 b = b && handler.writeBegin(); // vector data 00620 00621 // ------------------------------------------ 00622 b = b && handler.write("size",static_cast<unsigned int>(points.size())); 00623 b = b && handler.writeBegin(); // data block of vector 00624 if (!points.empty()) { // | 00625 typename points_type::const_iterator it; // | 00626 it=points.begin(); // | 00627 b = b && (*it)->write(handler); // | 00628 for (++it;it!=points.end();++it) { // | 00629 b = b && handler.writeDataSeparator(); // | 00630 b = b && (*it)->write(handler); // | 00631 } // | 00632 } // | 00633 b = b && handler.writeEnd(); // data block of vector 00634 00635 // ------------------------------------------- 00636 00637 b = b && handler.writeEnd(); // vector data 00638 b = b && handler.writeEnd(); // points field 00639 00640 // ------------------------------------------------------- 00641 00642 b = b && handler.writeEOL(); 00643 00644 // Save the children 00645 00646 // left node first 00647 b = b && handler.writeBegin(); // left child (1) 00648 b = b && handler.writeSymbol("left"); // 00649 b = b && handler.writeKeyValueSeparator(); // 00650 b = b && handler.writeBegin(); // node block (2) 00651 if (notNull(left)) { // 00652 // recursivelly save the children // 00653 b = b && left->write(handler,false); // 00654 } // 00655 b = b && handler.writeEnd(); // node block (1) 00656 b = b && handler.writeEnd(); // left child (0) 00657 b = b && handler.writeEOL(); 00658 00659 // right node next 00660 b = b && handler.writeBegin(); // right child (1) 00661 b = b && handler.writeSymbol("right"); // 00662 b = b && handler.writeKeyValueSeparator(); // 00663 b = b && handler.writeBegin(); // node block (2) 00664 if (notNull(right)) { // 00665 // recursivelly save the children // 00666 b = b && right->write(handler,false); // 00667 } // 00668 b = b && handler.writeEnd(); // node block (1) 00669 b = b && handler.writeEnd(); // right child (0) 00670 00671 b = b && handler.writeEOL(); 00672 00673 if (complete) { 00674 b=b && handler.writeEnd(); 00675 } 00676 00677 return b; 00678 } 00679 00680 # ifdef _LTI_MSC_6 00681 /** 00682 * write the parameters to the given ioHandler 00683 * @param handler the ioHandler to be used 00684 * @param complete if true (the default) the enclosing begin/end will 00685 * be also writen, otherwise only the data block will be writen. 00686 * @return true if write was successful 00687 */ 00688 virtual bool write(ioHandler& handler,const bool complete=true) { 00689 // ...we need this workaround to cope with another really awful MSVC 00690 // bug. 00691 return writeMS(handler,complete); 00692 } 00693 # endif 00694 00695 00696 protected: 00697 /** 00698 * deep clear points 00699 */ 00700 void clearPoints() { 00701 // delete the elements 00702 typename points_type::iterator it,eit; 00703 for (it=points.begin(),eit=points.end();it!=eit;++it) { 00704 delete (*it); 00705 (*it)=0; 00706 } 00707 00708 points.clear(); 00709 } 00710 00711 /** 00712 * split the data stored at this node considering the axis with 00713 * the highest variance. 00714 * 00715 * @param maxCount maximum bucket size (how many elements are allowed 00716 * to be in a leaf node) 00717 * @param levels number of levels required until now for this tree. 00718 * @param leaves at the end this variable (which should be initialized 00719 * with zero externally) contains the number of leaves in the tree 00720 */ 00721 void subdivide(const int maxCount,int& levels,int& leaves) { 00722 const int n = static_cast<int>(points.size()); 00723 if (n <= maxCount) { 00724 // we don't need to split. This now is small enough 00725 leaves++; 00726 levels=1; 00727 return; 00728 } 00729 00730 // remove the old children and create empty ones. 00731 if (notNull(left)) { 00732 delete left; 00733 left = 0; 00734 } 00735 left = new node(); 00736 00737 if (notNull(right)) { 00738 delete right; 00739 right = 0; 00740 } 00741 right = new node(); 00742 00743 // split dimension at this node 00744 // remember split dimension (splitDim is a class attribute) 00745 const int dim = splitDim = getDimWithHighestVariance(); 00746 00747 // get the median of the splitDim as the value to split the space 00748 // remember split position 00749 const value_type medVal = partition = getMedianVal(dim); 00750 00751 const int lc = n/2; 00752 int npleft(0),npeq(0); // number of points in the left side 00753 typename points_type::iterator it=points.begin(); 00754 std::list<element*> stack; 00755 // split the points into the two children. 00756 while (it!=points.end()) { 00757 if (((*it)->point[dim] < medVal)) { 00758 left->add(*it); 00759 npleft++; 00760 } else if (((*it)->point[dim] > medVal)) { 00761 right->add(*it); 00762 } else { 00763 npeq++; 00764 stack.push_back(*it); 00765 } 00766 ++it; 00767 } 00768 00769 // the remaining median-equal values need to be split so 00770 // that both children have the same number of points 00771 while (npleft<lc) { 00772 left->add(stack.front()); 00773 stack.pop_front(); 00774 npleft++; 00775 } 00776 if (!stack.empty()) { 00777 right->add(stack); 00778 } 00779 00780 points.clear(); 00781 00782 // recursively split the data into both child nodes 00783 int llev,rlev; 00784 left->subdivide(maxCount,llev,leaves); 00785 right->subdivide(maxCount,rlev,leaves); 00786 levels = 1+max(llev,rlev); 00787 } 00788 00789 /** 00790 * get the dimension of the data with the highest variance. 00791 * We assume the whole data set to be considered is located 00792 * at the points vector. 00793 */ 00794 int getDimWithHighestVariance() const { 00795 assert(!points.empty() && notNull(points.front())); 00796 00797 // get the used dimension 00798 const int dim = points.front()->size(); 00799 00800 assert(dim>0); 00801 00802 // total number of points 00803 const int n = static_cast<int>(points.size()); 00804 00805 // type for squares 00806 typedef typename typeInfo<value_type>::square_accumulation_type 00807 sqrType; 00808 00809 // sum of all elements 00810 vector<sqrType> sum(dim,sqrType(0)); 00811 // variance 00812 vector<sqrType> var(dim,sqrType(0)); 00813 00814 typename points_type::const_iterator it; 00815 int mxi,j; 00816 sqrType tmp,mx; 00817 00818 // compute some temporary variables with the sum of elements and 00819 // the sum of square of elements 00820 for (it=points.begin();it!=points.end();++it) { 00821 // we cannot just add the points, because we don't really know 00822 // the type. So let's add the elements separately 00823 for (j=0;j<dim;++j) { 00824 tmp=(*(*it))[j]; 00825 sum[j]+=tmp; 00826 var[j]+=(tmp*tmp); 00827 } 00828 } 00829 00830 // compute not the variance, but m x variance, to save some time, 00831 // and get the dimension where the maximal one is found 00832 mxi=0; 00833 tmp=sum[mxi]; 00834 mx = var[mxi]-(tmp*tmp/n); // the first "variance" for dimension 0 00835 for (j=1;j<dim;++j) { // the rest of "variances" 00836 tmp = sum[j]; 00837 tmp = var[j]-(tmp*tmp/n); 00838 if (tmp>mx) { // if greater 00839 mxi=j; // remember it. 00840 mx=tmp; 00841 } 00842 } 00843 00844 return mxi; 00845 } 00846 00847 /** 00848 * get the median value at the given search dimension 00849 * 00850 * @param searchDim search dimension 00851 * @return the median of the given dimension 00852 */ 00853 value_type getMedianVal(const int searchDim) const { 00854 int i; 00855 const int n = static_cast<int>(points.size()); 00856 00857 vector<value_type> val(false,n); // don't initialize 00858 00859 // get elements in the split dimension 00860 typename points_type::const_iterator it; 00861 for (i=0,it=points.begin(); it!=points.end();++it,++i) { 00862 val[i] = (*(*it))[searchDim]; 00863 } 00864 00865 // the quickMedian functor can be created just once and const, 00866 // because we don't need to change the parameters and the required 00867 // apply is const. Even multi-thread applications would use different 00868 // stack-frames, and should work. (This should be tested!!!) 00869 static const quickMedian<value_type> qmed; 00870 00871 // get the median of desired dimension 00872 return qmed.apply(val); 00873 } 00874 00875 /** 00876 * search for exactly the given key in the list of elements. If 00877 * found, return true, otherwise return false and leave the 00878 * element instance untouched. 00879 * 00880 * For floating types this method usually returns false, because 00881 * the exact match of the key is very unprobable. This method is 00882 * therefore used mostly for integer value_types 00883 */ 00884 bool getPoint(const T& key,element& elem) const { 00885 if (!points.empty()) { 00886 typename points_type::const_iterator it,eit; 00887 for (it=points.begin(),eit=points.end();it!=eit;++it) { 00888 if ((*it)->point == key) { 00889 elem=*(*it); 00890 return true; 00891 } 00892 } 00893 } 00894 return false; 00895 } 00896 00897 /** 00898 * search for exactly the given key in the list of elements. If 00899 * found, return true, otherwise return false and leave the 00900 * element instance untouched. 00901 * 00902 * For floating types this method usually returns false, because 00903 * the exact match of the key is very unprobable. This method is 00904 * therefore used mostly for integer value_types 00905 */ 00906 bool getPoint(const T& key,std::list<element>& elems) const { 00907 bool found=false; 00908 if (!points.empty()) { 00909 typename points_type::const_iterator it,eit; 00910 for (it=points.begin(),eit=points.end();it!=eit;++it) { 00911 if ((*it)->point == key) { 00912 elems.push_back(*(*it)); 00913 found=true; 00914 } 00915 } 00916 } 00917 return found; 00918 } 00919 00920 /** 00921 * insert all elements in the given list into the internal 00922 * elements vector. 00923 * 00924 * The pointed elements will be inserted as they are (without copying), 00925 * and the memory managment is controled by this node itself. 00926 * 00927 * The dimensionality of each element MUST be equal than the one 00928 * of the first added element. 00929 */ 00930 void add(std::list<element*>& pts) { 00931 typename std::list<element*>::iterator it=pts.begin(); 00932 while (it!=pts.end()) { 00933 points.push_back(*it); 00934 ++it; 00935 } 00936 } 00937 00938 }; // end of node class 00939 00940 // ---------------------------------------------------------------------- 00941 // kdTree Definition 00942 // ---------------------------------------------------------------------- 00943 00944 public: 00945 00946 /** 00947 * Return type of the size() member 00948 */ 00949 typedef int size_type; 00950 00951 /** 00952 * Default constructor 00953 */ 00954 kdTree(); 00955 00956 /** 00957 * Copy constructor 00958 * @param other the object to be copied 00959 */ 00960 kdTree(const kdTree& other); 00961 00962 /** 00963 * Destructor 00964 */ 00965 virtual ~kdTree(); 00966 00967 /** 00968 * Returns the name of this type ("kdTree") 00969 */ 00970 virtual const char* getTypeName() const; 00971 00972 /** 00973 * Copy data of "other" functor. 00974 * @param other the functor to be copied 00975 * @return a reference to this functor object 00976 */ 00977 kdTree& copy(const kdTree& other); 00978 00979 /** 00980 * Alias for copy member 00981 * @param other the functor to be copied 00982 * @return a reference to this functor object 00983 */ 00984 kdTree& operator=(const kdTree& other); 00985 00986 /** 00987 * Returns a pointer to a clone of this functor. 00988 */ 00989 virtual mathObject* clone() const; 00990 00991 /** 00992 * Clear the tree. 00993 * 00994 * All elements belonging to the tree will be removed. Also all elements 00995 * added until now will be deleted. 00996 */ 00997 virtual void clear(); 00998 00999 /** 01000 * Check if the tree is empty 01001 */ 01002 virtual bool empty() const; 01003 01004 /** 01005 * Get the number of elements added to the tree with the function add(). 01006 * 01007 * Note that these points are not really \b in the tree until you 01008 * call build() or rebuild(). After calling either the added 01009 * points are flushed and the return value of this function is 01010 * zero. 01011 * 01012 * @see size() 01013 */ 01014 virtual int getNumberOfAddedElements() const; 01015 01016 /** 01017 * Get the number of elements in the built tree. 01018 * 01019 * Note that this value can differ substantially from the value 01020 * returned by getNumberOfAddedElements(). The latter don't belong 01021 * to the tree yet. Thus, adding elements, then calling build and 01022 * then adding more elements, generally results in two different 01023 * values. 01024 * 01025 * The return value is zero if no tree has been built yet. 01026 * 01027 * @see getNumberOfAddedElements() 01028 */ 01029 virtual int size() const; 01030 01031 /** 01032 * Get the number of leaves in the tree. 01033 * 01034 * Return zero if the tree hasn't been build yet. 01035 */ 01036 virtual int getNumberOfLeaves() const; 01037 01038 /** 01039 * Get the number of levels of the tree. 01040 * 01041 * Return zero if the tree hasn't been build yet. 01042 */ 01043 virtual int getLevels() const; 01044 01045 /** 01046 * Get pointer to root node 01047 * 01048 * Return a null pointer if the tree hasn't been build yet. 01049 */ 01050 virtual node* getRoot(); 01051 01052 /** 01053 * @name Search methods 01054 */ 01055 //@{ 01056 01057 /** 01058 * Search for an element with exactly the given position in the 01059 * hyperspace. 01060 * 01061 * This is the classical search in a kd-tree, that assumes that 01062 * a leaf node contains exactly the given point. 01063 * If found, the contents of the element will by copied in the 01064 * elem attributes and true will be returned. Otherwise false will 01065 * be returned. 01066 * 01067 * If the key is present more than once, only the "first" one will 01068 * be returned, which is the first one the list of points at the 01069 * left-most node containing it. 01070 * 01071 * @param key point in the n-dimensional space you are looking for. 01072 * @param elem the contents of the found point will be left here. 01073 * @return true if key was found, otherwise false. 01074 */ 01075 bool searchExactly(const T& key,element& elem) const; 01076 01077 /** 01078 * Search for all elements with exactly the given position in the 01079 * hyperspace. 01080 * 01081 * This is the classical search in a kd-tree, that assumes that 01082 * a leaf node contains exactly the given point. 01083 * If found, the contents of the element will by copied in the 01084 * elem attributes and true will be returned. Otherwise false will 01085 * be returned. 01086 * 01087 * @param key point in the n-dimensional space you are looking for. 01088 * @param elems a list containing copies to all found elements with the 01089 * given keys 01090 * @return true if at least one key was found, otherwise false. 01091 */ 01092 bool searchExactly(const T& key,std::list<element>& elems) const; 01093 01094 /** 01095 * Search for the nearest element in the tree to the given key point. 01096 * 01097 * If found, a pointer to the element will be written in the 01098 * \a elem parameters and true will be returned. Otherwise false will 01099 * be returned and the pointer will be set to zero. 01100 * 01101 * The pointer is not const to allow you to change the \a data of the 01102 * element, but if you also change the \a point, the tree will be corrupted 01103 * and will not work appropriately. There is no way to change the search 01104 * keys dynamically in a kd-tree without a heavy load of computation. If 01105 * that is what you are looking for, you should consider rebuilding the 01106 * entire tree (expensive!). 01107 * 01108 * @param key point in the n-dimensional space you are looking for. 01109 * @param elem pointer to the contents of the point found, or zero if 01110 * not found. You should \b never delete the pointed data. 01111 * @return true if key was found, otherwise false (i.e. tree empty). 01112 * 01113 * \warning This method is not thread safe. In order to provide a 01114 * fast search mechanism for the nearest neighbor some 01115 * temporary variables are stored in the tree class itself, 01116 * and therefore it is not possible to search the 01117 * nearest neighbor in the same tree from different 01118 * threads. 01119 */ 01120 bool searchNearest(const T& key,element*& elem) const; 01121 01122 /** 01123 * Search for the nearest element in the tree to the given key point. 01124 * 01125 * If found, a pointer to the element will be written in the 01126 * \a elem parameters and true will be returned. Otherwise false will 01127 * be returned and the pointer will be set to zero. 01128 * 01129 * The pointer is not const to allow you to change the \a data of the 01130 * element, but if you also change the \a point the tree will be corrupted 01131 * and will not work appropriately. There is no way to change the search 01132 * keys dynamically in a kd-tree without a heavy load of computation. If 01133 * that is what you are looking for, you should consider rebuilding the 01134 * entire tree (expensive!). 01135 * 01136 * @param key point in the n-dimensional space you are looking for. 01137 * @param elem pointer to the contents of the point found, or zero if 01138 * not found. You should \b never delete the pointed data. 01139 * @param dist distance between the points. The type of distance is 01140 * determined by the used distanctor (the third template 01141 * type of the tree, which return per default the square 01142 * of the euclidean distance). 01143 * @return true if key was found, otherwise false (i.e. tree empty). 01144 * 01145 * \warning This method is not thread safe. In order to provide a 01146 * fast search mechanism for the nearest neighbor some 01147 * temporary variables are stored in the tree class itself, 01148 * and therefore it is not possible to search the 01149 * nearest neighbor in the same tree from different 01150 * threads. 01151 */ 01152 bool searchNearest(const T& key,element*& elem,acc_type& dist) const; 01153 01154 /** 01155 * Search for the nearest element in the tree to the given key point. 01156 * 01157 * If found, the contents of the element will by copied in the 01158 * elem parameters and true will be returned. Otherwise false will 01159 * be returned. 01160 * @param key point in the n-dimensional space you are looking for. 01161 * @param elem the contents of the found point will be left here. 01162 * @return true if key was found, otherwise false (i.e. tree empty). 01163 * 01164 * \warning This method is not thread safe. In order to provide a 01165 * fast search mechanism for the nearest neighbor some 01166 * temporary variables are stored in the tree class itself, 01167 * and therefore it is not possible to search the 01168 * nearest neighbor in the same tree from different 01169 * threads. 01170 */ 01171 bool searchNearest(const T& key,element& elem) const; 01172 01173 /** 01174 * Search for the nearest element in the tree to the given key point. 01175 * 01176 * If found, the contents of the element will by copied in the 01177 * elem parameters and true will be returned. Otherwise false will 01178 * be returned. 01179 * @param key point in the n-dimensional space you are looking for. 01180 * @param elem the contents of the found point will be left here. 01181 * @param dist distance between the points. The type of distance is 01182 * determined by the used distanctor (the third template 01183 * type of the tree, which return per default the square 01184 * of the euclidean distance). 01185 * @return true if key was found, otherwise false (i.e. tree empty). 01186 * 01187 * \warning This method is not thread safe. In order to provide a 01188 * fast search mechanism for the nearest neighbor some 01189 * temporary variables are stored in the tree class itself, 01190 * and therefore it is not possible to search the 01191 * nearest neighbor in the same tree from different 01192 * threads. 01193 */ 01194 bool searchNearest(const T& key,element& elem,acc_type& dist) const; 01195 01196 /** 01197 * Search for the nearest element in the tree to the given key point. 01198 * 01199 * If found, the contents of the element will by copied in the 01200 * elem parameters and true will be returned. Otherwise false will 01201 * be returned. 01202 * @param key point in the n-dimensional space you are looking for. 01203 * @param data the contents of the found nearest point will be left here. 01204 * @return true if key was found, otherwise false (i.e. tree empty). 01205 * 01206 * \warning This method is not thread safe. In order to provide a 01207 * fast search mechanism for the nearest neighbor some 01208 * temporary variables are stored in the tree class itself, 01209 * and therefore it is not possible to search the 01210 * nearest neighbor in the same tree from different 01211 * threads. 01212 */ 01213 bool searchNearest(const T& key,D& data) const; 01214 01215 /** 01216 * Search for the nearest k elements in the tree to the given key point. 01217 * 01218 * If you are looking just for the nearest elements (i.e. k=1) use the 01219 * searchNearest(const T&,D&) or searchNearest(const T&,element&) methods 01220 * instead. They are optimized for this case and are much faster. 01221 * 01222 * @param k number of elements you are looking for 01223 * @param key the point in the n-dimensional space you are looking for 01224 * @param neighbors contains the pointers to the found elements. You 01225 * should NEVER delete these elements. 01226 * @return true if k elements were found, or false, if the tree contains 01227 * less than k elements 01228 */ 01229 bool searchNearest(const int k, 01230 const T& key, 01231 std::list<element*>& neighbors) const; 01232 01233 /** 01234 * Search for the nearest k elements in the tree to the given key point. 01235 * 01236 * If you are looking just for the nearest elements (i.e. k=1) use the 01237 * searchNearest(const T&,D&) or searchNearest(const T&,element&) methods 01238 * instead. They are optimized for this case and are much faster. 01239 * 01240 * @param k number of elements you are looking for. 01241 * @param key the point in the n-dimensional space you are looking for. 01242 * @param neighbors is a multimap containing as access key the 01243 * square of the euclidean distance or the result of 01244 * the given distantor between the 01245 * corresponding element* and the search key. 01246 * Remember that if you iterate the multimap, the 01247 * elements will be sorted in increasing order of 01248 * the distance (i.e. the nearest element first). 01249 * You should NEVER delete the pointed elements. 01250 * @return true if k elements were found, or false, if the tree contains 01251 * less than k elements 01252 */ 01253 bool searchNearest(const int k, 01254 const T& key, 01255 std::multimap<acc_type,element*>& neighbors) const; 01256 01257 /** 01258 * Search for elements in an hyper-spheric neighbourhood of a given key 01259 * point, i.e. search for all elements that reside within a hypersphere 01260 * with the given radius centered at the given key. Note that the 01261 * hypersphere is always defined using an Euclidean distance, no matter 01262 * of the specified distanctor policy. 01263 * 01264 * The returned list of elements is not sorted. If you need it sorted 01265 * you should use the searchWithin() method with the multimap result. 01266 * 01267 * @param key point at which the hypersphere must be centered 01268 * @param dist allowed distance from the key point. Note that this 01269 * represents exaclty the radius of the hypersphere and not 01270 * the square of it. 01271 * @param elems list of elements found. You should NEVER delete the 01272 * pointed elements. 01273 */ 01274 bool searchWithin(const T& key, 01275 const acc_type& dist, 01276 std::list<element*>& elems) const; 01277 01278 01279 /** 01280 * Search for elements in an hyper-spheric neighbourhood of a given key 01281 * point, i.e. search for all elements that reside within a hypersphere 01282 * with the given radius centered at the given key. Note that the 01283 * hypersphere is always defined using an Euclidean distance, no matter 01284 * of the specified distanctor policy. 01285 * 01286 * The returned multimap is always sorted in ascending order of 01287 * the distances (this is a property of all std::multimaps). If you 01288 * want to save some time and don't need the sorted data consider using 01289 * the other searchWithin() method, which stores the result in a std::list. 01290 * 01291 * @param key point at which the hypersphere must be centered 01292 * @param dist allowed distance from the key point. Note that this 01293 * represents exaclty the radius of the hypersphere and not 01294 * the square of it. 01295 * @param neighbors multimap of elements found. You should NEVER delete 01296 * the pointed elements. Note that the keys used to sort 01297 * the multimap are the square of the distances to the 01298 * given key point. This is done this way to save the 01299 * time of applying the "sqrt()" function, which takes some 01300 * time. 01301 */ 01302 bool searchWithin(const T& key, 01303 const acc_type& dist, 01304 std::multimap<acc_type,element*>& neighbors) const; 01305 01306 01307 /** 01308 * Search the best-bin-first algorithm of Beis and Lowe. 01309 * 01310 * Use this method only if the dimensionality of your data is high 01311 * enough. The time savings take effect only if the kd-tree is big 01312 * enough and the dimensionality of the data too. Make a few tests 01313 * with your data in order to detect if this approximation is good enough 01314 * and fast enough for you. Otherwise use the traditional search with 01315 * searchNearest() 01316 * 01317 * @param k number of elements you are looking for 01318 * @param key the point in the n-dimensional space you are looking for 01319 * @param neighbors contains the pointers to the found elements. You 01320 * should NEVER delete these elements. 01321 * @param emax is the maximal number of visits allowed for leaf nodes. 01322 * (in the original paper is called \f$E_{max}\f$). Of course 01323 * there can be more visits than emax if it is necessary to 01324 * find at least k neighbors. 01325 * @return true if k elements were found, or false, if the tree contains 01326 * less than k elements 01327 */ 01328 bool searchBestBinFirst(const int k, 01329 const T& key, 01330 const int emax, 01331 std::list<element*>& neighbors) const; 01332 01333 01334 /** 01335 * Search the best-bin-first algorithm of Beis and Lowe. 01336 * 01337 * Use this method only if the dimensionality of your data is high 01338 * enough. The time savings take effect only if the kd-tree is big 01339 * enough and the dimensionality of the data too. Make a few tests 01340 * with your data in order to detect if this approximation is good enough 01341 * and fast enough for you. Otherwise use the traditional search with 01342 * searchNearest() 01343 * 01344 * @param k number of elements you are looking for 01345 * @param key the point in the n-dimensional space you are looking for 01346 * @param neighbors contains the pointers to the found elements. You 01347 * should NEVER delete these elements. 01348 * @param emax is the maximal number of visits allowed for leaf nodes. 01349 * (in the original paper is called \f$E_{max}\f$). 01350 * @return true if k elements were found, or false, if the tree contains 01351 * less than k elements 01352 */ 01353 bool searchBestBinFirst(const int k, 01354 const T& key, 01355 const int emax, 01356 std::multimap<acc_type,element*>& neighbors) const; 01357 01358 /** 01359 * Search for all points lying within the given hyperbox. 01360 * @param boxMin point representing the lowest values at each coordinate 01361 * building the lower limits of the bounding box. 01362 * @param boxMax point representing the highest values at each coordinate 01363 * building the upper limits of the bounding box. 01364 * @param neighbors list of pointer to the elements found until now. 01365 * @return true if any element was found. 01366 */ 01367 bool searchRange(const T& boxMin, 01368 const T& boxMax, 01369 std::list<element*>& neighbors) const; 01370 01371 //@} 01372 01373 /** 01374 * Consider the given element to be inserted in the tree after calling 01375 * the build(const int) method. 01376 * 01377 * The dimensionality of each point MUST be equal than the one 01378 * first added, otherwise an assertion will be thrown when building the 01379 * tree. 01380 * 01381 * @param point n-dimensional point representint the position of 01382 * this element * in the n-dimensional space 01383 * @param data data contained in this element. 01384 */ 01385 void add(const T& point,const D& data); 01386 01387 /** 01388 * Build the kd-Tree for all nodes added with the add() method, using 01389 * the given bucket size as the maximum number of elements a node 01390 * can contain. The previous tree will be destroyed before the new one 01391 * is constructed. 01392 * the 01393 * @param bucketSize maximum size of elements a node can contain (default 01394 * value is 1). 01395 * @return true if successful, false otherwise. 01396 */ 01397 bool build(const int bucketSize = 1); 01398 01399 /** 01400 * Rebuild the kd-Tree for all elements added with the add() 01401 * method and those already present in the tree, using the given 01402 * bucket size as the maximum number of elements a node can 01403 * contain. Although the previous tree will be destroyed before 01404 * the new one is constructed it will contain all elements 01405 * contained in the old one. 01406 * 01407 * Rebuilding the tree is quite slow since the elements have to be 01408 * extracted and copied from the existing tree first. This is 01409 * necessary since a kd-tree needs to know the complete set of 01410 * data for building. 01411 * 01412 * @param bucketSize maximum size of elements a node can contain (default 01413 * value is 1). 01414 * @return true if successful, false otherwise. 01415 */ 01416 bool rebuild(const int bucketSize = 1); 01417 01418 /** 01419 * Read the parameters from the given ioHandler 01420 * @param handler the ioHandler to be used 01421 * @param complete if true (the default) the enclosing begin/end will 01422 * be also read, otherwise only the data block will be read. 01423 * @return true if write was successful 01424 */ 01425 virtual bool read(ioHandler &handler, const bool complete=true); 01426 01427 /** 01428 * Write the parameters in the given ioHandler 01429 * @param handler the ioHandler to be used 01430 * @param complete if true (the default) the enclosing begin/end will 01431 * be also written, otherwise only the data block will be 01432 * written. 01433 * @return true if write was successful 01434 */ 01435 virtual bool write(ioHandler& handler,const bool complete=true) const; 01436 01437 protected: 01438 /** 01439 * The root node 01440 */ 01441 node *root; 01442 01443 /** 01444 * Number of levels in the tree 01445 */ 01446 int levels; 01447 01448 /** 01449 * Number of elements contained in the tree 01450 */ 01451 int numElements; 01452 01453 /** 01454 * Number of elements added to the tree (see add()) 01455 */ 01456 int numAddedElements; 01457 01458 /** 01459 * Number of leaf nodes in the tree 01460 */ 01461 int numLeaves; 01462 01463 /** 01464 * Bounding Box 01465 * After creating the tree with build(), this matrix will be a 01466 * 2 x n matrix containing at the first row the minimum possible values 01467 * for the current type, and the second row the maximum values. 01468 */ 01469 matrix<value_type> totalBounds; 01470 01471 /** 01472 * Elements that will be contained in the tree. 01473 * All nodes contain pointers to the elements objects, that will be 01474 * transfered to the nodes in the tree with the build method. 01475 * Thereafter, this list will be empty. 01476 */ 01477 std::list<element*> points; 01478 01479 /** 01480 * Instance of the policy class used for computing the distances. 01481 */ 01482 U distantor; 01483 01484 private: 01485 /** 01486 * Read recursivelly the points contained in the node 01487 */ 01488 void getDataInSubtree(node* nodePtr,std::list<element*>& data) const; 01489 01490 /** 01491 * Search for an element with exactly the given position in the 01492 * hyperspace. 01493 * 01494 * This is the classical search in a kd-tree, that assumes that 01495 * a leaf node contains exactly the given point. 01496 * If found, the contents of the element will by copied in the 01497 * elem attributes and true will be returned. Otherwise false will 01498 * be returned, and the elem will be left unchanged. 01499 * 01500 * @param nptr node at which the search begins. 01501 * @param key point in the n-dimensional space you are looking for. 01502 * @param elem the contents of the found point will be left here. 01503 * @return true if key was found, otherwise false. 01504 */ 01505 bool searchExactly(const node* nptr,const T& key,element& elem) const; 01506 01507 /** 01508 * Search for all elements with exactly the given position in the 01509 * hyperspace. 01510 * 01511 * This is the classical search in a kd-tree, that assumes that 01512 * a leaf node contains exactly the given point. 01513 * If found, the contents of the element will by copied in the 01514 * elem attributes and true will be returned. Otherwise false will 01515 * be returned. 01516 * 01517 * @param nptr node at which the search begins. 01518 * @param key point in the n-dimensional space you are looking for. 01519 * @param elems a list containing copies to all found elements with the 01520 * given keys 01521 * @return true if at least one key was found, otherwise false. 01522 */ 01523 bool searchExactly(const node* nptr, 01524 const T& key,std::list<element>& elems) const; 01525 01526 01527 /** 01528 * Check if the hypersphere is within bounds. This is called in 01529 * the original paper "ball within bounds). 01530 * It only returns true if the distance at each component between 01531 * the key and the bounds is greater than the given distance. 01532 * (dist expects here the square of the distance, as it has been 01533 * stored in the multimap). 01534 */ 01535 inline bool 01536 checkHypersphereWithinBounds(const T& key, 01537 const matrix<value_type>& bounds, 01538 const acc_type& dist) const; 01539 01540 /** 01541 * Check if the bounds overlap the hypersphere. It was called in 01542 * the original paper "bounds overlap ball". 01543 */ 01544 inline bool 01545 checkBoundsOverlapHypersphere(const T& key, 01546 const matrix<value_type>& bounds, 01547 const acc_type& dist) const; 01548 01549 /** 01550 * Search for the nearest k elements in the tree to the given key point. 01551 * @param nptr pointer to the subtree where the elements need to be 01552 * searched for. 01553 * @param k number of elements you are looking for 01554 * @param key the point in the n-dimensional space you are looking for 01555 * @param bounds hyperbox where the search is taking place 01556 * @param neighbors contains the pointers to the found elements. You 01557 * should NEVER delete these elements. As multimap 01558 * it is always sorted after the "acc_typed" key, 01559 * which is in this case the square distance of the 01560 * element to the key. 01561 * @param neighSize the number of the the neighbors found. 01562 * @return true if k elements were found, or false, if the tree contains 01563 * less than k elements 01564 */ 01565 bool searchNearest(const node* nptr, 01566 const int k, 01567 const T& key, 01568 matrix<value_type>& bounds, 01569 std::multimap<acc_type,element*>& neighbors) const; 01570 01571 /** 01572 * Search for the nearest element in the tree to the given key point. 01573 * @param nptr pointer to the subtree where the elements need to be 01574 * searched for. 01575 * @param key the point in the n-dimensional space you are looking for 01576 * @param bounds hyperbox where the search is taking place 01577 * @param neighbors contains the pointers to the found elements. You 01578 * should NEVER delete these elements. As multimap 01579 * it is always sorted after the "acc_typed" key, 01580 * which is in this case the square distance of the 01581 * element to the key. 01582 * @param neighSize the number of the the neighbors found. 01583 * @return true if k elements were found, or false, if the tree contains 01584 * less than k elements 01585 * 01586 * \warning This method is not thread safe. In order to provide a 01587 * fast search mechanism for the nearest neighbor some 01588 * temporary variables are stored in the tree class itself, 01589 * and therefore it is not possible to search the 01590 * nearest neighbor in the same tree from different 01591 * threads. 01592 */ 01593 bool searchNearest(const node* nptr, 01594 const T& key, 01595 std::pair<acc_type,element*>& neighbors) const; 01596 01597 /** 01598 * Search for the nearest element in the tree to the given key point. 01599 * @param nptr pointer to the node root of the subtree to be evaluated 01600 * @param key the point in the n-dimensional space you are looking for 01601 * @param dist distance radius to search point in 01602 * @param bounds hyperbox where the search is taking place 01603 * @param elems contains pointers to the found elements 01604 * @return true if k elements were found, or false, if the tree contains 01605 * less than k elements 01606 */ 01607 bool searchWithin(const node* nptr, 01608 const T& key, 01609 const acc_type& dist, 01610 matrix<value_type>& bounds, 01611 std::list<element*>& elems) const; 01612 01613 /** 01614 * Search for the nearest element in the tree to the given key point. 01615 * @param nptr pointer to the node root of the subtree to be evaluated 01616 * @param key the point in the n-dimensional space you are looking for 01617 * @param dist distance radius to search point in 01618 * @param bounds hyperbox where the search is taking place 01619 * @param elems contains pointers to the found elements 01620 * @return true if k elements were found, or false, if the tree contains 01621 * less than k elements 01622 */ 01623 bool searchWithin(const node* nptr, 01624 const T& key, 01625 const acc_type& dist, 01626 matrix<value_type>& bounds, 01627 std::multimap<acc_type,element*>& neighbors) const; 01628 01629 /** 01630 * Search for all points lying within the given hyperbox. 01631 * @param nptr pointer to the node root of the subtree to be evaluated 01632 * @param boxMin point representing the lowest values at each coordinate 01633 * building the lower limits of the bounding box. 01634 * @param boxMax point representing the highest values at each coordinate 01635 * building the upper limits of the bounding box. 01636 * @param neighbors list of pointer to the elements found until now. 01637 * @return true if completed. 01638 */ 01639 bool searchRange(const node* nptr, 01640 const T& boxMin, 01641 const T& boxMax, 01642 std::list<element*>& neighbors) const; 01643 01644 /** 01645 * Check if a point lies withing the given bounding box. 01646 * @return true if point lies within the box, false otherwise. 01647 */ 01648 inline bool withinBox(const T& boxMin, 01649 const T& boxMax, 01650 const T& key) const; 01651 01652 /** 01653 * Check if a box lies withing the given bounding box. 01654 * @return true if box lies within the bbox, false otherwise. 01655 */ 01656 inline bool withinBox(const matrix<value_type>& bbox, 01657 const T& boxMin, 01658 const T& boxMax) const; 01659 01660 /** 01661 * Get the square of the L2 distance of the given point to the 01662 * node's hyperbox. 01663 * 01664 * If the point lies withing the hyperbox, the distance will be zero. 01665 * 01666 * @param na hyperbox representing the node's covered subspace. 01667 * The first row represents the minimum and the second the 01668 * maximum values. It must be na.columns()==indexPoint.size() 01669 * @param indexPoint the point to be compared with the hyperbox. 01670 */ 01671 inline acc_type minDistancePointToBox(const T& indexPoint, 01672 const matrix<value_type>& na) const; 01673 01674 /** 01675 * Search the best-bin-first algorithm of Beis and Lowe. 01676 * 01677 * Use this method only if the dimensionality of your data is high 01678 * enough. The time savings take effect only if the kd-tree is big 01679 * enough and the dimensionality of the data too. Make a few tests 01680 * with your data in order to detect if this approximation is good enough 01681 * and fast enough for you. Otherwise use the traditional search with 01682 * searchNearest() 01683 * 01684 * @param node pointer to the subtree where the elements need to be 01685 * searched for. 01686 * @param k number of elements you are looking for 01687 * @param key the point in the n-dimensional space you are looking for 01688 * @param neighbors contains the pointers to the found elements. You 01689 * should NEVER delete these elements. 01690 * @param emax maximum number of leaves to be visited. 01691 * @return true if k elements were found, or false, if the tree contains 01692 * less than k elements 01693 */ 01694 bool searchBestBinFirst(const node* root, 01695 const int k, 01696 const T& key, 01697 std::multimap<acc_type,element*>& neighbors, 01698 const int emax) const; 01699 01700 private: 01701 /** 01702 * @name searchNearest Temporary variables 01703 * 01704 * The search of the nearest neighbors is optimized avoiding the 01705 * creation of many temporary variables. 01706 */ 01707 //@{ 01708 01709 /** 01710 * Minimum components of the bounding box. 01711 * It shares the memory with the first row of boundsBox. 01712 */ 01713 mutable vector<value_type> boundsMin; 01714 01715 /** 01716 * Maximum components of the bounding box 01717 * It shares the memory with the second row of boundsBox. 01718 */ 01719 mutable vector<value_type> boundsMax; 01720 01721 /** 01722 * Matrix containing the bounding box (first row min, second row max) 01723 */ 01724 mutable matrix<value_type> boundsBox; 01725 //@} 01726 01727 }; 01728 01729 } 01730 01731 #include "ltiKdTree_template.h" 01732 01733 #endif